I'm developing an add-on package which introduces a few Archetypes-based content types; these are defined in the default profile of that package.
After (re-) installing my package in the Quick-Installer, I can see my types in the types tool; but I can't add them TTW, and they are not listed in the folder_constraintypes_form. I did select them in the "Allowed content types" multiselect list of the Folder portal type.
Since I got a ValueError
from FactoryTypeInformation._getFactoryMethod
in an bin/instance debug
session, I "developed" Products.CMFPlone
(branch 2.2
) and changed the TypesTool.py
like so:
from pprint import pprint # ADDED
...
class FactoryTypeInformation(TypeInformation):
...
def _getFactoryMethod(self, container, check_security=1):
if not self.product or not self.factory:
raise ValueError, ('Product factory for %s was undefined' %
self.getId())
pd = container.manage_addProduct # ADDED
p = container.manage_addProduct[self.product]
self_product = self.product # ADDED
self_factory = self.factory # ADDED
m = getattr(p, self.factory, None)
if m is None:
pprint(locals()) # ADDED
raise ValueError, ('Product factory for %s was invalid' %
self.getId())
if not check_security:
return m
if getSecurityManager().validate(p, p, self.factory, m):
return m
raise AccessControl_Unauthorized( 'Cannot create %s' % self.getId() )
The debug
session now looks like this:
>>> root = app.plone
>>> from Products.CMFCore.utils import getToolByName
>>> tmp_folder = root.temp
>>> type_name = 'MyType'
>>> types_tool = getToolByName(tmp_folder, 'portal_types')
>>> type_info = types_tool.getTypeInfo(type_name)
>>> type_info
<DynamicViewTypeInformation at /plone/portal_types/MyType>
>>> new_content_item = type_info._constructInstance(tmp_folder, 'shiny_new_object')
{'check_security': 0,
'container': <ATFolder at /plone/temp>,
'pd': <App.FactoryDispatcher.ProductDispatcher object at 0x227afd0>,
'p': <App.FactoryDispatcher.FactoryDispatcher object at 0x7b97450>,
'self': <DynamicViewTypeInformation at /plone/portal_types/MyType>,
'm': None,
'self_factory': 'addMyType',
'self_product': 'MyCompany.MyProduct'}
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/opt/zope/instances/zope-devel/src/Products.CMFCore/Products/CMFCore/TypesTool.py", line 551, in _constructInstance
m = self._getFactoryMethod(container, check_security=0)
File "/opt/zope/instances/zope-devel/src/Products.CMFCore/Products/CMFCore/TypesTool.py", line 467, in _getFactoryMethod
self.getId())
ValueError: Product factory for MyType was invalid
So, the FactoryDispatcher
lacks the necessary addMyType
attribute.
Probably my declarations are incomplete?
This is what I have:
config.py
:
# -*- coding: utf-8 -*-
from Products.CMFCore.permissions import setDefaultRoles
from os import sep
from .permissions import (AddMyType,
)
PROJECTNAME = "MyCompany.MyProduct"
PRODUCT_HOME = sep.join(__file__.split(sep)[:-1])
MANAGERS_ONLY = ('Manager',)
MANAGERS_AND_OWNER = ('Manager', 'Owner')
# Permissions
DEFAULT_ADD_CONTENT_PERMISSION = "Add portal content"
setDefaultRoles(DEFAULT_ADD_CONTENT_PERMISSION, MANAGERS_AND_OWNER)
ADD_CONTENT_PERMISSIONS = {
'MyType': AddMyType,
}
for perm in ADD_CONTENT_PERMISSIONS.values():
setDefaultRoles(perm, MANAGERS_ONLY)
content/mytype.py
:
# -*- coding: utf-8 -*-
__author__ = """unknown <unknown>"""
__docformat__ = 'plaintext'
from AccessControl import ClassSecurityInfo
from zope.interface import implements
from ..interfaces import IMyType
from ..config import PROJECTNAME
from Products.ATContentTypes.content.base import ATCTContent
from Products.ATContentTypes.content.schemata import ATContentTypeSchema
from Products.ATContentTypes.content.base import registerATCT as registerType
MyType_schema = (
ATContentTypeSchema.copy()
)
class MyType(ATCTContent):
"""
description of my type
"""
security = ClassSecurityInfo()
implements(IMyType)
meta_type = 'MyType'
_at_rename_after_creation = True
schema = MyType_schema
registerType(MyType, PROJECTNAME)
interfaces.py
:
# -*- coding: utf-8 -*-
"""Module where all interfaces, events and exceptions live."""
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from zope.interface import Interface
class ISupBetonqualiLayer(IDefaultBrowserLayer):
"""Marker interface that defines a browser layer."""
class IMyType(Interface):
"""Marker interface for .mytype.MyType
"""
permissions.py
:
# -*- coding: utf-8 -*- vim: ts=8 sts=4 sw=4 si et tw=79
"""
Permissions
"""
AddMyType = 'MyCompany.MyProduct: Add MyType'
profiles/default/factorytool.xml
:
<?xml version="1.0"?>
<object name="portal_factory" meta_type="Plone Factory Tool">
<factorytypes>
<type portal_type="MyType"/>
</factorytypes>
</object>
profiles/default/rolemap.xml
:
<?xml version="1.0"?>
<rolemap>
<roles>
<role name="MyAuthor"/>
</roles>
<permissions>
<permission name="MyCompany.MyProduct: Add MyType" acquire="True">
<role name="MyAuthor"/>
<role name="Manager"/>
</permission>
</permissions>
</rolemap>
profiles/default/types.xml
:
<?xml version="1.0"?>
<object name="portal_types"
meta_type="Plone Types Tool">
<object name="MyType"
meta_type="Factory-based Type Information with dynamic views"/>
</object>
profiles/default/types/MyType.xml
:
<?xml version="1.0"?>
<object name="MyType"
meta_type="Factory-based Type Information with dynamic views"
xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<property name="title">MyType</property>
<property name="description">
Some description text which is indeed visible in the types tool
</property>
<property name="content_icon">SomeExisting.png</property>
<property name="content_meta_type">MyType</property>
<property name="product">MyCompany.MyProduct</property>
<property name="factory">addMyType</property>
<property name="immediate_view">mytype_view</property>
<property name="global_allow">True</property>
<property name="filter_content_types">False</property>
<property name="allowed_content_types">
</property>
<property name="allow_discussion">False</property>
<property name="default_view">mytype_view</property>
<property name="view_methods">
<element value="base_view"/>
</property>
<property name="default_view_fallback">False</property>
<alias from="(Default)" to="(dynamic view)"/>
<alias from="index.html" to="(dynamic view)"/>
<alias from="view" to="(selected layout)"/>
<alias from="edit" to="base_edit"/>
<alias from="properties" to="base_metadata"/>
<action title="View"
action_id="view"
category="object"
condition_expr=""
url_expr="string:${object_url}/view"
visible="True">
<permission value="View"/>
</action>
<action title="Edit"
action_id="edit"
category="object"
condition_expr="not:object/@@plone_lock_info/is_locked_for_current_user"
url_expr="string:${object_url}/edit"
visible="True">
<permission value="Modify portal content"/>
</action>
</object>
- Should not Archetypes take care of creating that missing
addMyType
method? - What could make this fail?
- Is there something obviously missing in my configuration?
- The site contains Archtypes-based objects exclusively so far. Will I come into trouble if I add Dexterity-based types now? ''(I'm totally inexperienced with Dexterity)''
Before someone tells me to do so: I created a question in the Plone community forum already; no luck so far. If important information comes in on either page, I'll sync it.
These are the missing parts to make your contenttype addable:
1.) Register the content-directory in
MyCompany/MyProduct/configure.zcml
by adding:<include package=".content" />
2.) Add the file
MyCompany/MyProduct/content/configure.zcml
with this content:3.) Fix the then occurring syntax-error in
MyCompany/MyProduct/content/mytype.py
by replacingclass MyType(*basecls)
withclass MyType(ATCTContent)
.And last but not least remove the former attempts of making things work. Best would be to outsource the type to a dedicated pckg and create it with zopeskel, imo.
For the view-error occurring after adding a type, feel free to open a new quest ;-)