Plone: Registry dict field with multiple fields values - plone

I have an interface:
class ISomething(Interface):
something = schema.Dict(
title=u"Something",
description=u"Define something.",
key_type=schema.TextLine(title=u"Some Title"),
value_type=schema.Text(title=u"Some Text"))
used to create a form that saves values in registry (ControlPanelFormWrapper, RegistryEditForm).
In registry.xml:
<record name="something">
<field type="plone.registry.field.Dict">
<title>Something</title>
<key_type type="plone.registry.field.TextLine" />
<value_type type="plone.registry.field.Text" />
</field>
</record>
It's working: I can add key-value items {'Some Title': 'Some Text'}.
I need to modify my form to have multiple fields instead of Some text, but keeping the Dict. Example:
{'Some Title': {
'field_1': 'Value 1',
'field_2': 'Value 2'
}
}
I expect this to work then:
registry = getUtility(IRegistry)
reg_something = registry.get("something")
print reg_something['Some Title']['field_1']
>>> Value 1
So, how to change my interface and registry record to have the form updated in this way?

This is described in an article from Mark van Lent:
https://www.vlent.nl/weblog/2011/09/07/dict-list-value-ploneappregistry/
Adjust the registry.xml accordingly, exchange the record-name with yours:
<record name="my.package.example">
<field type="plone.registry.field.Dict">
<title>Verification filesnames</title>
<key_type type="plone.registry.field.TextLine">
<title>Key</title>
</key_type>
<value_type type="plone.registry.field.List">
<title>Value list</title>
<value_type type="plone.registry.field.TextLine">
<title>Values</title>
</value_type>
</value_type>
</field>
<value purge="false" />
See also this question where Luca Fabbri and Gil Forcada each provide alternative approaches, which might be true time-savers on the long term:
Plone- How can I create a control panel for a record in registry that is a dictionary type?

registry.xml in my default profile (imported with an upgrade step):
<registry>
<records interface="my.package.something.ISomethingItems">
<record name="mypackage_multiplesomething">
<field type="plone.registry.field.List">
<title>Something Items</title>
<value_type type="collective.z3cform.datagridfield.DictRow">
<schema>my.package.something.ISomething</schema>
</value_type>
</field>
</record>
</records>
</registry>
In something.py just define the interfaces:
from collective.z3cform.datagridfield import BlockDataGridFieldFactory
from collective.z3cform.datagridfield.registry import DictRow
from plone import api
from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper
from plone.app.registry.browser.controlpanel import RegistryEditForm
from plone.autoform import directives
from zope import schema
from zope.interface import Interface
from zope.interface import implementer
from zope.schema.interfaces import IVocabularyFactory
from zope.schema.vocabulary import SimpleTerm
from zope.schema.vocabulary import SimpleVocabulary
class ISomething(Interface):
id = schema.ASCIILine(
title=u"Something ID",
description=u"Some description."
)
text = schema.Text(
title=u"A text field",
description=u"Human readable text"
)
url = schema.URI(
title=u"An URL",
description=u"Don't forget http:// or https://"
)
class ISomethingItems(Interface):
# the field is the same used in registry.xml
mypackage_multiplesomething = schema.List(
title=u"Something Items",
description=u"Define something items",
value_type=DictRow(title=u"Something", schema=ISomething)
)
directives.widget(mypackage_multiplesomething=BlockDataGridFieldFactory)
Now we can have an edit form (in something.py):
class SomethingItemsEditForm(RegistryEditForm):
schema = ISomethingItems
label = u"Something items definition"
class SomethingItemsView(ControlPanelFormWrapper):
""" Something items edit form """
form = SomethingItemsEditForm
defined as browser page (configure.zcml):
<browser:page
name="something-items-settings"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".something.SomethingItemsView"
permission="cmf.ManagePortal"
/>
Easy to get the values from registry using api:
>>> from plone import api
>>> reg_something_items = api.portal.get_registry_record(
'mypackage_somethingitems', interface=ISomethingItems)
[{'id': 'some id', 'text': 'some text', 'url': 'http://something.com'}, {'id': 'some id other', 'text': 'some text other', 'url': 'http://something-other.com'}]
>>> item = reg_something_items[0]
{'id': 'some id', 'text': 'some text', 'url': 'http://something.com'}
>>> item['id']
some id
>>> item['text']
some text
>>> item['url']
http://something.com
If you added an uninstall profile to your product it is a good idea to add registry.xml in it:
<registry>
<record name="my.package.something.ISomethingItems.mypackage_somethingitems"
delete="True" remove="True" />
</registry>
to be sure the registry will be clean after uninstall.
You can check anytime the values you have in registry in SITE/portal_registry (Site Setup -> Configuration Registry)

Related

My Archetypes-based content type can't be added

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:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five"
i18n_domain="MyCompany.MyProduct">
<class class=".mytype.MyType">
<require
permission="zope2.View"
interface="..interfaces.IMyType"
/>
</class>
</configure>
3.) Fix the then occurring syntax-error in MyCompany/MyProduct/content/mytype.py by replacing class MyType(*basecls) with class 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 ;-)

Change the id of an object in Plone when not published

In our use case, if the title of an unpublished object is modified we would like to change its id according with the new title.
We try to accomplish it using a simple subscriber without success:
ZCML:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:zcml="http://namespaces.zope.org/zcml">
<subscriber
for="DummyContentType
zope.lifecycleevent.IObjectModifiedEvent"
handler=".subscriber.update_id"
/>
</configure>
Python:
# -*- coding: utf-8 -*-
from plone import api
from plone.i18n.normalizer.interfaces import IIDNormalizer
from zope.component import queryUtility
def update_id(obj, event):
state = api.content.get_state(obj)
if state != 'private':
return
util = queryUtility(IIDNormalizer)
new_id = util.normalize(obj.Title())
api.content.rename(obj=obj, new_id=new_id, safe_id=True)
obj.reindexObject()
When this code run we get an ResourceLockedError exception

Django : NOT NULL constraint failed

I am trying to run a app which has a basic template which accepts the fields and saves it. My Model looks like this:
from django.db import models
# Create your models here.
class Book(models.Model):
"""docstring for MyApp"""
title = models.CharField(max_length=200)
abstract = models.TextField()
pub_date = models.DateTimeField('date published')
publisher = models.CharField(max_length=200)
def __unicode__(self):
return self.title
class Author(models.Model):
name = models.CharField(max_length=200)
sci='Sci'
arts= 'Arts'
engg= 'Engg'
mgmt='mgmt'
none=' '
Choice_In_Intrest = (
(sci,'Science'),
(arts,'Arts'),
(engg,'Engineering'),
(mgmt,'Mangaement'),
)
intrest = models.CharField(max_length=4 ,choices= Choice_In_Intrest , default=none)
book = models.ForeignKey(Book, null=True)
urls.py:
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
#url(r'^admin/', include(admin.site.urls)),
url(r'^create/$', 'myBook.views.insertBook'),
url(r'^all/$', 'myBook.views.books'),
url(r'^get/(?P<book_id>\d+)/$', 'myBook.views.book'),
url(r'^addAuthor/(?P<book_id>\d+)/$', 'myBook.views.addAuthor'),
]
forms.py:
from django import forms
from models import Book, Author
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields ='__all__'
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = '__all__'
**insert_book.html:**
{% block content%}
<h2>Add Book</h2>
<form action='/create/' method="POST">{%csrf_token%}
<ul>
{{form.as_ul}}
</ul>
<input type="submit" name="submit" value="Add Book">
</form>
{% endblock %}
When I runs the server the Html page displayed, but when I click the Add Book button, it shows the following error:
IntegrityError at /create/
NOT NULL constraint failed: myBook_book.author_id
Request Method: POST
Request URL: http://127.0.0.1:8080/create/
Django Version: 1.8.5
Exception Type: IntegrityError
Exception Value:
NOT NULL constraint failed: myBook_book.author_id
Exception Location: /home/rizwan/django-rizwan/local/lib/python2.7/site-packages/Django-1.8.5-py2.7.egg/django/db/backends/sqlite3/base.py in execute, line 318
Python Executable: /home/rizwan/django-rizwan/bin/python
Python Version: 2.7.6
Python Path:
['/home/rizwan/projects/bookInfo',
'/home/rizwan/django-rizwan/local/lib/python2.7/site-packages/Django-1.8.5-py2.7.egg',
'/home/rizwan/django-rizwan/lib/python2.7/site-packages/Django-1.8.5-py2.7.egg',
'/home/rizwan/django-rizwan/lib/python2.7',
'/home/rizwan/django-rizwan/lib/python2.7/plat-x86_64-linux-gnu',
'/home/rizwan/django-rizwan/lib/python2.7/lib-tk',
'/home/rizwan/django-rizwan/lib/python2.7/lib-old',
'/home/rizwan/django-rizwan/lib/python2.7/lib-dynload',
'/usr/lib/python2.7',
'/usr/lib/python2.7/plat-x86_64-linux-gnu',
'/usr/lib/python2.7/lib-tk',
'/home/rizwan/django-rizwan/local/lib/python2.7/site-packages',
'/home/rizwan/django-rizwan/lib/python2.7/site-packages']
Server time: Wed, 4 Nov 2015 11:12:00 +0000
I haven't define author_id any where, What caused it?
I am using Sqlite 3.
id fields are automatically generated by Models, and they are predictably of type serial NOT NULL PRIMARY KEY,. While using the Book model, they are required but have not been set yet. Database didn't get any author_id, so it attempted to set null on this field, but id field has the not null constraint. You can fix by either setting null=True on field definition in the model, or you can have a default, or add an author field to your form.

How to make dexterity modifications available to other clients?

The modified model_source of a dexterity type is not available for other clients until the other client restarts.
Invalidating or clearing the SCHEMA_CACHE is not a working solution: every client seems to have its own SCHEMA_CACHE which afik cannot be cleared or invalidated from another client.
Is there any solution to solve this problem?
The scenario presented here uses ipython as second client. The same can be reproduced through the web by starting two clients: (1) create a dexterity type in client1, and (2) edit the XML Field Model in client2.
I'd like to put this as an issue on https://github.com/plone/plone.dexterity but as for today issues seem not to be available in the plone.dexterity github project
utils.sync()
from Products.CMFCore.utils import getToolByName
from plone.dexterity.fti import DexterityFTI
id = 'mydexteritytype'
plone_site = app.Plone
tool_portal_types = getToolByName(plone_site, 'portal_types')
if tool_portal_types.hasObject(id): tool_portal_types.manage_delObjects(id)
utils.commit()
utils.sync()
fti = DexterityFTI(id)
fti.id = id
data = {}
data['title'] = id
data['i18n_domain'] = 'plone'
data['behaviors'] = "\n".join([
'plone.app.dexterity.behaviors.metadata.IDublinCore',
'plone.app.content.interfaces.INameFromTitle',
])
data['model_source'] = '''
<model xmlns:security="http://namespaces.plone.org/supermodel/security"
xmlns:marshal="http://namespaces.plone.org/supermodel/marshal"
xmlns:form="http://namespaces.plone.org/supermodel/form"
xmlns="http://namespaces.plone.org/supermodel/schema">
<schema>
<field name="original" type="zope.schema.TextLine">
<default>original</default>
<description/>
<title>original</title>
</field>
</schema>
</model>'''
data['klass'] = 'plone.dexterity.content.Container'
data['filter_content_types'] = True
data['icon_expr'] = 'string:${portal_url}/document_icon.png'
fti.manage_changeProperties(**data)
tool_portal_types._setObject(fti.id, fti)
utils.commit()
After running the code above, the new created mydexteritytype is available for all other clients.
The modifications produced by the following code will be only available in the client running the code. All other clients are not aware of the changes.
utils.sync()
from plone.dexterity.interfaces import IDexterityFTI
from zope.component import getUtility
fti = getUtility(IDexterityFTI, name=id)
model_source = '''
<model xmlns:security="http://namespaces.plone.org/supermodel/security"
xmlns:marshal="http://namespaces.plone.org/supermodel/marshal"
xmlns:form="http://namespaces.plone.org/supermodel/form"
xmlns="http://namespaces.plone.org/supermodel/schema">
<schema>
<field name="modified" type="zope.schema.TextLine">
<default>modified</default>
<description/>
<title>modified</title>
</field>
</schema>
</model>'''
fti.manage_changeProperties(model_source=model_source)
from plone.dexterity.schema import SCHEMA_CACHE
SCHEMA_CACHE.invalidate(fti)
SCHEMA_CACHE.clear()
utils.commit()
This pull-request is supposed to fix this issue:
https://github.com/plone/plone.dexterity/pull/137

Alfresco document-derived content is missing <content>

I've created a custom content type derived from document. I am trying to use CMIS to query my Alfresco server (tried with 4.2.b and 4.2.c) programmatically for my documents using python cmislib. I have a pyramid server that takes REST calls and sends them to my Alfresco server using CMIS.
I get this error:
2013-04-11 11:19:25,526 | ERROR | Exception when serving /access_manager/search_noauth
Traceback (most recent call last):
File "/home/hbrown/.virtualenvs/access_manager_master/local/lib/python2.7/site-packages/waitress-0.8.1-py2.7.egg/waitress/channel.py", line 329, in service
task.service()
[...]
File "/home/hbrown/workspace/spt/access_manager/access_manager/views/search.py", line 223, in cmis_main
for result in repo.query(whole_query)
File "/home/hbrown/.virtualenvs/access_manager_master/local/lib/python2.7/site-packages/cmislib/model.py", line 2467, in getContentStream
assert(len(contentElements) == 1), 'Expected to find exactly one atom:content element.'
AssertionError: Expected to find exactly one atom:content element.
I am using getContentStream() to retrieve content. Based on the code comment, I'd say it is the correct API call:
>>> doc.getName()
u'sample-b.pdf'
>>> o = open('tmp.pdf', 'wb')
>>> result = doc.getContentStream()
>>> o.write(result.read())
>>> result.close()
>>> o.close()
>>> import os.path
>>> os.path.getsize('tmp.pdf')
117248
The python code in cmislib clearly expects the document to have XML that includes an element named content, and mine does not.
The calling code looks like this:
from cmislib import CmisClient
SERVER = "localhost"
url = "http://{0}:8080/alfresco/cmisatom".format(SERVER)
client = CmisClient(url, 'admin', 'alfresco')
repo = client.defaultRepository
results = repo.query("select * from wg:bulletin")
print results[0].getContentStream().read()
The XML being operated on in getContentStream looks like this:
<atom:entry>
<atom:author>
<atom:name/>
</atom:author>
<atom:id>http://chemistry.apache.org/aWQtMQ==</atom:id>
<atom:published>2013-04-12T03:22:38Z</atom:published>
<atom:title>Query Result id-1</atom:title>
<app:edited>2013-04-12T03:22:38Z</app:edited>
<atom:updated>2013-04-12T03:22:38Z</atom:updated>
<cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
<cmis:properties>
<cmis:propertyInteger displayName="Content Stream Length" localName="contentStreamLength" propertyDefinitionId="cmis:contentStreamLength" queryName="b.cmis:contentStreamLength">
<cmis:value>249</cmis:value>
</cmis:propertyInteger>
<cmis:propertyId displayName="Object Type Id" localName="objectTypeId" propertyDefinitionId="cmis:objectTypeId" queryName="b.cmis:objectTypeId">
<cmis:value>D:wg:bulletin</cmis:value>
</cmis:propertyId>
<cmis:propertyString displayName="Version Series Checked Out By" localName="versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy" queryName="b.cmis:versionSeriesCheckedOutBy"/>
<cmis:propertyId displayName="Version Series Checked Out Id" localName="versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId" queryName="b.cmis:versionSeriesCheckedOutId"/>
<cmis:propertyId displayName="Version series id" localName="versionSeriesId" propertyDefinitionId="cmis:versionSeriesId" queryName="b.cmis:versionSeriesId">
<cmis:value>workspace://SpacesStore/1cd2053d-1fc4-4e85-b780-ba80284f0841</cmis:value>
</cmis:propertyId>
<cmis:propertyString displayName="wg:account" localName="account" propertyDefinitionId="wg:account" queryName="b.wg:account"/>
<cmis:propertyString displayName="Version Label" localName="versionLabel" propertyDefinitionId="cmis:versionLabel" queryName="b.cmis:versionLabel">
<cmis:value>1.0</cmis:value>
</cmis:propertyString>
<cmis:propertyBoolean displayName="Is Latest Version" localName="isLatestVersion" propertyDefinitionId="cmis:isLatestVersion" queryName="b.cmis:isLatestVersion">
<cmis:value>true</cmis:value>
</cmis:propertyBoolean>
<cmis:propertyBoolean displayName="Is Version Series Checked Out" localName="isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut" queryName="b.cmis:isVersionSeriesCheckedOut">
<cmis:value>false</cmis:value>
</cmis:propertyBoolean>
<cmis:propertyString displayName="Last Modified By" localName="lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy" queryName="b.cmis:lastModifiedBy">
<cmis:value>admin</cmis:value>
</cmis:propertyString>
<cmis:propertyString displayName="Created by" localName="createdBy" propertyDefinitionId="cmis:createdBy" queryName="b.cmis:createdBy">
<cmis:value>admin</cmis:value>
</cmis:propertyString>
<cmis:propertyDateTime displayName="wg:displayUntil" localName="displayUntil" propertyDefinitionId="wg:displayUntil" queryName="b.wg:displayUntil"/>
<cmis:propertyId displayName="Alfresco Node Ref" localName="nodeRef" propertyDefinitionId="alfcmis:nodeRef" queryName="b.alfcmis:nodeRef">
<cmis:value>workspace://SpacesStore/1cd2053d-1fc4-4e85-b780-ba80284f0841</cmis:value>
</cmis:propertyId>
<cmis:propertyString displayName="wg:email" localName="email" propertyDefinitionId="wg:email" queryName="b.wg:email"/>
<cmis:propertyBoolean displayName="wg:isActive" localName="isActive" propertyDefinitionId="wg:isActive" queryName="b.wg:isActive">
<cmis:value>false</cmis:value>
</cmis:propertyBoolean>
<cmis:propertyString displayName="wg:username" localName="username" propertyDefinitionId="wg:username" queryName="b.wg:username"/>
<cmis:propertyBoolean displayName="Is Latest Major Version" localName="isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion" queryName="b.cmis:isLatestMajorVersion">
<cmis:value>true</cmis:value>
</cmis:propertyBoolean>
<cmis:propertyId displayName="Content Stream Id" localName="contentStreamId" propertyDefinitionId="cmis:contentStreamId" queryName="b.cmis:contentStreamId">
<cmis:value>store://2013/4/10/15/29/20b185d0-afae-4a7f-a06e-58eab399bdc9.bin</cmis:value>
</cmis:propertyId>
<cmis:propertyString displayName="Name" localName="name" propertyDefinitionId="cmis:name" queryName="b.cmis:name">
<cmis:value>.pythonrc</cmis:value>
</cmis:propertyString>
<cmis:propertyString displayName="Content Stream MIME Type" localName="contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType" queryName="b.cmis:contentStreamMimeType">
<cmis:value>text/plain</cmis:value>
</cmis:propertyString>
<cmis:propertyDateTime displayName="Creation Date" localName="creationDate" propertyDefinitionId="cmis:creationDate" queryName="b.cmis:creationDate">
<cmis:value>2013-04-10T15:29:18.146-04:00</cmis:value>
</cmis:propertyDateTime>
<cmis:propertyString displayName="Change token" localName="changeToken" propertyDefinitionId="cmis:changeToken" queryName="b.cmis:changeToken"/>
<cmis:propertyString displayName="wg:state" localName="state" propertyDefinitionId="wg:state" queryName="b.wg:state"/>
<cmis:propertyDateTime displayName="wg:displayFrom" localName="displayFrom" propertyDefinitionId="wg:displayFrom" queryName="b.wg:displayFrom"/>
<cmis:propertyString displayName="Checkin Comment" localName="checkinComment" propertyDefinitionId="cmis:checkinComment" queryName="b.cmis:checkinComment"/>
<cmis:propertyString displayName="wg:application" localName="application" propertyDefinitionId="wg:application" queryName="b.wg:application"/>
<cmis:propertyId displayName="Object Id" localName="objectId" propertyDefinitionId="cmis:objectId" queryName="b.cmis:objectId">
<cmis:value>workspace://SpacesStore/1cd2053d-1fc4-4e85-b780-ba80284f0841;1.0</cmis:value>
</cmis:propertyId>
<cmis:propertyBoolean displayName="Is Immutable" localName="isImmutable" propertyDefinitionId="cmis:isImmutable" queryName="b.cmis:isImmutable">
<cmis:value>false</cmis:value>
</cmis:propertyBoolean>
<cmis:propertyBoolean displayName="Is Major Version" localName="isMajorVersion" propertyDefinitionId="cmis:isMajorVersion" queryName="b.cmis:isMajorVersion">
<cmis:value>true</cmis:value>
</cmis:propertyBoolean>
<cmis:propertyString displayName="wg:institution" localName="institution" propertyDefinitionId="wg:institution" queryName="b.wg:institution"/>
<cmis:propertyId displayName="Base Type Id" localName="baseTypeId" propertyDefinitionId="cmis:baseTypeId" queryName="b.cmis:baseTypeId">
<cmis:value>cmis:document</cmis:value>
</cmis:propertyId>
<cmis:propertyString displayName="Content Stream Filename" localName="contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName" queryName="b.cmis:contentStreamFileName">
<cmis:value>.pythonrc</cmis:value>
</cmis:propertyString>
<cmis:propertyDateTime displayName="Last Modified Date" localName="lastModificationDate" propertyDefinitionId="cmis:lastModificationDate" queryName="b.cmis:lastModificationDate">
<cmis:value>2013-04-10T15:29:23.384-04:00</cmis:value>
</cmis:propertyDateTime>
</cmis:properties>
</cmisra:object>
</atom:entry>
There is clearly no XML element named content here for the python code to extract.
Is this a misconfiguration of my custom content document or is it a change in CMIS that cmislib does not track or am I calling the wrong API function to get the content or something else?
Later: the minimum change to fix this is to make calls to either reload or getAllowableActions.
This was the original code:
def cmis_main(props, settings):
"""
Create a CMIS query based on props and execute against Alfresco
"""
def cmis_query(props, mapping):
"""
Create CMIS query of AND-separated OR-clauses
"""
# Code that formats a query string from dictionaries...
cmis_mapping = {
# Dictionary config for call to cmis_query
# Nothing to see here. Move on.
"app_sids": {
"where_fmt": IN_WHERE_FMT,
"key": "{0}:application".format(CMIS_NAMESPACE),
"fn": set_format,
},
}
cmis_url, cmis_user, cmis_password = cmis_args(settings)
cmisclient = CmisClient(cmis_url, cmis_user, cmis_password)
repo = cmisclient.getDefaultRepository()
whole_query = cmis_query(props, cmis_mapping)
logger.debug(whole_query)
return [
{
'name': result.name,
'content': result.getContentStream().read(),
'content_mime_type': result.properties["cmis:contentStreamMimeType"],
}
for result in repo.query(whole_query)
]
And it was broken. So I changed the code to this:
results = list(repo.query(whole_query))
for result in results:
print(result.getAllowableActions())
# or: result.reload()
return [
{
'name': result.name,
'content': result.getContentStream().read(),
'content_mime_type': result.properties["cmis:contentStreamMimeType"],
}
for result in results
]
And it worked. I changed it to this:
results = list(repo.query(whole_query))
for result in results:
pass
return [
{
'name': result.name,
'content': result.getContentStream().read(),
'content_mime_type': result.properties["cmis:contentStreamMimeType"],
}
for result in results
]
And it broke. So the XML does not appear to be fully loaded in the CMISLIB object.
Try doing results[0].reload() before calling getContentStream(). That shouldn't be required but it may force the object to reload with the content element.

Resources