Using Zoho remote API to edit office documents in a Django app
Zoho.com is a set of web applications - for communication, collaboration, and documents management (documents, sheets, presentations/slides). There are two APIs available for those apps - Data API used on documents and data stored on Zoho apps, that you use, and Remote API that is used on documents stored on your server. The Data API allows more collaboration, and getting precise sets of data (look at CloudSQL). Remote API allows you to use Zoho editors (Writer, Sheet, Show and others) to edit documents (doc, odt, ppt, odp, xls, ods and many more) on your site. More on api.wiki.zoho.com.
pyCurl and Zoho Remote API
In this article we will use the Zoho Remo API to implement document edition in a Django powered website. To use a remote API call you have to POST a multi-part request to the API url containing the file content, and required data. In Python the best library for this task is pycurl. Here is an example how to "open" a document in the Zoho editor:import pycurl
apikey = 'ZOHO API KEY'
class Bodyfetcher:
def __init__(self):
self.contents = ''
def body_callback(self, buf):
self.contents = self.contents + buf
t = Bodyfetcher()
c = pycurl.Curl()
c.setopt(c.POST, 1)
# send the request to the API URL
c.setopt(c.URL, "http://export.writer.zoho.com/remotedoc.im?apikey=%s&output=editor" % apikey)
# set the required data
c.setopt(c.HTTPPOST, [("content", (c.FORM_FILE, "a.odt")), ("filename", 'a.odt'), ("id", '13'), ("format", 'odt'), ("saveurl", 'http://localhost/')])
c.setopt(c.WRITEFUNCTION, t.body_callback)
c.perform()
c.close()
# JS that will show the editor (if displayed in a browser)
print t.contents
Document editing in a Django App
class Document(models.Model):
title = models.CharField(max_length=255, verbose_name='Title')
description = models.TextField(verbose_name='Description')
file = models.FilePathField(verbose_name='File', blank=True, null=True, path=settings.MEDIA_ROOT + 'documents/')
doctype = models.CharField(max_length=10, verbose_name='Type', choices=[('doc', 'Document'), ('sheet', 'Sheet'), ('slide', 'Slides')])
class Meta:
verbose_name = 'Document'
verbose_name_plural = 'Documents'
def __unicode__(self):
return self.title
#!/usr/bin/python
import pycurl
from django.shortcuts import render_to_response
from django.conf import settings
from django.template import RequestContext
from django.http import HttpResponseRedirect,HttpResponse
from django.views.generic.list_detail import object_list
from documents.models import *
def show_index(request):
"""
List all documents
"""
return object_list(
request,
Document.objects.all(),
paginate_by = 50,
allow_empty = True,
template_name = 'show_index.html',
extra_context = {})
class Bodyfetcher:
def __init__(self):
self.contents = ''
def body_callback(self, buf):
self.contents = self.contents + buf
def view_doc(request, did):
"""
Display the document in read-only
"""
doc = Document.objects.get(id=did)
ext = str(doc.file.split('.')[-1])
fname = str(doc.file.split('/')[-1])
t = Bodyfetcher()
c = pycurl.Curl()
c.setopt(c.POST, 1)
c.setopt(c.URL, "http://export.writer.zoho.com/remotedoc.im?apikey=%s&output=view" % settings.APIKEY)
c.setopt(c.HTTPPOST, [("content", (c.FORM_FILE, str(doc.file))), ("filename", fname), ("id", str(doc.id)), ("format", ext)])
c.setopt(c.VERBOSE, 1)
c.setopt(c.WRITEFUNCTION, t.body_callback)
c.perform()
c.close()
zoho = t.contents
return render_to_response(
'view_doc.html',
{'doc': doc, 'zoho': zoho},
context_instance=RequestContext(request))
def edit_doc(request, did):
"""
Display the document in Zoho editor
"""
doc = Document.objects.get(id=did)
ext = str(doc.file.split('.')[-1])
fname = str(doc.file.split('/')[-1])
t = Bodyfetcher()
c = pycurl.Curl()
c.setopt(c.POST, 1)
c.setopt(c.URL, "http://export.writer.zoho.com/remotedoc.im?apikey=%s&output=editor" % settings.APIKEY)
c.setopt(c.HTTPPOST, [("content", (c.FORM_FILE, str(doc.file))), ("filename", fname), ("id", str(doc.id)), ("format", ext), ("saveurl", 'http://localhost:8080/doc/save_file/')])
c.setopt(c.WRITEFUNCTION, t.body_callback)
c.perform()
c.close()
zoho = t.contents
return render_to_response(
'edit_doc.html',
{'doc': doc, 'zoho': zoho},
context_instance=RequestContext(request))
def edit_doc_in_frame(request, did):
"""
Show the document in editor embeded in an iframe
"""
doc = Document.objects.get(id=did)
ext = str(doc.file.split('.')[-1])
fname = str(doc.file.split('/')[-1])
t = Bodyfetcher()
c = pycurl.Curl()
c.setopt(c.POST, 1)
c.setopt(c.URL, "http://export.writer.zoho.com/remotedoc.im?apikey=%s&output=id" % settings.APIKEY)
c.setopt(c.HTTPPOST, [("content", (c.FORM_FILE, str(doc.file))), ("filename", fname), ("id", str(doc.id)), ("format", ext), ("saveurl", 'http://localhost:8080/doc/save_file/')])
c.setopt(c.WRITEFUNCTION, t.body_callback)
c.perform()
c.close()
zoho = t.contents
return render_to_response(
'edit_doc_in_frame.html',
{'doc': doc, 'zoho': zoho},
context_instance=RequestContext(request))
def save_file(request):
"""
Save POSTed file
"""
if request.POST:
data = request.POST.copy()
doc = Document.objects.get(id=data['id'])
ext = str(doc.file.split('.')[-1])
fname = str(doc.file.split('/')[-1])
if fname == data['filename']:
#ok
# referer check would be recommended here etc.
print 'saving file'
content = request.FILES['content'].read()
f = open(str(doc.file), 'wb')
f.write(content)
f.close()
return HttpResponse('ok')
Sheet and slides
Remote API for Zoho Sheet and Zoho Show is more simple. You can use the editor, but the API won't return the JS code. Instead you will get the editor URL in response headers (Location header). To handle that we have to use pycurl slightly different:class Headerfetcher:
def __init__(self):
self.contents = ''
def body_callback(self, buf):
self.contents = self.contents + buf
def edit_sheet(request, did, inframe=False):
"""
Display the sheet in Zoho editor
"""
doc = Document.objects.get(id=did)
ext = str(doc.file.split('.')[-1])
fname = str(doc.file.split('/')[-1])
t = Headerfetcher()
c = pycurl.Curl()
c.setopt(c.POST, 1)
c.setopt(c.URL, "http://sheet.zoho.com/remotedoc.im?apikey=%s&output=editor" % settings.APIKEY)
c.setopt(c.HTTPPOST, [("content", (c.FORM_FILE, str(doc.file))), ("filename", fname), ("id", str(doc.id)), ("format", ext), ("saveurl", 'http://localhost:8080/doc/save_file/')])
c.setopt(c.HEADERFUNCTION, t.body_callback)
c.perform()
c.close()
x = t.contents.split('
')
for i in x:
if i.startswith('Location: '):
zoho = i.replace('Location: ', '').strip()
if inframe:
return render_to_response(
'edit_sheet_in_frame.html',
{'doc': doc, 'zoho': zoho},
context_instance=RequestContext(request))
else:
return HttpResponseRedirect(zoho)
return HttpResponse('ZohoError :(')
Zoho Data API and CloudSQL
The Data API won't let us use the editors on our websites, but it allows us to manipulate files and data stored in the zoho apps we use. The most interesting for app-making is the data stored in Zoho Reports (and Sheets). Using CloudSQL we can query data saved in sheets and process it in out apps (make reports, whatever). You can check Get Started with Zoho CloudSQL in 4 easy steps.
Here is an example CloudSQL usage with the Python library from Zoho, that maps most of the SQL to objects:from com.adventnet.zoho.client.report.python.ReportClient import ReportClient
APIKEY = 'YOUR KEY'
LOGINNAME = 'YOUR LOGIN'
PASSWORD = 'YOUR PASSWORD'
DATABASENAME = 'DB NAME'
TABLENAME = 'TABLE NAME'
rc = ReportClient(APIKEY)
rc.login(LOGINNAME,PASSWORD)
uri = rc.getURI(LOGINNAME,DATABASENAME,TABLENAME)
export = open('export.csv', 'w')
rc.exportData(uri, 'csv', export)
#rc.exportData(uri, 'csv', export, "Firma = 'Firma A' AND Zysk = 400")
print 'Done'
Comment article