Metadata-Version: 1.0
Name: wsapi4plone.core
Version: 0.1a3
Summary: A Web Services API for Plone.
Home-page: https://weblion.psu.edu/trac/weblion/wiki/WebServicesApiPlone
Author: WebLion Group, Penn State University
Author-email: support@weblion.psu.edu
License: GPL
Description: 
        
        =============================================
        Web Services API for Plone (wsapi4plone.core)
        =============================================
        
        A Plone product that provides an XML-RPC API to Plone content and operations.  In other words, a Plone web services API.  One of the main goals is to provide a slim, versatile and extensive way to create, read, update and delete (CRUD) Plone content.  The secondary goal is to provide an interface on which Plone and other systems can communicate with one another.
        
        There are five known categories that the wsapi4plone is useful for:  Cross Site Communication, Desktop Applications, Skinning/Theming, Batch Processing and Site Migration.  The primary focus of wsapi4plone thus far is on Cross Site Communication (Plone to Plone communication), Desktop Applications (Desktop Authoring) and Site Migration (Plone Import/Export)
        
        .. contents:: Table of Contents
        :depth: 2
        
        -------------
        XML-RPC Calls
        -------------
        
        .. note:: The next version of the wsapi4plone.core package will have sphinx documentation.  The following call documentation will be derived from the view methods rather than rewriting that documentation here.  So, I ask you to please forgive any inaccuracies that may follow. Thank you.
        
        post_object
        ===========
        
        :Usage: ``post_object(params)``
        :Input: ``{ path: [{ attr: value, ...}, type_name], ...}``
        :Returns: ``[path, ...]``
        :Example: `Post a new content object`_
        
        put_object
        ==========
        
        :Usage: ``put_object(params)``
        :Input: ``{ path: [{ attr: value, ...}, type_name], ...}``
        :Returns: ``[path, ...]``
        :Example: `Put or update information on a content object`_
        
        get_object
        ==========
        
        :Usage: ``get_object(path=[])``
        :Input: ``None | [path, ...]``
        :Returns: ``{ path: [{ attr: value, ...}, type_name, {misc_info: value}], ...}``
        :Example: `Get a content object`_
        
        
        delete_object
        =============
        
        :Usage: ``delete_object(path=[])``
        :Input: ``None | [path, ...]``
        :Returns: ``None``
        :Example: `Delete a content object`_
        
        query
        =====
        
        :Usage: ``query(filtr={})``
        :Returns: ``{ path: {index_id: value, ...}, ...}``
        :Example: `Finding what you're looking for`_
        
        get_schema
        ==========
        
        :Usage: ``get_schema(type_name, path='')``
        :Returns: ``{ attr: {required: True | False, type: type_string, ...}, ...}``
        :Example: `Get a content object's structure`_
        
        get_types
        =========
        
        :Usage: ``get_types(path='')``
        :Returns: ``[type_name, ...]``
        :Example: `Get the available content-types`_
        
        get_workflow
        ============
        
        :Usage: ``get_workflow(path='')``
        :Returns: ``{ state: current_state, transitions: [transition_name, ...], ...}``
        :Example: `Get a content object's workflow state`_
        
        set_workflow
        ============
        
        :Usage: ``set_workflow(transition, path='')``
        :Returns: ``None``
        :Example: `Transition a content object's workflow state`_
        
        ------------------------------
        Installation (for zc.buildout)
        ------------------------------
        
        To install wsapi4plone simply add the following lines to your Plone instance declaration.  The next time you start Zope the calls will be available.  No further installation is required.
        ::
        
        ...
        eggs =
        ...
        wsapi4plone.core
        zcml =
        ...
        wsapi4plone.core
        
        
        ------------------------------------
        Usage Examples (via the interpreter)
        ------------------------------------
        
        Setup the client connection using ``xmlrpclib`` with basic authorization.
        ::
        
        >>> from xmlrpclib import ServerProxy
        >>> client = ServerProxy('http://user:password@localhost:8888/plone')
        
        .. _wsapi4plone.client: http://pypi.python.org/pypi/wsapi4plone.client
        
        .. note:: Please take a look at the `wsapi4plone.client`_ package if you are interested in cookie based authentication.
        
        Finding what you're looking for
        ===============================
        
        We can use the ``query`` call to search for content in the site.  This will also allow us to get a full index of all the content objects in the site if we do not provide any parameters.  Example:
        ::
        
        >>> q = client.query()
        >>> len(q)
        7
        >>> q
        {'/plone/front-page': {'CreationDate': '2007-04-02 15:28:30',
        'Creator': 'admin',
        'Date': '2009-08-19 09:56:50',
        'Description': 'Congratulations! You have successfully installed Plone.',
        'EffectiveDate': 'None',
        'ExpirationDate': 'None',
        'ModificationDate': '2009-08-19 09:56:50',
        'Subject': [],
        'Title': 'Welcome to Plone',
        'Type': 'Page',
        'UID': '07f20e423b6ca478eb8691ff816b83a3',
        'container': False,
        'created': <DateTime '2007-04-02T14:28:30-05:00' at 6a9440>,
        'effective': <DateTime '1000-01-01T00:00:00-04:00' at 71d558>,
        'expires': <DateTime '2499-12-31T00:00:00-04:00' at 6a95a8>,
        'id': 'front-page',
        'listCreators': ['admin'],
        'modified': <DateTime '2009-08-19T09:56:50-04:00' at 6a9620>,
        'review_state': 'published',
        'size': '4.9 kB'}, ... }
        
        We can also pass criteria to the query call in the form of a dictionary.  The ``query`` call is simply an abstraction of the Plone portal_catalog's search method.  Therefore, you can look at <<<google search: plone portal_catalog>>> for more information on the possible calls to the portal_catalog.  A basic example would look like:
        ::
        
        >>> q = client.query({'Title': "Users"})
        >>> q.keys()
        ['/plone/Members']
        
        Get a content object
        ====================
        
        To get information about the site (or the current calling location based on the url used above) use the ``get_object`` call without any parameters.
        ::
        
        >>> site_object = client.get_object()
        >>> site_object
        {'/plone': [{'description': '', 'id': 'plone', 'title': 'Site'},
        'Plone Site',
        {'contents': {'/plone/Members': {'CreationDate': '2009-08-19 09:56:50',
        'Creator': 'admin',
        'Date': '2009-08-19 09:56:51',
        'Description': "Container for users' home directories",
        'EffectiveDate': 'None',
        'ExpirationDate': 'None',
        'ModificationDate': '2009-08-19 09:56:51',
        'Subject': [],
        'Title': 'Users',
        'Type': 'Large Folder',
        'UID': '6e22e44bbe5581e10e3ff4913cebf83a',
        'container': True,
        'created': <DateTime '2009-08-19T09:56:50-04:00' at 71abc0>,
        'effective': <DateTime '1000-01-01T00:00:00-04:00' at 71a8f0>,
        'expires': <DateTime '2499-12-31T00:00:00-04:00' at 71ac10>,
        'id': 'Members',
        'listCreators': ['admin'],
        'modified': <DateTime '2009-08-19T09:56:51-04:00' at 71ac88>,
        'review_state': 'published',
        'size': '1 kB'}, ... }]}
        
        Analyzing the results
        ---------------------
        
        The ``get_object`` call will return data in a dictionary that is keyed by absolute path within the site.  The value of each key is a list of three items.  The items are loosely referred to as schema, type and miscellaneous, in that specific order.
        
        :Schema:  The schema isn't exactly a schema, but for lack of a better word has been called such.  The data is a dictionary of the content object's attribute name to value.  Further information about the schema can be determined by using the ``get_schema`` call and the content's type name.
        
        :Type: The type is a string that represents the content-type of the object.  The type name is derived from the name in the Plone portal_types tool.
        
        :Miscellaneous: The miscellaneous value is dependent on the content-type of the object and/or any extensions provided to the WSAPI by third party packages.  This value will always be available, but may return an empty dictionary when there are no extensions for the content-type.  An example of the default extension of container objects is the 'contents' key in the miscellaneous dictionary, which provides information about the contents of the container.  The value shares the same data structure as the query call.
        
        Get specific content objects by path
        ------------------------------------
        
        To be more specific about which objects you want returned, you can provide a list of paths to the ``get_object`` call.  The path can be relative to the xmlrpclib initialization location or absolute.  However, everything will always be returned with the absolute path, no matter if you use relative paths or not.
        
        An example would be something like:
        ::
        
        >>> objs = client.get_object(['Members', '/plone/front-page'])
        >>> len(objs)
        2
        >>> objs.keys()
        ['/plone/front-page', '/plone/Members']
        
        Put or update information on a content object
        =============================================
        
        To put or update information in an existing content object we pass the ``put_object`` call a dictionary of keyed paths that are valued with a list of schema and type.  The short of this is that you can do a ``get_object`` call and change/update the results, then simply pass those results through the ``put_object`` call.  Let's take a look at an example that changes the text body of the *front-page* object using the ``get_object`` call shortcut.
        ::
        
        >>> frontpage = client.get_object(['/plone/front-page'])
        >>> schema = frontpage['/plone/front-page'][0]
        >>> # Drop everything except the feel we want, even though sending back the whole thing wouldn't hurt anything.
        ...
        >>> schema = dict([ (x,schema[x]) for x in schema if x == 'text' ])
        >>> schema['text'] = "Once a new technology starts rolling, \
        ... if you're not part of the steamroller, you're part of the road. --Stewart Brand"
        >>> frontpage['/plone/front-page'][0] = schema
        >>> # get the results and send them back into the get_object call
        ...
        >>> updated_frontpage = client.get_object(client.put_object(frontpage))
        >>> updated_frontpage['/plone/front-page'][0]['text']
        "Once a new technology starts rolling, if you're not part of the steamroller, you're part of the road. --Stewart Brand"
        
        Post a new content object
        =========================
        
        To create or post a piece of content to a Plone site you would use the ``post_object`` call, which is almost the same as the ``put_object`` call.  The only difference between the two calls is that the type (aka content-type) is optional with ``put_object``, but not with ``post_object``.  Also, it should be noted that it is your responsibility to provide any required attributes, as the ``post_object`` call does not verify you have providing values for required attributes.
        
        Knowing what content-types are available
        ----------------------------------------
        
        Since you are required to use a content-type in the creation of an object, where do you find out what content-types are available.  The ``get_types`` call is for this very purpose.  Look at `Get the available content-types`_ for more information about the ``get_types`` call.  Quick example:
        ::
        
        >>> types = client.get_types()
        >>> types
        ['Document', 'Event', 'Favorite', 'File', 'Folder', 'Image', 'Link', 'News Item', 'Topic']
        
        Getting the required attributes of a content-type
        -------------------------------------------------
        
        Before you create new content it is helpful to know what attributes the content-type has.  To do that we can use the ``get_schema`` call, which will return the attributes of a particular type and meta-data about the attributes.  Look at `Get a content object's structure`_ for more information about the ``get_schema`` call.  Quick example:
        ::
        
        >>> link_schema = client.get_schema('Link')
        >>> [ x for x in link_schema if link_schema[x]['required'] ]
        ['remoteUrl', 'title']
        
        Creating the content
        --------------------
        
        To create object we need to give the ``post_object`` the same data structure you give to ``put_object`` and receive from ``get_object``.  What is the keyed value we give it?  The key of the dictionary will be the to-be-created object id.  Everything else is relatively straight forward, since it is so similar to the ``put_object`` call.  Let's take a look at an example where we create a *Link* to the PSU WebLion website in a Plone site.
        ::
        
        >>> weblion = {'/plone/weblion': [{'title': 'PSU WebLion', 'remoteUrl': 'http://weblion.psu.edu/'},'Link']}
        >>> # Note: I could have used the relative path 'weblion' as the key rather than the absolute path.
        ...
        >>> weblion = client.get_object(client.post_object(weblion))
        >>> weblion
        {'/plone/weblion': [{'allowDiscussion': False,
        'contributors': [],
        'creation_date': <DateTime '2009-08-19T15:05:48-04:00' at 6a9648>,
        'creators': ['admin'],
        'description': '',
        'effectiveDate': None,
        'excludeFromNav': False,
        'expirationDate': None,
        'id': 'weblion',
        'language': '',
        'location': '',
        'modification_date': <DateTime '2009-08-19T15:05:48-04:00' at 6a95f8>,
        'relatedItems': [],
        'remoteUrl': 'http://weblion.psu.edu/',
        'rights': '',
        'subject': [],
        'title': 'PSU WebLion'},
        'Link',
        None]}
        
        Delete a content object
        =======================
        
        The ``delete_object`` call does exactly what it says, deletes objects.  To use ``delete_object`` you pass it a list of paths.  Like the other calls the paths can be absolute or relative to the client call location.  Let's delete the *Members* folder and the *events* collection.
        ::
        
        >>> client.delete_object(['Members','/plone/events'])
        
        Get the available content-types
        ===============================
        
        Plone comes with a nice variety of content-types and this is one of the reasons it is such a powerful system.  We can use the ``get_types`` call to get the available types.  In addition, you can provide the call with a path to the container to discover the available types for that container.  Let's take a look at the types that can be added to the current call location (the plone site) and the *news* object, which is a *Large Plone Folder*.
        ::
        
        >>> client.get_types()
        ['Document', 'Event', 'Favorite', 'File', 'Folder', 'Image', 'Link', 'News Item', 'Topic']
        >>> client.get_types('/plone/news')
        ['News Item']
        
        Get a content object's structure
        ================================
        
        You usually want a blue print or schematic before trying to start an engineering project.  The same usually holds true for content objects, because not all content has the same shape or function.  The ``get_schema`` call helps to determine the schema of a content-type, which is basically a blue print for the object.  The call returns a dictionary of schema attributes for the given content-type.  The dictionary is keyed by the attribute's name and its value is a dictionary of meta-data.
        
        .. note:: The current implementation provides a dictionary of two key value pairs (required and type) as the attribute meta-data.  Future wsapi4plone.core versions may also provide default values and permission information.
        
        Let's take a look at the schema for an *Image* content-type.
        ::
        
        >>> image_schema = client.get_schema('Image')
        >>> image_schema
        {'allowDiscussion': {'required': False, 'type': 'boolean'},
        'contributors': {'required': False, 'type': 'lines'},
        'creation_date': {'required': False, 'type': 'datetime'},
        'creators': {'required': False, 'type': 'lines'},
        'description': {'required': False, 'type': 'text'},
        'effectiveDate': {'required': False, 'type': 'datetime'},
        'excludeFromNav': {'required': False, 'type': 'boolean'},
        'expirationDate': {'required': False, 'type': 'datetime'},
        'id': {'required': 0, 'type': 'string'},
        'image': {'required': True, 'type': 'image'},
        'language': {'required': False, 'type': 'string'},
        'location': {'required': False, 'type': 'string'},
        'modification_date': {'required': False, 'type': 'datetime'},
        'relatedItems': {'required': False, 'type': 'reference'},
        'rights': {'required': False, 'type': 'text'},
        'subject': {'required': False, 'type': 'lines'},
        'title': {'required': False, 'type': 'string'}}
        
        .. note:: The ``get_schema`` call takes a path parameter in addition to the content-type name, because sometimes there are type constraints on content and content containers.
        
        Get a content object's workflow state
        =====================================
        
        You can only go so far with creating and updating content before, for instance, you need to transition the content from a private state to a public state.  The ``get_workflow`` call returns a dictionary of two bit of information.  One the current workflow *state* of the content. Two the available *transition(s)* the authenticated user can perform.  Let's take a look at the *weblion* object we created in the `Post a new content object`_ section.
        ::
        
        >>> client.get_workflow('weblion')
        {'state': 'private', 'transitions': ['submit', 'publish']}
        
        Transition a content object's workflow state
        ============================================
        
        Using the ``get_workflow`` call has provided you with available transitions you can perform on the given content object.  We can now use the ``set_workflow`` call to transition the workflow state of the content.  Let's *publish* the *weblion* object that was create in the `Post a new content object`_ section.  In this example the second parameter, path, is optional and based on the current call location.
        ::
        
        >>> client.set_workflow('publish', 'weblion')
        >>> client.get_workflow('weblion')
        {'state': 'published', 'transitions': ['retract', 'reject']}
        
        
        ---------
        Changelog
        ---------
        
        0.1a3 (2009-08-24)
        ==================
        - Wrote some documentation. More will follow in the next release.
        - Removed the Plone egg dependency, because it causes complications with Plone < 3.2.
        - Rewrote the tests for the WSAPI calls.
        - Fixed the get_workflow call to return only the transitions the current authenticated users can perform.
        - Fixed a bug in the Plone service adapter's set_properties method, where the ISO 8601 format wasn't being parsed correctly.
        - Removed a few lines that assume CMF type factories and management of objects. This part can be handled by the serviced container object's api, which abstracts the process of creation and deletion.
        - The post_object call now derives the to-be-created object's id from the path.
        - Modified the get_schema method to fix the Not Found? error. I'm not sure why it wasn't finding the object, but something tells me it has to do with it the transaction not completing.
        
        0.1a2 (2009-07-29)
        ==================
        - Package name change from wsapi4plone to wsapi4plone.core.
        
        0.1a1 (2009-07-08)
        ==================
        - Initial release.
        
        
        
        -----------------------
        Maintenance Information
        -----------------------
        
        .. _home: https://weblion.psu.edu/trac/weblion/wiki/WebServicesApiPlone
        .. _`Web Service API wiki page`: home_
        .. _`PSU WebLion website`: https://weblion.psu.edu/
        .. _`WebLion Trac site`: https://weblion.psu.edu/trac/weblion/wiki
        .. _`a new ticket`: https://weblion.psu.edu/trac/weblion/newticket
        .. _`wsapi4plone report`: https://weblion.psu.edu/trac/weblion/query?status=new&status=assigned&status=reopened&component=wsapi4plone&order=priority&report=19
        
        Tasks, enhancements and status information
        ==========================================
        You can view the current tasks and enhancements in the `wsapi4plone report`_ or on the `Web Service API wiki page`_ on the `PSU WebLion website`_.
        
        Report a bug
        ============
        Submit a bug to the `WebLion Trac site`_ as `a new ticket`_.  Please try to determine if a similar ticket already exists before creating a new one.  You can view current tickets and proposed improvements on the `Web Service API wiki page`_.
        
Keywords: wsapi,api,xmlrpc,weblion
Platform: UNKNOWN
Classifier: Framework :: Plone
Classifier: Framework :: Zope2
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.4
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
Classifier: Development Status :: 3 - Alpha
