view doc/xmlrpc.txt @ 5525:bb7865241f8a

Make CSV import/export compatible across Python versions (also RDBMS journals) (issue 2550976, issue 2550975). The roundup-admin export and import commands are used for migrating between different database backends. It is desirable that they should be usable also for migrations between Python 2 and Python 3, and in some cases (e.g. with the anydbm backend) this may be required. To be usable for such migrations, the format of the generated CSV files needs to be stable, meaning the same as currently used with Python 2. The export process uses repr() to produce the fields in the CSV files and eval() to convert them back to Python data structures. repr() of strings with non-ASCII characters produces different results for Python 2 and Python 3. This patch adds repr_export and eval_import functions to roundup/anypy/strings.py which provide the required operations that are just repr() and eval() in Python 2, but are more complicated in Python 3 to use data representations compatible with Python 2. These functions are then used in the required places for export and import. repr() and eval() are also used in storing the dict of changed values in the journal for the RDBMS backends. It is similarly desirable that the database be compatible between Python 2 and Python 3, so that export and import do not need to be used for a migration between Python versions for non-anydbm back ends. Thus, this patch changes rdbms_common.py in the places involved in storing journals in the database, not just in those involved in import/export. Given this patch, import/export with non-ASCII characters appear based on some limited testing to work across Python versions, and an instance using the sqlite backend appears to be compatible between Python versions without needing import/export, *if* the sessions/otks databases (which use anydbm) are deleted when changing Python version.
author Joseph Myers <jsm@polyomino.org.uk>
date Sun, 02 Sep 2018 23:48:04 +0000
parents d0689aaa83db
children 94a7669677ae
line wrap: on
line source

=========================
XML-RPC access to Roundup
=========================

.. contents::
   :local:

Introduction
------------
Version 1.4 of Roundup includes an XML-RPC frontend for remote access. The
XML-RPC interface allows a limited subset of commands similar to those found in
local `roundup-admin` tool.

By default XML-RPC is accessible from ``/xmlrpc`` endpoint:

    http://username:password@localhost:8000/xmlrpc

For demo tracker the URL would be:

    http://localhost:8917/demo/xmlrpc

Enabling XML-RPC server 
-----------------------
There are two ways to run the XML-RPC interface:

  stand alone roundup-xmlrpc-server

  through roundup itself

stand alone roundup-xmlrpc-server
---------------------------------
The Roundup XML-RPC standalone server must be started before remote clients can access the
tracker via XML-RPC. ``roundup-xmlrpc-server`` is installed in the scripts
directory alongside ``roundup-server`` and roundup-admin``. When invoked, the
location of the tracker instance must be specified.

	roundup-xmlrpc-server -i ``/path/to/tracker``

The default port is ``8000``. An alternative port can be specified with the
``--port`` switch.

through roundup
---------------
In addition to running a stand alone server described above, the
XML-RPC service is available from the roundup HTTP server.

security consideration
----------------------
Note that the current ``roundup-xmlrpc-server`` implementation does not
support SSL. This means that usernames and passwords will be passed in
cleartext unless the server is being proxied behind another server (such as
Apache or lighttpd) that provide SSL.


Client API
----------
The server currently implements four methods. Each method requires that the
user provide a username and password in the HTTP authorization header in order
to authenticate the request against the tracker.

======= ====================================================================
Command Description
======= ====================================================================
schema

        Fetch tracker schema.

list    arguments: *classname, [property_name]*

        List all elements of a given ``classname``. If ``property_name`` is
        specified, that is the property that will be displayed for each
        element. If ``property_name`` is not specified the default label
        property will be used.

display arguments: *designator, [property_1, ..., property_N]*

        Display a single item in the tracker as specified by ``designator``
        (e.g. issue20 or user5). The default is to display all properties
        for the item. Alternatively, a list of properties to display can be
        specified.

create  arguments: *classname, arg_1 ... arg_N*

        Create a new instance of ``classname`` with ``arg_1`` through
        ``arg_N`` as the values of the new instance. The arguments are
        name=value pairs (e.g. ``status='3'``).

set     arguments: *designator, arg_1 ... arg_N*

        Set the values of an existing item in the tracker as specified by
        ``designator``. The new values are specified in ``arg_1`` through
        ``arg_N``. The arguments are name=value pairs (e.g. ``status='3'``).

lookup  arguments: *classname, key_value*

        looks up the key_value for the given class. The class needs to
        have a key and the user needs search permission on the key
        attribute and id for the given classname.

filter  arguments: *classname, list or None, attributes*
        
        ``list`` is a list of ids to filter. It can be set to None to run
        filter over all values (requires ``allow_none=True`` when
        instantiating the ServerProxy). The ``attributes`` are given as a 
        dictionary of name value pairs to search for. See also :ref:`query-tracker`.
======= ====================================================================

sample python client
====================

This client will work if you turn off the x-requested-with header and
the only CSRF header check you require is the HTTP host header::

        >>> import xmlrpclib
        >>> roundup_server = xmlrpclib.ServerProxy('http://admin:admin@localhost:8917/demo/xmlrpc', allow_none=True)
        >>> roundup_server.schema()
        {'user': [['username', '<roundup.hyperdb.String>'], ...], 'issue': [...]}
        >>> roundup_server.list('user')
        ['admin', 'anonymous', 'demo']
        >>> roundup_server.list('issue', 'id')
        ['1']
        >>> roundup_server.display('issue1')
        {'assignedto' : None, 'files' : [], 'title' = 'yes, ..... }
        >>> roundup_server.display('issue1', 'priority', 'status')
        {'priority' : '1', 'status' : '2'}
        >>> roundup_server.set('issue1', 'status=3')
        >>> roundup_server.display('issue1', 'status')
        {'status' : '3' }
        >>> roundup_server.create('issue', "title='another bug'", "status=2")
        '2'
        >>> roundup_server.filter('user',None,{'username':'adm'})
        ['1']
        >>> roundup_server.filter('user',['1','2'],{'username':'adm'})
        ['1']
        >>> roundup_server.filter('user',['2'],{'username':'adm'})
        []
        >>> roundup_server.filter('user',[],{'username':'adm'})
        []
        >>> roundup_server.lookup('user','admin')
        '1'

advanced python client adding anti-csrf headers
===============================================

The one below adds Referer and X-Requested-With headers so it can pass
stronger CSRF detection methods. It also generates a fault message
from the server and reports it. Note if you are using http rather than
https, replace xmlrpclib.SafeTransport with xmlrpclib.Transport::

    import xmlrpclib

    class SpecialTransport(xmlrpclib.SafeTransport):

	def send_content(self, connection, request_body):

	    connection.putheader("Referer", "https://localhost/demo/")
	    connection.putheader("Origin", "https://localhost")
	    connection.putheader("X-Requested-With", "XMLHttpRequest")

	    connection.putheader("Content-Type", "text/xml")	
	    connection.putheader("Content-Length", str(len(request_body)))
	    connection.endheaders()
	    if request_body:
		connection.send(request_body)

    roundup_server = xmlrpclib.ServerProxy(
	'https://admin:admin@localhost/demo/xmlrpc',
	transport=SpecialTransport(),
	verbose=False,
	allow_none=True)

    print(roundup_server.schema())
    print(roundup_server.display('user2', 'username'))
    print(roundup_server.display('issue1', 'status'))
    print(roundup_server.filter('user',['1','2','3'],{'username':'demo'}))

   # this will fail with a fault
   try:
      print(roundup_server.filter('usr',['0','2','3'],{'username':'demo'}))
   except Exception as msg:
      print(msg)

Roundup Issue Tracker: http://roundup-tracker.org/