I'm trying to develop a Python client that communicates with Drupal 6.2 over either jsonrpc or xmlrpc. I've read countless examples and code snippets but none work. This is my code so far. I'm getting 'Token has expired' - I've increased the token expiry time to 360 but still nothing works. Does anyone have a working example in Python that logs in and performs multiple calls; e.g. node.get, node.load?

import hashlib
import urllib
import urllib2
import cookielib
from django.utils import simplejson
import random
import string
import datetime
import sys
import hmac
import hashlib

#~ url = "http://localhost/drupal/services/json-rpc"
url = "http://localhost/drupal/?q=services/json-rpc"

cookiejar = cookielib.CookieJar()
urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar))
csrf_token = ''

def generate_password(length=8, chars=string.letters + string.digits):
	return ''.join([random.choice(chars) for i in range(length)])

api_key = "441cd598e14f8424399bf8ff071bc80a"
domain = "localhost.local"

def generate_hash(command, ts, domain, api_key, nonce):

	msg = "%s;%s;%s;%s" % (ts,domain,nonce,command)
	hm = hmac.new(api_key, msg, hashlib.sha256)
	print(hm.hexdigest())
	return hm.hexdigest()

def connect():
	print('Connecting')
	ts = datetime.datetime.now()
	command = 'system.connect'
	nonce = generate_password(10)
	hash = generate_hash(command, ts.strftime("%Y-%m-%d %H:%M:%S"), domain, api_key, nonce)

	data = {
	}

	headers = {'X-Requested-With': 'XMLHttpRequest'}
	params = urllib.urlencode({
		'method': command,
		'params': simplejson.dumps(data),
	})

	session_id = ""
	username = ""
	uid = -1
	roles =  None
  
	request = urllib2.Request(url, params, headers)
	try:
		result = urlOpener.open(request)
		content = result.read()
		d = simplejson.loads(content)
	except Exception, e:
		print(str(e))
		sys.exit(-1)

	# Decode the result.
	print(d)
	session_id = d['result']['sessid']
	uid = d['result']['user']['uid']
	roles = d['result']['user']['roles']

	session_data = {
		'session_id': session_id,
		'uid': uid,
		'roles': roles,
	}

	return session_data

def login(session_data):
	ts = datetime.datetime.now()
	print('Login %s' % ts.strftime("%Y-%m-%d %H:%M:%S"))
	command = 'user.login'
	nonce = generate_password(10)
	hash = generate_hash(command, ts, domain, api_key, nonce)

	data = {
		'hash': hash,
		'domain_name': domain,
		'domain_time_stamp': ts.strftime("%Y-%m-%d %H:%M:%S"),
		'nonce': nonce,
		'sessid': session_data['session_id'],
		'username': 'test',
		'password': 'test',
	}

	headers = {'X-Requested-With': 'XMLHttpRequest'}
	params = urllib.urlencode({
		'method': command,
		'params': simplejson.dumps(data),
	})

	request = urllib2.Request(url, params, headers)
	try:
		result = urlOpener.open(request)
		content = result.read()
		print(content)
	except Exception, e:
		print(str(e))
		sys.exit(-1)
   
def get_node(nid, session_data):
	command = "node.get"
	ts = datetime.datetime.now()
	print('Getting node %s' % ts.strftime("%Y-%m-%d %H:%M:%S"))
	nonce = generate_password(10)
	hash = generate_hash(command, ts.strftime("%Y-%m-%d %H:%M:%S"), domain, api_key, nonce)

	data = {
		'nid': 1,
		'hash': hash,
		'domain_name': domain,
		'domain_time_stamp': ts.strftime("%Y-%m-%d %H:%M:%S"),
		'nonce': nonce,
		'sessid': session_data['session_id'],
	}

	headers = {'X-Requested-With': 'XMLHttpRequest'}
	params = urllib.urlencode({
		'method': command,
		'params': simplejson.dumps(data),
		'fields': [
			'title',
			'body',
		],
	})
	request = urllib2.Request(url, params, headers)
	try:
		result = urlOpener.open(request)
		content = result.read()
		print(content)
	except Exception, e:
		print(str(e))
		sys.exit(-1)
	   
   
if __name__=="__main__":
	session_data = connect()
	print('Session Data %s'% str(session_data))
	login(session_data)
	#~ get_node(1, session_data)

Comments

stodge’s picture

Bah this has been driving me nuts for months. I finally worked out the solution. I was passing times as a string, while they should be the number of seconds since the epoch:


def make_time():
	dt = datetime.datetime.now()
	t = time.mktime(dt.timetuple())
	return t

Doh!