252 lines
7.7 KiB
Python
252 lines
7.7 KiB
Python
"""Module to talk to EtherpadLite API."""
|
|
import requests
|
|
import logging
|
|
|
|
from flectra.tools import html2plaintext
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class EtherpadLiteClient:
|
|
"""Client to talk to EtherpadLite API."""
|
|
API_VERSION = 1 # TODO probably 1.1 sometime soon
|
|
|
|
CODE_OK = 0
|
|
CODE_INVALID_PARAMETERS = 1
|
|
CODE_INTERNAL_ERROR = 2
|
|
CODE_INVALID_FUNCTION = 3
|
|
CODE_INVALID_API_KEY = 4
|
|
TIMEOUT = 20
|
|
|
|
apiKey = ""
|
|
baseUrl = "http://localhost:9001/api"
|
|
|
|
def __init__(self, apiKey=None, baseUrl=None):
|
|
if apiKey:
|
|
self.apiKey = apiKey
|
|
|
|
if baseUrl:
|
|
self.baseUrl = baseUrl
|
|
|
|
def call(self, function, arguments=None):
|
|
"""Create a dictionary of all parameters"""
|
|
url = '%s/%d/%s' % (self.baseUrl, self.API_VERSION, function)
|
|
|
|
params = arguments or {}
|
|
params['apikey'] = self.apiKey
|
|
|
|
r = requests.post(url, data=params, timeout=self.TIMEOUT)
|
|
r.raise_for_status()
|
|
return self.handleResult(r.json())
|
|
|
|
def handleResult(self, result):
|
|
"""Handle API call result"""
|
|
if 'code' not in result:
|
|
raise Exception("API response has no code")
|
|
if 'message' not in result:
|
|
raise Exception("API response has no message")
|
|
|
|
if 'data' not in result:
|
|
result['data'] = None
|
|
|
|
if result['code'] == self.CODE_OK:
|
|
return result['data']
|
|
elif result['code'] == self.CODE_INVALID_PARAMETERS or result['code'] == self.CODE_INVALID_API_KEY:
|
|
raise ValueError(result['message'])
|
|
elif result['code'] == self.CODE_INTERNAL_ERROR:
|
|
raise Exception(result['message'])
|
|
elif result['code'] == self.CODE_INVALID_FUNCTION:
|
|
raise Exception(result['message'])
|
|
else:
|
|
raise Exception("An unexpected error occurred whilst handling the response")
|
|
|
|
# GROUPS
|
|
# Pads can belong to a group. There will always be public pads that do not belong to a group (or we give this group the id 0)
|
|
|
|
def createGroup(self):
|
|
"""creates a new group"""
|
|
return self.call("createGroup")
|
|
|
|
def createGroupIfNotExistsFor(self, groupMapper):
|
|
"""this functions helps you to map your application group ids to etherpad lite group ids"""
|
|
return self.call("createGroupIfNotExistsFor", {
|
|
"groupMapper": groupMapper
|
|
})
|
|
|
|
def deleteGroup(self, groupID):
|
|
"""deletes a group"""
|
|
return self.call("deleteGroup", {
|
|
"groupID": groupID
|
|
})
|
|
|
|
def listPads(self, groupID):
|
|
"""returns all pads of this group"""
|
|
return self.call("listPads", {
|
|
"groupID": groupID
|
|
})
|
|
|
|
def createGroupPad(self, groupID, padName, text=''):
|
|
"""creates a new pad in this group"""
|
|
params = {
|
|
"groupID": groupID,
|
|
"padName": padName,
|
|
}
|
|
if text:
|
|
params['text'] = text
|
|
return self.call("createGroupPad", params)
|
|
|
|
# AUTHORS
|
|
# Theses authors are bind to the attributes the users choose (color and name).
|
|
|
|
def createAuthor(self, name=''):
|
|
"""creates a new author"""
|
|
params = {}
|
|
if name:
|
|
params['name'] = name
|
|
return self.call("createAuthor", params)
|
|
|
|
def createAuthorIfNotExistsFor(self, authorMapper, name=''):
|
|
"""this functions helps you to map your application author ids to etherpad lite author ids"""
|
|
params = {
|
|
'authorMapper': authorMapper
|
|
}
|
|
if name:
|
|
params['name'] = name
|
|
return self.call("createAuthorIfNotExistsFor", params)
|
|
|
|
# SESSIONS
|
|
# Sessions can be created between a group and a author. This allows
|
|
# an author to access more than one group. The sessionID will be set as
|
|
# a cookie to the client and is valid until a certain date.
|
|
|
|
def createSession(self, groupID, authorID, validUntil):
|
|
"""creates a new session"""
|
|
return self.call("createSession", {
|
|
"groupID": groupID,
|
|
"authorID": authorID,
|
|
"validUntil": validUntil
|
|
})
|
|
|
|
def deleteSession(self, sessionID):
|
|
"""deletes a session"""
|
|
return self.call("deleteSession", {
|
|
"sessionID": sessionID
|
|
})
|
|
|
|
def getSessionInfo(self, sessionID):
|
|
"""returns informations about a session"""
|
|
return self.call("getSessionInfo", {
|
|
"sessionID": sessionID
|
|
})
|
|
|
|
def listSessionsOfGroup(self, groupID):
|
|
"""returns all sessions of a group"""
|
|
return self.call("listSessionsOfGroup", {
|
|
"groupID": groupID
|
|
})
|
|
|
|
def listSessionsOfAuthor(self, authorID):
|
|
"""returns all sessions of an author"""
|
|
return self.call("listSessionsOfAuthor", {
|
|
"authorID": authorID
|
|
})
|
|
|
|
# PAD CONTENT
|
|
# Pad content can be updated and retrieved through the API
|
|
|
|
def getText(self, padID, rev=None):
|
|
"""returns the text of a pad"""
|
|
params = {"padID": padID}
|
|
if rev is not None:
|
|
params['rev'] = rev
|
|
return self.call("getText", params)
|
|
|
|
# introduced with pull request merge
|
|
def getHtml(self, padID, rev=None):
|
|
"""returns the html of a pad"""
|
|
params = {"padID": padID}
|
|
if rev is not None:
|
|
params['rev'] = rev
|
|
return self.call("getHTML", params)
|
|
|
|
def setText(self, padID, text):
|
|
"""sets the text of a pad"""
|
|
return self.call("setText", {
|
|
"padID": padID,
|
|
"text": text
|
|
})
|
|
|
|
def setHtmlFallbackText(self, padID, html):
|
|
try:
|
|
# Prevents malformed HTML errors
|
|
html_wellformed = '<html><body>' + html + '</body></html>'
|
|
return self.setHtml(padID, html_wellformed)
|
|
except Exception:
|
|
_logger.exception('Falling back to setText. SetHtml failed with message:')
|
|
return self.setText(padID, html2plaintext(html).encode('UTF-8'))
|
|
|
|
def setHtml(self, padID, html):
|
|
"""sets the text of a pad from html"""
|
|
return self.call("setHTML", {
|
|
"padID": padID,
|
|
"html": html
|
|
})
|
|
|
|
# PAD
|
|
# Group pads are normal pads, but with the name schema
|
|
# GROUPID$PADNAME. A security manager controls access of them and its
|
|
# forbidden for normal pads to include a in the name.
|
|
|
|
def createPad(self, padID, text=''):
|
|
"""creates a new pad"""
|
|
params = {
|
|
"padID": padID,
|
|
}
|
|
if text:
|
|
params['text'] = text
|
|
return self.call("createPad", params)
|
|
|
|
def getRevisionsCount(self, padID):
|
|
"""returns the number of revisions of this pad"""
|
|
return self.call("getRevisionsCount", {
|
|
"padID": padID
|
|
})
|
|
|
|
def deletePad(self, padID):
|
|
"""deletes a pad"""
|
|
return self.call("deletePad", {
|
|
"padID": padID
|
|
})
|
|
|
|
def getReadOnlyID(self, padID):
|
|
"""returns the read only link of a pad"""
|
|
return self.call("getReadOnlyID", {
|
|
"padID": padID
|
|
})
|
|
|
|
def setPublicStatus(self, padID, publicStatus):
|
|
"""sets a boolean for the public status of a pad"""
|
|
return self.call("setPublicStatus", {
|
|
"padID": padID,
|
|
"publicStatus": publicStatus
|
|
})
|
|
|
|
def getPublicStatus(self, padID):
|
|
"""return true of false"""
|
|
return self.call("getPublicStatus", {
|
|
"padID": padID
|
|
})
|
|
|
|
def setPassword(self, padID, password):
|
|
"""returns ok or a error message"""
|
|
return self.call("setPassword", {
|
|
"padID": padID,
|
|
"password": password
|
|
})
|
|
|
|
def isPasswordProtected(self, padID):
|
|
"""returns true or false"""
|
|
return self.call("isPasswordProtected", {
|
|
"padID": padID
|
|
})
|