use formlib for creating a new loops site; automatically create subobjects
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1246 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
f6f863eeb6
commit
db5a60a6a3
10 changed files with 223 additions and 41 deletions
|
@ -28,11 +28,14 @@ from zope.app.form.browser.interfaces import ITerms
|
||||||
from zope.app.intid.interfaces import IIntIds
|
from zope.app.intid.interfaces import IIntIds
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.dottedname.resolve import resolve
|
from zope.dottedname.resolve import resolve
|
||||||
|
from zope.formlib.form import FormFields
|
||||||
from zope.formlib.form import EditForm as BaseEditForm
|
from zope.formlib.form import EditForm as BaseEditForm
|
||||||
|
from zope.formlib.form import AddForm as BaseAddForm
|
||||||
from zope.formlib.namedtemplate import NamedTemplate
|
from zope.formlib.namedtemplate import NamedTemplate
|
||||||
from zope.interface import implements
|
from zope.interface import Interface, implements
|
||||||
from zope.app.publisher.browser import applySkin
|
from zope.app.publisher.browser import applySkin
|
||||||
from zope.publisher.interfaces.browser import ISkin
|
from zope.publisher.interfaces.browser import ISkin
|
||||||
|
from zope import schema
|
||||||
from zope.schema.vocabulary import SimpleTerm
|
from zope.schema.vocabulary import SimpleTerm
|
||||||
from zope.security import canAccess, canWrite
|
from zope.security import canAccess, canWrite
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
@ -40,6 +43,29 @@ from zope.security.proxy import removeSecurityProxy
|
||||||
from cybertools.typology.interfaces import IType
|
from cybertools.typology.interfaces import IType
|
||||||
from loops.interfaces import IView
|
from loops.interfaces import IView
|
||||||
from loops import util
|
from loops import util
|
||||||
|
from loops.util import _
|
||||||
|
|
||||||
|
|
||||||
|
class NameField(schema.ASCIILine):
|
||||||
|
|
||||||
|
def _validate(self, value):
|
||||||
|
super(NameField, self)._validate(value)
|
||||||
|
|
||||||
|
|
||||||
|
class IAddForm(Interface):
|
||||||
|
|
||||||
|
name = NameField(
|
||||||
|
title=_(u'Object name'),
|
||||||
|
description=_(u'Name of the object - will be used for addressing the '
|
||||||
|
'object via a URL; should therefore be unique within '
|
||||||
|
'the container and not contain special characters')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AddForm(BaseAddForm):
|
||||||
|
|
||||||
|
form_fields = FormFields(IAddForm)
|
||||||
|
template = NamedTemplate('loops.pageform')
|
||||||
|
|
||||||
|
|
||||||
class EditForm(BaseEditForm):
|
class EditForm(BaseEditForm):
|
||||||
|
|
|
@ -85,13 +85,11 @@
|
||||||
|
|
||||||
<!-- loops top-level container -->
|
<!-- loops top-level container -->
|
||||||
|
|
||||||
<addform
|
<page
|
||||||
label="Add loops Container"
|
|
||||||
name="AddLoopsContainer.html"
|
name="AddLoopsContainer.html"
|
||||||
schema="loops.interfaces.ILoops"
|
for="zope.app.container.interfaces.IAdding"
|
||||||
content_factory="loops.Loops"
|
class="loops.browser.manager.LoopsAddForm"
|
||||||
template="add.pt"
|
permission="zope.ManageApplication"
|
||||||
permission="zope.ManageContent"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<addMenuItem
|
<addMenuItem
|
||||||
|
@ -108,14 +106,13 @@
|
||||||
add="zope.ManageContent"
|
add="zope.ManageContent"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<editform
|
<page
|
||||||
label="Edit Loops Container"
|
|
||||||
name="edit.html"
|
name="edit.html"
|
||||||
schema="loops.interfaces.ILoops"
|
|
||||||
fields="skinName"
|
|
||||||
for="loops.interfaces.ILoops"
|
for="loops.interfaces.ILoops"
|
||||||
permission="zope.ManageContent"
|
class="loops.browser.manager.LoopsEditForm"
|
||||||
menu="zmi_views" title="Edit" />
|
permission="zope.ManageApplication"
|
||||||
|
menu="zmi_views" title="Edit"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- concept manager -->
|
<!-- concept manager -->
|
||||||
|
|
||||||
|
|
60
browser/manager.py
Normal file
60
browser/manager.py
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Definition of view classes for the top-level loops container.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app import zapi
|
||||||
|
from zope.app.event.objectevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
|
from zope.event import notify
|
||||||
|
from zope.formlib.form import FormFields
|
||||||
|
from loops import Loops
|
||||||
|
from loops.interfaces import ILoops
|
||||||
|
from loops.browser.common import AddForm, EditForm, BaseView
|
||||||
|
from loops.setup import ISetupManager
|
||||||
|
from loops.util import _
|
||||||
|
|
||||||
|
|
||||||
|
class LoopsAddForm(AddForm):
|
||||||
|
|
||||||
|
form_fields = AddForm.form_fields + FormFields(ILoops)
|
||||||
|
label = _(u'Create Loops Site')
|
||||||
|
|
||||||
|
def createAndAdd(self, data):
|
||||||
|
container = self.context.context
|
||||||
|
name = data.pop('name', 'loopsdemo')
|
||||||
|
loops = Loops()
|
||||||
|
self.context.contentName = name
|
||||||
|
for attr in data:
|
||||||
|
setattr(loops, attr, data[attr])
|
||||||
|
notify(ObjectCreatedEvent(loops))
|
||||||
|
self.context.add(loops)
|
||||||
|
setup = ISetupManager(loops, None)
|
||||||
|
if setup is not None:
|
||||||
|
setup.setup()
|
||||||
|
return loops
|
||||||
|
|
||||||
|
|
||||||
|
class LoopsEditForm(EditForm):
|
||||||
|
|
||||||
|
form_fields = FormFields(ILoops)
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,16 @@ function toggleFormFieldHelp(ob,state) {
|
||||||
|
|
||||||
<div id="viewspace" metal:define-slot="viewspace">
|
<div id="viewspace" metal:define-slot="viewspace">
|
||||||
|
|
||||||
<h1 i18n:translate="heading_editform"
|
<h1 tal:condition="not:view/label"
|
||||||
|
i18n:translate="heading_editform"
|
||||||
metal:define-slot="heading">Edit
|
metal:define-slot="heading">Edit
|
||||||
<span i18n:name="title"
|
<span i18n:name="title"
|
||||||
tal:content="context/title">Concept</span>
|
tal:content="context/title|context/zope:name">Concept</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<h1 tal:condition="view/label"
|
||||||
|
tal:content="view/label">Headline</h1>
|
||||||
|
|
||||||
<metal:block define-macro="header">
|
<metal:block define-macro="header">
|
||||||
|
|
||||||
<div class="form-status"
|
<div class="form-status"
|
||||||
|
|
|
@ -284,6 +284,7 @@
|
||||||
</class>
|
</class>
|
||||||
|
|
||||||
|
|
||||||
|
<adapter factory="loops.setup.SetupManager" />
|
||||||
<adapter factory="loops.external.NodesLoader" />
|
<adapter factory="loops.external.NodesLoader" />
|
||||||
<adapter factory="loops.external.NodesExporter" />
|
<adapter factory="loops.external.NodesExporter" />
|
||||||
<adapter factory="loops.external.NodesImporter" />
|
<adapter factory="loops.external.NodesImporter" />
|
||||||
|
|
46
helpers.txt
46
helpers.txt
|
@ -19,26 +19,30 @@ Let's first do some basic imports
|
||||||
>>> from zope.interface import Interface
|
>>> from zope.interface import Interface
|
||||||
>>> from zope.publisher.browser import TestRequest
|
>>> from zope.publisher.browser import TestRequest
|
||||||
|
|
||||||
and setup a simple loops site with its manager objects,
|
and provide a relation registry:
|
||||||
|
|
||||||
|
>>> from cybertools.relation.interfaces import IRelationRegistry
|
||||||
|
>>> from cybertools.relation.registry import DummyRelationRegistry
|
||||||
|
>>> from zope.app.testing import ztapi
|
||||||
|
>>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry())
|
||||||
|
|
||||||
|
Now we can setup a simple loops site with its manager objects, using a
|
||||||
|
loops setup manager:
|
||||||
|
|
||||||
>>> from loops import Loops
|
>>> from loops import Loops
|
||||||
>>> site['loops'] = Loops()
|
>>> site['loops'] = Loops()
|
||||||
>>> loopsRoot = site['loops']
|
>>> loopsRoot = site['loops']
|
||||||
|
|
||||||
>>> from loops.concept import ConceptManager, Concept
|
>>> from loops.setup import SetupManager
|
||||||
>>> loopsRoot['concepts'] = ConceptManager()
|
>>> setup = SetupManager(loopsRoot)
|
||||||
|
>>> setup.setup()
|
||||||
>>> concepts = loopsRoot['concepts']
|
>>> concepts = loopsRoot['concepts']
|
||||||
|
|
||||||
>>> from loops.resource import ResourceManager, Document, MediaAsset
|
|
||||||
>>> loopsRoot['resources'] = ResourceManager()
|
|
||||||
>>> resources = loopsRoot['resources']
|
>>> resources = loopsRoot['resources']
|
||||||
|
|
||||||
>>> from loops.view import ViewManager, Node
|
|
||||||
>>> loopsRoot['views'] = ViewManager()
|
|
||||||
>>> views = loopsRoot['views']
|
>>> views = loopsRoot['views']
|
||||||
|
|
||||||
some concepts,
|
We also add some example concepts,
|
||||||
|
|
||||||
|
>>> from loops.concept import Concept
|
||||||
>>> cc1 = Concept(u'Zope')
|
>>> cc1 = Concept(u'Zope')
|
||||||
>>> concepts['cc1'] = cc1
|
>>> concepts['cc1'] = cc1
|
||||||
>>> cc1.title
|
>>> cc1.title
|
||||||
|
@ -51,6 +55,7 @@ some concepts,
|
||||||
|
|
||||||
resources,
|
resources,
|
||||||
|
|
||||||
|
>>> from loops.resource import Document, MediaAsset
|
||||||
>>> doc1 = Document(u'Zope Info')
|
>>> doc1 = Document(u'Zope Info')
|
||||||
>>> resources['doc1'] = doc1
|
>>> resources['doc1'] = doc1
|
||||||
>>> doc1.title
|
>>> doc1.title
|
||||||
|
@ -61,6 +66,7 @@ resources,
|
||||||
|
|
||||||
and nodes (in view space):
|
and nodes (in view space):
|
||||||
|
|
||||||
|
>>> from loops.view import Node
|
||||||
>>> m1 = Node(u'Home')
|
>>> m1 = Node(u'Home')
|
||||||
>>> views['m1'] = m1
|
>>> views['m1'] = m1
|
||||||
>>> m1.nodeType = 'menu'
|
>>> m1.nodeType = 'menu'
|
||||||
|
@ -69,12 +75,6 @@ and nodes (in view space):
|
||||||
>>> m1['p1'] = m1p1
|
>>> m1['p1'] = m1p1
|
||||||
>>> m1p1.nodeType = 'page'
|
>>> m1p1.nodeType = 'page'
|
||||||
|
|
||||||
Finally, we also need a relation registry:
|
|
||||||
|
|
||||||
>>> from cybertools.relation.interfaces import IRelationRegistry
|
|
||||||
>>> from cybertools.relation.registry import DummyRelationRegistry
|
|
||||||
>>> from zope.app.testing import ztapi
|
|
||||||
>>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry())
|
|
||||||
|
|
||||||
Type management with typology
|
Type management with typology
|
||||||
=============================
|
=============================
|
||||||
|
@ -98,11 +98,10 @@ As we have not yet associated a type with one of our content objects we get
|
||||||
>>> cc1_type.token
|
>>> cc1_type.token
|
||||||
'.unknown'
|
'.unknown'
|
||||||
|
|
||||||
So we create two special concepts: one ('hasType') as the predicate signifying
|
During setup we created two special concepts: one ('hasType') as the predicate
|
||||||
a type relation, and the other ('type') as the one and only type concept:
|
signifying a type relation, and the other ('type') as the one and only type
|
||||||
|
concept:
|
||||||
|
|
||||||
>>> concepts['hasType'] = Concept(u'has type')
|
|
||||||
>>> concepts['type'] = Concept(u'Type')
|
|
||||||
>>> typeObject = concepts['type']
|
>>> typeObject = concepts['type']
|
||||||
|
|
||||||
Assigning a type to a concept is a core functionality of concepts as
|
Assigning a type to a concept is a core functionality of concepts as
|
||||||
|
@ -189,8 +188,9 @@ get a type manager from all loops objects, always with the same context:
|
||||||
|
|
||||||
>>> types = typeManager.types
|
>>> types = typeManager.types
|
||||||
>>> sorted(t.token for t in types)
|
>>> sorted(t.token for t in types)
|
||||||
['.loops/concepts/topic', '.loops/concepts/type',
|
['.loops/concepts/predicate', '.loops/concepts/topic',
|
||||||
'loops.resource.Document', 'loops.resource.MediaAsset']
|
'.loops/concepts/type', 'loops.resource.Document',
|
||||||
|
'loops.resource.MediaAsset']
|
||||||
|
|
||||||
>>> typeManager.getType('.loops/concepts/topic') == cc1_type
|
>>> typeManager.getType('.loops/concepts/topic') == cc1_type
|
||||||
True
|
True
|
||||||
|
@ -200,7 +200,7 @@ condition:
|
||||||
|
|
||||||
>>> types = typeManager.listTypes(include=('concept',))
|
>>> types = typeManager.listTypes(include=('concept',))
|
||||||
>>> sorted(t.token for t in types)
|
>>> sorted(t.token for t in types)
|
||||||
['.loops/concepts/topic', '.loops/concepts/type']
|
['.loops/concepts/predicate', '.loops/concepts/topic', '.loops/concepts/type']
|
||||||
>>> types = typeManager.listTypes(exclude=('concept',))
|
>>> types = typeManager.listTypes(exclude=('concept',))
|
||||||
>>> sorted(t.token for t in types)
|
>>> sorted(t.token for t in types)
|
||||||
['loops.resource.Document', 'loops.resource.MediaAsset']
|
['loops.resource.Document', 'loops.resource.MediaAsset']
|
||||||
|
|
|
@ -32,8 +32,7 @@ from zope.app.folder.interfaces import IFolder
|
||||||
from cybertools.relation.interfaces import IRelation
|
from cybertools.relation.interfaces import IRelation
|
||||||
|
|
||||||
import util
|
import util
|
||||||
|
from util import _
|
||||||
_ = MessageFactory('loops')
|
|
||||||
|
|
||||||
|
|
||||||
# common interfaces
|
# common interfaces
|
||||||
|
|
86
setup.py
Normal file
86
setup.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Automatic setup of a loops site.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
import transaction
|
||||||
|
from zope.app.event.objectevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
|
from zope.event import notify
|
||||||
|
from zope.component import adapts
|
||||||
|
from zope.interface import implements, Interface
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
|
||||||
|
from loops.interfaces import ILoops
|
||||||
|
from loops.concept import ConceptManager, Concept
|
||||||
|
from loops.resource import ResourceManager
|
||||||
|
from loops.view import ViewManager, Node
|
||||||
|
|
||||||
|
|
||||||
|
class ISetupManager(Interface):
|
||||||
|
""" An object that controls the setup of a loops site.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
""" Set up a loops site: create all necessary objects and the
|
||||||
|
relations between them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class SetupManager(object):
|
||||||
|
|
||||||
|
adapts(ILoops)
|
||||||
|
implements(ISetupManager)
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
concepts, resources, views = self.setupManagers()
|
||||||
|
self.setupCoreConcepts(concepts)
|
||||||
|
|
||||||
|
def setupManagers(self):
|
||||||
|
loopsRoot = self.context
|
||||||
|
concepts = self.addObject(loopsRoot, ConceptManager, 'concepts')
|
||||||
|
resources = self.addObject(loopsRoot, ResourceManager, 'resources')
|
||||||
|
views = self.addObject(loopsRoot, ViewManager, 'views')
|
||||||
|
return concepts, resources, views
|
||||||
|
|
||||||
|
def setupCoreConcepts(self, conceptManager):
|
||||||
|
typeConcept = self.addObject(conceptManager, Concept, 'type', u'Type')
|
||||||
|
hasType = self.addObject(conceptManager, Concept, 'hasType', u'has type')
|
||||||
|
predicate = self.addObject(conceptManager, Concept, 'predicate', u'Predicate')
|
||||||
|
standard = self.addObject(conceptManager, Concept, 'standard', u'subobject')
|
||||||
|
typeConcept.conceptType = typeConcept
|
||||||
|
predicate.conceptType = typeConcept
|
||||||
|
hasType.conceptType = predicate
|
||||||
|
standard.conceptType = predicate
|
||||||
|
|
||||||
|
def addObject(self, container, class_, name, title=None):
|
||||||
|
if name in container:
|
||||||
|
return container[name]
|
||||||
|
if title:
|
||||||
|
obj = container[name] = class_(title)
|
||||||
|
else:
|
||||||
|
obj = container[name] = class_()
|
||||||
|
notify(ObjectCreatedEvent(obj))
|
||||||
|
notify(ObjectModifiedEvent(obj))
|
||||||
|
return obj
|
|
@ -17,6 +17,12 @@ from loops.concept import Concept, ConceptManager
|
||||||
from loops.resource import Document, MediaAsset, ResourceManager
|
from loops.resource import Document, MediaAsset, ResourceManager
|
||||||
from loops.view import Node, ViewManager
|
from loops.view import Node, ViewManager
|
||||||
|
|
||||||
|
# just for making sure there aren't any syntax and other errors during
|
||||||
|
# Zope startup:
|
||||||
|
|
||||||
|
from loops.browser.manager import LoopsAddForm, LoopsEditForm
|
||||||
|
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
"Basic tests for the loops package."
|
"Basic tests for the loops package."
|
||||||
|
|
||||||
|
|
3
util.py
3
util.py
|
@ -23,9 +23,12 @@ $Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope.interface import directlyProvides, directlyProvidedBy
|
from zope.interface import directlyProvides, directlyProvidedBy
|
||||||
|
from zope.i18nmessageid import MessageFactory
|
||||||
from zope.schema import vocabulary
|
from zope.schema import vocabulary
|
||||||
#from view import TargetRelation
|
#from view import TargetRelation
|
||||||
|
|
||||||
|
_ = MessageFactory('loops')
|
||||||
|
|
||||||
|
|
||||||
class KeywordVocabulary(vocabulary.SimpleVocabulary):
|
class KeywordVocabulary(vocabulary.SimpleVocabulary):
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue