loops.integrator: provide view for show and update external collections
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1690 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
a0b113195d
commit
9133b0fb52
10 changed files with 104 additions and 15 deletions
|
@ -44,6 +44,7 @@ from zope.security.proxy import removeSecurityProxy
|
|||
|
||||
from cybertools.typology.interfaces import IType, ITypeManager
|
||||
from loops.interfaces import IConcept
|
||||
from loops.interfaces import ITypeConcept
|
||||
from loops.concept import Concept, ConceptTypeSourceList, PredicateSourceList
|
||||
from loops.browser.common import EditForm, BaseView, LoopsTerms
|
||||
from loops import util
|
||||
|
@ -133,20 +134,25 @@ class ConceptView(BaseView):
|
|||
|
||||
@Lazy
|
||||
def view(self):
|
||||
context = self.context
|
||||
viewName = self.request.get('loops.viewName') or getattr(self, '_viewName', None)
|
||||
if not viewName:
|
||||
ti = IType(self.context).typeInterface
|
||||
ti = IType(context).typeInterface
|
||||
# TODO: check the interface (maybe for a base interface IViewProvider)
|
||||
# instead of the viewName attribute:
|
||||
if ti and 'viewName' in ti:
|
||||
if ti and ti != ITypeConcept and 'viewName' in ti:
|
||||
typeAdapter = ti(self.context)
|
||||
viewName = typeAdapter.viewName
|
||||
if not viewName:
|
||||
tp = IType(context).typeProvider
|
||||
if tp:
|
||||
viewName = ITypeConcept(tp).viewName
|
||||
if viewName:
|
||||
# ??? Would it make sense to use a somehow restricted interface
|
||||
# that should be provided by the view like IQuery?
|
||||
#viewInterface = getattr(typeAdapter, 'viewInterface', None) or IQuery
|
||||
adapter = component.queryMultiAdapter((self.context, self.request),
|
||||
interface.Interface, name=viewName)
|
||||
adapter = component.queryMultiAdapter((context, self.request),
|
||||
name=viewName)
|
||||
if adapter is not None:
|
||||
return adapter
|
||||
#elif type provides view: use this
|
||||
|
|
|
@ -98,9 +98,11 @@ Working with the External Collection
|
|||
>>> res = coll01.getResources()
|
||||
>>> len(res)
|
||||
2
|
||||
>>> sorted((r.__name__, r.title) for r in res)
|
||||
[(u'programming_beautifulprogram.pdf', u'BeautifulProgram'),
|
||||
(u'programming_zope_zope3.txt', u'zope3')]
|
||||
>>> sorted((r.__name__, r.title, r._storageName) for r in res)
|
||||
[(u'programming_beautifulprogram.pdf', u'BeautifulProgram', 'fullpath'),
|
||||
(u'programming_zope_zope3.txt', u'zope3', 'fullpath')]
|
||||
|
||||
To do: Check storage parameters.
|
||||
|
||||
|
||||
Fin de partie
|
||||
|
|
48
integrator/browser.py
Normal file
48
integrator/browser.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
#
|
||||
# Copyright (c) 2007 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
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
View class(es) for intergrating external objects.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope import interface, component
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
from cybertools.typology.interfaces import IType
|
||||
from loops.browser.concept import ConceptView
|
||||
|
||||
|
||||
class ExternalCollectionView(ConceptView):
|
||||
|
||||
macro_template = ViewPageTemplateFile('collection_macros.pt')
|
||||
|
||||
@property
|
||||
def macro(self):
|
||||
return self.macro_template.macros['render_collection']
|
||||
|
||||
def update(self):
|
||||
if 'update' in self.request.form:
|
||||
ti = IType(self.context).typeInterface
|
||||
if ti is not None:
|
||||
adapted = ti(self.context)
|
||||
adapted.update()
|
||||
return True
|
||||
|
|
@ -70,6 +70,7 @@ class ExternalCollectionAdapter(AdapterBase):
|
|||
for addr, mdate in provider.collect(self):
|
||||
if addr in old:
|
||||
if mdate > self.lastUpdated:
|
||||
# force reindexing
|
||||
notify(ObjectModifiedEvent(old[addr]))
|
||||
else:
|
||||
new.append(addr)
|
||||
|
@ -113,7 +114,7 @@ class DirectoryCollectionProvider(object):
|
|||
title=title,
|
||||
resourceType=extFileType,
|
||||
externalAddress=addr,
|
||||
storage='fullpath',
|
||||
storageName='fullpath',
|
||||
storageParams=dict(subdirectory=directory))
|
||||
yield obj
|
||||
|
||||
|
|
11
integrator/collection_macros.pt
Normal file
11
integrator/collection_macros.pt
Normal file
|
@ -0,0 +1,11 @@
|
|||
<metal:resources define-macro="render_collection"
|
||||
tal:define="dummy item/update">
|
||||
|
||||
<metal:concept use-macro="item/template/macros/conceptdata" />
|
||||
|
||||
<form action="." method="post">
|
||||
<input type="submit" name="update" value="Update Collection" />
|
||||
</form>
|
||||
|
||||
</metal:resources>
|
||||
|
|
@ -19,4 +19,15 @@
|
|||
<zope:utility
|
||||
factory="loops.integrator.collection.DirectoryCollectionProvider" />
|
||||
|
||||
<!-- view(s) -->
|
||||
|
||||
<zope:adapter
|
||||
name="collection.html"
|
||||
for="loops.interfaces.IConcept
|
||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
provides="zope.interface.Interface"
|
||||
factory="loops.integrator.browser.ExternalCollectionView"
|
||||
permission="zope.View"
|
||||
/>
|
||||
|
||||
</configure>
|
||||
|
|
|
@ -8,9 +8,9 @@ import os
|
|||
from zope import component
|
||||
|
||||
from loops import util
|
||||
from loops.interfaces import IExternalFile
|
||||
from loops.interfaces import IFile, IExternalFile
|
||||
from loops.concept import Concept
|
||||
from loops.resource import Resource
|
||||
from loops.resource import Resource, FileAdapter, ExternalFileAdapter
|
||||
from loops.integrator.interfaces import IExternalCollection
|
||||
from loops.knowledge.setup import SetupManager as KnowledgeSetupManager
|
||||
from loops.setup import SetupManager, addAndConfigureObject
|
||||
|
@ -28,6 +28,9 @@ class TestSite(BaseTestSite):
|
|||
component.provideAdapter(KnowledgeSetupManager, name='knowledge')
|
||||
concepts, resources, views = self.baseSetup()
|
||||
|
||||
component.provideAdapter(FileAdapter, provides=IFile)
|
||||
component.provideAdapter(ExternalFileAdapter, provides=IExternalFile)
|
||||
|
||||
tType = concepts.getTypeConcept()
|
||||
tExtFile = addAndConfigureObject(concepts, Concept, 'extfile',
|
||||
title=u'External File', conceptType=tType,
|
||||
|
|
|
@ -305,6 +305,9 @@ class ExternalFileAdapter(FileAdapter):
|
|||
|
||||
implements(IExternalFile)
|
||||
|
||||
_adapterAttributes = (FileAdapter._adapterAttributes
|
||||
+ ('storageParams', 'externalAddress'))
|
||||
|
||||
def getStorageParams(self):
|
||||
params = getattr(self.context, '_storageParams', None)
|
||||
if params is not None:
|
||||
|
|
7
setup.py
7
setup.py
|
@ -114,9 +114,12 @@ def addAndConfigureObject(container, class_, name, **kw):
|
|||
basicKw = dict([(k, kw[k]) for k in kw if k in basicAttributes])
|
||||
obj = addObject(container, class_, name, **basicKw)
|
||||
ti = IType(obj).typeInterface
|
||||
adapted = ti is not None and ti(obj) or obj
|
||||
if ti is not None:
|
||||
adapted = ti(obj)
|
||||
else:
|
||||
adapted = obj
|
||||
adapterAttributes = [k for k in kw if k not in basicAttributes]
|
||||
for attr in adapterAttributes:
|
||||
setattr(obj, attr, kw[attr])
|
||||
setattr(adapted, attr, kw[attr])
|
||||
notify(ObjectModifiedEvent(obj))
|
||||
return obj
|
||||
|
|
|
@ -19,13 +19,13 @@ from cybertools.typology.interfaces import IType
|
|||
from loops import Loops
|
||||
from loops import util
|
||||
from loops.common import NameChooser
|
||||
from loops.interfaces import IIndexAttributes
|
||||
from loops.interfaces import IIndexAttributes, IDocument
|
||||
from loops.concept import Concept
|
||||
from loops.concept import IndexAttributes as ConceptIndexAttributes
|
||||
from loops.resource import Resource
|
||||
from loops.resource import IndexAttributes as ResourceIndexAttributes
|
||||
from loops.setup import SetupManager, addObject
|
||||
from loops.type import ConceptType, ResourceType, TypeConcept
|
||||
from loops.type import LoopsType, ConceptType, ResourceType, TypeConcept
|
||||
|
||||
|
||||
class TestSite(object):
|
||||
|
@ -42,8 +42,9 @@ class TestSite(object):
|
|||
component.provideUtility(relations, IRelationRegistry)
|
||||
component.provideAdapter(IndexableRelationAdapter)
|
||||
|
||||
component.provideAdapter(LoopsType)
|
||||
component.provideAdapter(ConceptType)
|
||||
component.provideAdapter(ResourceType)
|
||||
component.provideAdapter(ResourceType, (IDocument,))
|
||||
component.provideAdapter(TypeConcept)
|
||||
component.provideAdapter(NameChooser)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue