From 13cce602fb9009da14e19df4dd84fca5279e4317 Mon Sep 17 00:00:00 2001 From: Tejas Tank Date: Tue, 15 May 2012 16:49:28 +0530 Subject: [PATCH] Etherpad API Integraion, Set default blank pad, and user name per pad visit bzr revid: tta@openerp.com-20120515111928-dgpejwc01nlyxemf --- addons/pad/__init__.py | 1 - addons/pad/etherpad.py | 255 ++++++++++++++++++++++++++++++++ addons/pad/ir_attachment.py | 36 ----- addons/pad/pad.py | 44 +++--- addons/pad/static/src/js/pad.js | 20 +-- addons/project/project_view.xml | 1 + 6 files changed, 289 insertions(+), 68 deletions(-) create mode 100644 addons/pad/etherpad.py delete mode 100644 addons/pad/ir_attachment.py diff --git a/addons/pad/__init__.py b/addons/pad/__init__.py index 66d9ec971af..ee80bcaf8d0 100644 --- a/addons/pad/__init__.py +++ b/addons/pad/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import ir_attachment import pad import res_company diff --git a/addons/pad/etherpad.py b/addons/pad/etherpad.py new file mode 100644 index 00000000000..d60fc3672bc --- /dev/null +++ b/addons/pad/etherpad.py @@ -0,0 +1,255 @@ +#!/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 = "" + + 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) + print params + 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/ir_attachment.py b/addons/pad/ir_attachment.py deleted file mode 100644 index 7cf37211c6f..00000000000 --- a/addons/pad/ir_attachment.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -from osv import fields, osv -import random -import string - -class ir_attachment(osv.osv): - _inherit = 'ir.attachment' - - def pad_generate_url(self, cr, uid, model): - pad_url_template = self.pool.get('res.users').browse(cr,uid,[uid])[0].company_id.pad_url_template - s = string.ascii_uppercase + string.digits - salt = ''.join([s[random.randint(0, len(s) - 1)] for i in range(8)]) - template_vars = { - 'db' : cr.dbname, - 'model' : model, - 'salt' : salt, - } - return pad_url_template % template_vars - - def pad_get(self, cr, uid, model, id): - if not id: return False - attachment = self.search(cr, uid, [('res_model', '=', model), ('res_id', '=', id), ('type', '=', 'url'), ('name', '=', 'Pad')]) - if attachment: - return self.read(cr, uid, attachment)[0]['url'] - else: - url = self.pad_generate_url(cr, uid, model) - self.create(cr, uid, { - 'res_model' : model, - 'res_id' : id, - 'type' : 'url', - 'name' : 'Pad', - 'url' : url, - }) - return url - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/pad/pad.py b/addons/pad/pad.py index 2e69b099d1a..dca8a3241ab 100644 --- a/addons/pad/pad.py +++ b/addons/pad/pad.py @@ -3,6 +3,8 @@ from osv import fields, osv import random import string from etherpad import EtherpadLiteClient +import urllib2 +from tools.translate import _ class pad_common(osv.osv_memory): @@ -17,7 +19,22 @@ class pad_common(osv.osv_memory): 'model' : model, 'salt' : salt, } - return pad_url_template % template_vars + url = pad_url_template % template_vars + api_key = self._pad_api_key(cr, uid) + if api_key: + api_url = url[0:url.find("p/")] + "api" + pad_id = url[url.find("p/")+2:] + pad_author = self._pad_user_name(cr,uid) + ep_client = EtherpadLiteClient(api_key, api_url) + try: + ep_client.createPad(pad_id," ") + except ValueError as strerror: + raise osv.except_osv(_('Configuration Error !'),_("Etherpad Have Wrong API Key.")) + except urllib2.HTTPError as e: + raise osv.except_osv(_('Configuration Error !'),_("Etherpad Have Wrong API URL.")) + except urllib2.URLError as e: + raise osv.except_osv(_('Configuration Error !'),_("Etherpad Have Wrong Pad URL Template.")) + return url def _pad_api_key(self, cr, uid, ids=None, name=None, arg=None , context=None): if not ids: @@ -39,29 +56,18 @@ class pad_common(osv.osv_memory): if not default: default = {} default.update({ - 'pad_url':self.pool.get('ir.attachment').pad_generate_url(cr, uid, self._name), + 'pad_url':self.pad_generate_url(cr, uid, self._name), }) return super(pad_common, self).copy(cr, uid, id, default, context) - - def create(self, cr, uid, vals, context=None): - record_id = super(pad_common, self).create(cr, uid, vals, context=context) - res = self.browse(cr,uid, record_id) - url = res.pad_url - api_key = self._pad_api_key(cr, uid) - if api_key: - api_url = url[0:url.find("p/")] + "api/" - pad_id = url[url.find("p/")+2:] - pad_author = self._pad_user_name(cr,uid) - ep_client = EtherpadLiteClient(api_key, api_url) - ep_client.createPad(pad_id,"") - ep_client.createAuthor(pad_author) - return record_id - + _columns = { - 'pad_url': fields.char('Full Screen', size=512), + 'pad_url': fields.char('Full Screen', size=512), + 'pad_username': fields.function(_pad_user_name, string='Picked', type='char',size=64), + } _defaults = { - 'pad_url': lambda self, cr, uid, context: self.pool.get('ir.attachment').pad_generate_url(cr, uid, self._name), + 'pad_url': lambda self, cr, uid, context: self.pad_generate_url(cr, uid, self._name), + 'pad_username': lambda self, cr, uid, context: self._pad_user_name(cr,uid), } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/pad/static/src/js/pad.js b/addons/pad/static/src/js/pad.js index 287f7389918..c51cc23785a 100644 --- a/addons/pad/static/src/js/pad.js +++ b/addons/pad/static/src/js/pad.js @@ -11,8 +11,7 @@ instance.web.form.FieldEtherpad = instance.web.form.AbstractField.extend(_.exten this.$element.find('span').text((iszoom?'Back to Task':this.field.string)); this.$element.find('div').toggleClass('etherpad_zoom'); $("body").toggleClass('etherpad_body'); - },this)); - + },this)); }, set_value: function(value_) { this._super(value_); @@ -20,13 +19,12 @@ instance.web.form.FieldEtherpad = instance.web.form.AbstractField.extend(_.exten }, render_value: function() { var show_value = instance.web.format_value(this.get('value'), this, ''); - if (!this.get("effective_readonly")) { - // var pad_url = show_value.split('\n')[0]; -// var api_url = pad_url.substring( 0, (pad_url.search("/p/")+1) ); - // var pad_id = pad_url.substring((pad_url.search("p/")+2) ); - // console.log(this); - this.$element.find('div').html(''); - + if (!this.get("effective_readonly")) { + console.log("this is sthis...",this); + var pad_username = "noNamed" ; + if(this.view.datarecord.hasOwnProperty("pad_username")) + pad_username = this.view.datarecord.pad_username; + this.$element.find('div').html(''); } else { if(this.get('value') != false) { @@ -37,9 +35,7 @@ instance.web.form.FieldEtherpad = instance.web.form.AbstractField.extend(_.exten .error(function() { self.$element.text('Unable to load pad'); }); } } - }, - - + }, })); instance.web.form.widgets = instance.web.form.widgets.extend({ diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 03a924ad1bd..c467e76928f 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -355,6 +355,7 @@ +