Personal tools
Skip to content. | Skip to navigation
Abstract An extensible Plone JSON API Framework Introduction This Package allows Users to expose content information via JSON. Motivation This project was born in 2012, out of the need for a data source to build a network based iOS application. Or more precise, I wanted to learn iOS programming and wanted to knit my own JSON API:) I know, it is a little bit awkward to provide an own routing mechanism for Plone which dispatches the request after the ZPublisher did its job, but it worked and thus, I did it. Limitations Since the API comes after the ZPublisher, it can only make use of HTTP GET and HTTP POST methods. The other methods will never reach the API View. Be aware that the API View comes with the permission zope2.View, so you need to programmatically check for the correct permissions on your custom routes.
Introduction This is an add-on package for plone.jsonapi.core which provides some basic URLs for Plone standard contents (and more). Motivation The routes package is built on top of the plone.jsonapi.core package to allow Plone developers to build modern (JavaScript) web UIs which communicate through a RESTful API with their Plone site. Compatibility The plone.jsonapi.routes should work with Plone 3 and 4. API URL After installation, the Plone API routes are available below the plone.jsonapi.core root URL (@@API) with the base /plone/api/1.0, for example http://localhost:8080/Plone/@@API/plone/api/1.0/api.json. There is also an overview of the registered routes which can be accessed here: http://localhost:8080/Plone/@@API/plone/api/1.0/api.json API Routes BASE_URL: /plone/api/1.0 This is an overview of the provided API Routes. The basic content routes provide all an interface for CRUD operations. CRUD URL Scheme: OPERATION URL METHOD PAYLOAD VIEW <BASE_URL>/<RESOURCE>/<uid:optional> GET -- CREATE <BASE_URL>/<RESOURCE>/create/<uid:optional> POST JSON UPDATE <BASE_URL>/<RESOURCE>/update/<uid:optional> POST JSON DELETE <BASE_URL>/<RESOURCE>/delete/<uid:optional> POST JSON
*plone.keyring* contains a Zope3 utility that facilitates handling of secrets in an application. Secrets are very important in modern applications, which is why a shared tool to manage them is useful. plone.keyring contains two basic components: * a *keyring*: a data structures which contains one or more secrets. * a *key manager*: a utility which contains the available keyrings and provides some convenience methods to manage them Keyrings ======== The keyring is the workhorse: it contains a set of secrets for a specific purpose. A ring has room for a fixed number of secrets which is set at creation time. The most recently added secret is considered to be the 'current' secret and the one that should be used. Older secrets in the ring can be used to keep data generated with older secrets valid for a period of time. Key manager =========== The key manager is a container for the available keyrings. It always contains a default system keyring which is used when no other ring is explicitly requested.
by Raphael Ritz, Jeff Roche, Martin Aspeli and others Provides basic automatic locking support for Plone. Locks are stealable by default, meaning that a user with edit privileges will be able to steal another user's lock, but will be warned that someone else may be editing the same object. Used by Plone, Archetypes and plone.app.iterate Basic locking ------------- By default, this is enabled on any ITTWLockable object. By default, this applies to any Archetypes content object. Stealable locks --------------- By default, locks can be stolen. That is, if a particular user has a lock and another user (with edit rights over the object) wants to edit the object, the second user can unlock the object. This is opposed to "safe" unlocking, which is done by the original owner. Categorised locks ----------------- So far, we have been managing a single type of lock. However, it is possible to manage different types of locks which are mutually exclusive. For example, if a particular type of lock is applied, it cannot be stolen by a user who is attempting to create another type of lock. Anonymous locking ================= When we are anonymous but do have edit rights we can also do a lock. Locking timeouts ================ Lock timeout should be ten minutes by default Turning locking on or off ========================= The status of the entire TTW locking mechanism can be controlled by setting up an ILockSettings adapter with a lock_on_ttw_edit property.
plone.memoize provides Python function decorators for caching the values of functions and methods. The type of cache storage is freely configurable by the user, as is the cache key, which is what the function's value depends on. plone.memoize has support for memcached and is easily extended to use other caching storages. It also has specialized decorators for use with Zope views. However, plone.memoize can be used without Zope.
This package contains a unittest test class based on the one from the Mocker mock library (http://labix.org/mocker). This class provides support for registering Zope 3 components (utilities, adapters, subscription adapters and event handlers) from mocks and tearing down the global component registry during test tear-down. There are also a few convenience methods and parameter checkers that are useful to Zope and Plone testing.
NOT in development. This package is beeing merged on plone.app.multilingual .. image:: https://travis-ci.org/plone/plone.multilingual.png :target: http://travis-ci.org/plone/plone.multilingual plone.multilingual ================== This package contains the core functionality for the next generation multilingual engine. These are the main artifacts and its purposes: canonical: * the canonical organizes the information about a "translation-group" * it's using a dictionary with language-codes as keys and uuids (provided by plone.uuid) as values storage: * persistent storage, which holds the canonicals in an IOBTree * the OOBTree's key is the UUID of the content, the according value is the canonical manager: * adapter for ITranslatable * provides the translations API adapters: * ITranslationLocator - where to put a translation * ITranslationIdChooser - generates a valid id for a translation * ITranslationCloner - copy the language-independent content to the translation * ITranslationFactory - creates the translation In order to have a test we have a type called Demo that has an adapter called DemoLanguage that will allow to get the language of the object:: >>> from plone.multilingual.interfaces import ITranslationManager >>> from plone.multilingual.interfaces import ILanguage >>> from plone.app.testing import setRoles, login, TEST_USER_ID, TEST_USER_NAME >>> from zope.lifecycleevent import modified >>> portal = layer['portal'] >>> setRoles(portal, TEST_USER_ID, ['Manager']) >>> login(portal, TEST_USER_NAME) >>> portal.invokeFactory('Folder', 'ob1', title=u"An archetypes based folder") 'ob1' >>> ILanguage(portal['ob1']).set_language('ca') >>> portal['ob1'].reindexObject() >>> modified(portal['ob1']) Ensuring that the new object gets its UUID:: >>> from plone.uuid.interfaces import IUUID >>> ob1_uuid = IUUID(portal['ob1']) >>> isinstance(ob1_uuid, str) True We create a new translation in 'en' language:: >>> ITranslationManager(portal['ob1']).add_translation('en') We try to create a new translation in 'ca' that already exists:: >>> ITranslationManager(portal['ob1']).add_translation('ca') Traceback (most recent call last): ... KeyError: 'Translation already exists' We try to create a new translation without language:: >>> ITranslationManager(portal['ob1']).add_translation(None) Traceback (most recent call last): ... KeyError: 'There is no target language' We get the 'en' translation:: >>> ITranslationManager(portal['ob1']).get_translation('en') <ATFolder at /plone/ob1-en> >>> ILanguage(ITranslationManager(portal['ob1']).get_translation('en')).get_language() == 'en' True let's get all the translations:: >>> ITranslationManager(portal['ob1']).get_translations() {'ca': <ATFolder at /plone/ob1>, 'en': <ATFolder at /plone/ob1-en>} let's get only the languages:: >>> ITranslationManager(portal['ob1']).get_translated_languages() ['ca', 'en'] has_translation:: >>> ITranslationManager(portal['ob1']).has_translation('en') True >>> ITranslationManager(portal['ob1']).has_translation('it') False register_translation with invalid language:: >>> ITranslationManager(portal['ob1']).remove_translation('en') >>> ITranslationManager(portal['ob1']).register_translation(None, portal['ob1-en']) Traceback (most recent call last): ... KeyError: 'There is no target language' register a translation with content:: >>> ITranslationManager(portal['ob1']).register_translation('en', portal['ob1-en']) >>> ITranslationManager(portal['ob1']).get_translations() {'ca': <ATFolder at /plone/ob1>, 'en': <ATFolder at /plone/ob1-en>} changing the content-language (there should act a subscriber):: >>> ILanguage(portal['ob1-en']).set_language('it') >>> from zope.event import notify >>> from zope.lifecycleevent import ObjectModifiedEvent >>> notify(ObjectModifiedEvent(portal['ob1-en'])) >>> ITranslationManager(portal['ob1']).get_translations() {'ca': <ATFolder at /plone/ob1>, 'it': <ATFolder at /plone/ob1-en>} test more translations:: >>> obj_it = ITranslationManager(portal['ob1']).get_translation('it') >>> ITranslationManager(obj_it).add_translation('fr') >>> ITranslationManager(obj_it).add_translation('pt') >>> ITranslationManager(portal['ob1']).get_translated_languages() ['ca', 'it', 'fr', 'pt'] >>> ITranslationManager(obj_it).get_translated_languages() ['ca', 'it', 'fr', 'pt'] test if canonicals objects are the same:: >>> obj_ca = ITranslationManager(obj_it).get_translation('ca') >>> canonical_it = ITranslationManager(obj_it).query_canonical() >>> canonical_ca = ITranslationManager(obj_ca).query_canonical() >>> canonical_it == canonical_ca True Messing up with content ----------------------- In case that we do mess up things with content (users always do):: >>> from zope.lifecycleevent import modified >>> portal.invokeFactory('Folder', 'ob2', title=u"An archetypes based doc") 'ob2' >>> ILanguage(portal['ob2']).set_language('it') >>> modified(portal['ob2']) >>> ILanguage(portal['ob2']).get_language() 'it' >>> ITranslationManager(portal['ob2']).add_translation('en') >>> ob2_en = ITranslationManager(portal['ob2']).get_translation('en') >>> portal.invokeFactory('Folder', 'ob3', title=u"An archetypes based doc") 'ob3' >>> ILanguage(portal['ob3']).set_language('it') >>> modified(portal['ob3']) >>> ILanguage(portal['ob3']).get_language() 'it' >>> ITranslationManager(portal['ob3']).add_translation('es') >>> ob3_es = ITranslationManager(portal['ob3']).get_translation('es') >>> from OFS.event import ObjectWillBeRemovedEvent >>> notify(ObjectWillBeRemovedEvent(portal['ob2'])) >>> portal.manage_delObjects('ob2') >>> notify(ObjectWillBeRemovedEvent(ob3_es)) >>> portal.manage_delObjects(ob3_es.id) >>> c_old = ITranslationManager(portal['ob3']).query_canonical() >>> c_new = ITranslationManager(ob2_en).query_canonical() >>> c_old == c_new False >>> isinstance(c_old, str) True >>> isinstance(c_new, str) True >>> ITranslationManager(ob2_en).register_translation('it', portal['ob3']) >>> c1 = ITranslationManager(portal['ob3']).query_canonical() >>> c2 = ITranslationManager(ob2_en).query_canonical() >>> c1 == c2 True Other use case, A('it' + 'en') and B('it' + 'es'), and we want A('en') -> B('es'):: >>> portal.invokeFactory('Folder', 'mess1', title=u"An archetypes based doc") 'mess1' >>> ILanguage(portal['mess1']).set_language('it') >>> modified(portal['mess1']) >>> ILanguage(portal['mess1']).get_language() 'it' >>> ITranslationManager(portal['mess1']).add_translation('en') >>> mess1_en = ITranslationManager(portal['mess1']).get_translation('en') >>> portal.invokeFactory('Folder', 'mess2', title=u"An archetypes based doc") 'mess2' >>> ILanguage(portal['mess2']).set_language('it') >>> ITranslationManager(portal['mess2']).add_translation('es') >>> mess2_es = ITranslationManager(portal['mess2']).get_translation('es') >>> ITranslationManager(mess1_en).register_translation('es', mess2_es) >>> ITranslationManager(portal['mess2']).get_translation('es') >>> ITranslationManager(portal['mess1']).get_translation('es') <ATFolder at /plone/mess2-es> Default-Adapters ---------------- id-chooser:: >>> from plone.multilingual.interfaces import ITranslationIdChooser >>> chooser = ITranslationIdChooser(portal['ob1-en']) >>> chooser(portal, 'es') 'ob1-es' locator:: >>> ITranslationManager(portal['ob1']).add_translation('es') >>> child_id = portal.ob1.invokeFactory('Folder', 'ob1_child', language="ca") >>> from plone.multilingual.interfaces import ITranslationLocator >>> locator = ITranslationLocator(portal['ob1-en']) >>> locator('es') == portal True >>> child_locator = ITranslationLocator(portal.ob1.ob1_child) >>> child_locator('es') == portal['ob1-es'] True >>> ITranslationManager(portal['ob1']).remove_translation('es') Convert intids to uuids upgrade step ------------------------------------ An upgrade step is available in case of having an existing site with the experimental 0.1 plone.multilingual version:: >>> from plone.multilingual.upgrades.to02 import upgrade .. note:: You must reinstall the plone.multilingual package in order to install the required new utility in place before upgrading. If you are using a version of Dexterity below 2.0, you must install the package plone.app.referenceablebehavior and enable the *Referenceable* (plone.app.referenceablebehavior.referenceable.IReferenceable) behavior for all your Dexterity content types before you attempt to upgrade your site. You can run the @@pml-upgrade view at the root of your site or follow the upgrade step in portal_setup > upgrades. If you can't see the upgrade step, press *Show old upgrades* and select the *Convert translation based intids to uuids (0.1 → 02)* Upgrade to catalog ------------------ :: >>> from plone.multilingual.upgrades.to03 import upgrade we shouldn't find the storage-utility anymore:: >>> from plone.multilingual.interfaces import IMultilingualStorage >>> gsm = portal.getSiteManager() >>> gsm.queryUtility(IMultilingualStorage) is None True
plone.multilingualbehavior adds multilingual behavior to content types built with Dexterity. It uses the next generation multilingual engine powered by five/Zope3 technologies, plone.multilingual. The behavior provides the Dexterity-driven content with a marker interface "ITranslatable", and makes available to that translation enabled type all the translation UI components such as menus, views, etc... To make your Dexterity content type translatable, add the following line to the <!-- enabled behaviors --> section in your type's profile: <!-- enabled behaviors --> <property name="behaviors"> <element value="plone.multilingualbehavior.interfaces.IDexterityTranslatable" /> </property> plone.multilingualbehavior implements language independent fields. The content of language independent fields is the same across all language versions. This is convenient, but also a little dangerous, because editing the field on any language version will change the content on all other language versions. For details on how to make fields language independent, see the examples in the test folder. tests/schemata.py shows how to make fields language independent when using the Grok framework; tests/samplecontent_type.xml shows how to achieve the same thing in an xml file. It is also possible to set a field to be language independent through the web, given a sufficiently new version of plone.schemaeditor.
This package contains fields and wrapper objects for storing: * A file with a filename * An image with a filename BLOB based types are supported if the z3c.blobfile package is installed. This will also require the ZODB3 package to be at version 3.8.1 or later, and BLOBs to be configured in zope.conf.