diff --git a/addons/pad/pad.py b/addons/pad/pad.py index 6d2cd0ee042..e263ff6a5af 100644 --- a/addons/pad/pad.py +++ b/addons/pad/pad.py @@ -5,32 +5,54 @@ import re import string import urllib2 from tools.translate import _ +from openerp.tools.misc import html2plaintext +from py_etherpad import EtherpadLiteClient class pad_common(osv.osv_memory): _name = 'pad.common' def pad_generate_url(self, cr, uid, context=None): - pad_server = self.pool.get('res.users').browse(cr, uid, uid, context).company_id.pad_server + company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id; + + pad = { + "server" : company.pad_server, + "key" : company.pad_key or "4DxmsNIbnQUVQMW9S9tx2oLOSjFdrx1l", + } + # make sure pad server in the form of http://hostname - if not pad_server: + if not pad["server"]: return '' - if not pad_server.startswith('http'): - pad_server = 'http://' + pad_server - pad_server = pad_server.rstrip('/') + if not pad["server"].startswith('http'): + pad["server"] = 'http://' + pad["server"] + pad["server"] = pad["server"].rstrip('/') # generate a salt s = string.ascii_uppercase + string.digits salt = ''.join([s[random.randint(0, len(s) - 1)] for i in range(10)]) + #path + path = '%s-%s-%s' % (cr.dbname.replace('_','-'), self._name, salt) # contruct the url - url = '%s/p/%s-%s-%s' % (pad_server, cr.dbname.replace('_','-'), self._name, salt) + url = '%s/p/%s' % (pad["server"], path) + + #if create with content + if "field_name" in context and "model" in context and "object_id" in context: + myPad = EtherpadLiteClient( pad["key"], pad["server"]+'/api') + myPad.createPad(path) + + #get attr on the field model + model = self.pool.get(context["model"]) + field = model._all_columns[context['field_name']] + real_field = field.column.pad_content_field + + #get content of the real field + for record in model.browse(cr, uid, [context["object_id"]]): + if record[real_field]: + myPad.setText(path, html2plaintext(record[real_field])) + - key = "4DxmsNIbnQUVQMW9S9tx2oLOSjFdrx1l" - return { + "server": pad["server"], + "path": path, "url": url, - "pad_server": pad_server, - "dbname": cr.dbname.replace('_','-'), - "name": self._name, - "salt": salt, } def pad_get_content(self, cr, uid, url, context=None): diff --git a/addons/pad/py_etherpad/__init__.py b/addons/pad/py_etherpad/__init__.py new file mode 100644 index 00000000000..6af310b48aa --- /dev/null +++ b/addons/pad/py_etherpad/__init__.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python +"""Module to talk to EtherpadLite API.""" + +import json +import urllib +import urllib2 + + +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.update({'apikey': self.apiKey}) + data = urllib.urlencode(params, True) + + try: + opener = urllib2.build_opener() + request = urllib2.Request(url=url, data=data) + response = opener.open(request, timeout=self.TIMEOUT) + result = response.read() + response.close() + except urllib2.HTTPError: + raise + + result = json.loads(result) + if result is None: + raise ValueError("JSON response could not be decoded") + + return self.handleResult(result) + + 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 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 + }) diff --git a/addons/pad/static/src/js/pad.js b/addons/pad/static/src/js/pad.js index e1e52150b81..e598ecca4f5 100644 --- a/addons/pad/static/src/js/pad.js +++ b/addons/pad/static/src/js/pad.js @@ -16,16 +16,17 @@ instance.web.form.FieldPad = instance.web.form.AbstractField.extend({ var self = this; var _super = self._super; _super.apply(self,[val]); + if (val === false || val === "") { - self.field_manager.dataset.call('pad_generate_url').then(function(data) { - - _super.apply(self,[data.url]); - - //var message="test value" - console.log('get :',data, this); - //setText(padID, text) - - self.render_value(); + self.field_manager.dataset.call('pad_generate_url',{context:{ + model: self.field_manager.model, + field_name: self.name, + object_id: self.field_manager.datarecord.id + }}).then(function(data) { + if(data&&data.url){ + _super.apply(self,[data.url]); + self.render_value(); + } }); } else { self.render_value(); @@ -33,7 +34,6 @@ instance.web.form.FieldPad = instance.web.form.AbstractField.extend({ this._dirty_flag = true; }, render_value: function() { - console.log("FieldPad.render_value: display"); var self = this; var value = this.get('value');