diff --git a/addons/note/note.py b/addons/note/note.py
index fb3f0cee853..9d62f7a2cb7 100644
--- a/addons/note/note.py
+++ b/addons/note/note.py
@@ -185,5 +185,4 @@ class note_base_config_settings(osv.osv_memory):
_columns = {
'module_note_pad': fields.boolean('Use collaborative pads (etherpad)'),
'group_note_fancy': fields.boolean('Use fancy layouts for notes', implied_group='note.group_note_fancy'),
- 'group_note_tags': fields.boolean('Allow setting tags on notes', implied_group='note.group_note_tags'),
}
diff --git a/addons/note/note_demo.xml b/addons/note/note_demo.xml
index 16fa5a3f66b..7769e3ee303 100644
--- a/addons/note/note_demo.xml
+++ b/addons/note/note_demo.xml
@@ -4,28 +4,27 @@
Today1
-
+ Tomorrow2
-
+ Later3
-
+
- Notes
+ Morning4
-
+
-
Customer report #349872Customer report #349872
@@ -35,8 +34,9 @@
* We should use the term Calendar, not Meeting.
]]>
-
+ 2
+
@@ -44,14 +44,7 @@
* Followed by the telephone conversation and mail about D.544.3
]]>
-
-
-
-
- Call Marc
-
]]>
-
-
+
@@ -67,7 +60,8 @@
* wine
]]>
-
+
+
@@ -79,15 +73,6 @@
-
- Read some documentation about OpenERP before diving into the code
-
* Open ERP: a modern approach to integrated business management
- * Open ERP for Retail and Industrial Management
- ]]>
-
-
-
-
New computer specs
* Motherboard
@@ -108,6 +93,7 @@
3
+
@@ -116,16 +102,7 @@
* Open ERP for Retail and Industrial Management
]]>
-
-
-
-
- Read some documentation about OpenERP before diving into the code
-
* Open ERP: a modern approach to integrated business management
- * Open ERP for Retail and Industrial Management
- ]]>
-
-
+
@@ -134,8 +111,9 @@
* Open ERP for Retail and Industrial Management
]]>
-
+ 7
+
diff --git a/addons/note/note_view.xml b/addons/note/note_view.xml
index a92c6abe30a..62b007aab6e 100644
--- a/addons/note/note_view.xml
+++ b/addons/note/note_view.xml
@@ -101,7 +101,7 @@
-
+
@@ -130,7 +130,7 @@
-
+
@@ -159,10 +159,6 @@
-
-
-
-
diff --git a/addons/note/security/res.groups.csv b/addons/note/security/res.groups.csv
index 61c54c964ff..88d7b2cd667 100644
--- a/addons/note/security/res.groups.csv
+++ b/addons/note/security/res.groups.csv
@@ -1,3 +1,2 @@
id,name,implied_ids/id
-group_note_tags,Memo / Display tags,
group_note_fancy,Memo / Fancy mode,
diff --git a/addons/pad/pad.py b/addons/pad/pad.py
index 48ac940ccfa..0cbb6107979 100644
--- a/addons/pad/pad.py
+++ b/addons/pad/pad.py
@@ -5,24 +5,56 @@ 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)
- return url
+ 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]))
+ #Etherpad for html not functional
+ #myPad.setHTML(path, record[real_field])
+
+ return {
+ "server": pad["server"],
+ "path": path,
+ "url": url,
+ }
def pad_get_content(self, cr, uid, url, context=None):
content = ''
@@ -57,7 +89,8 @@ class pad_common(osv.osv_memory):
for k,v in self._all_columns:
field = v.column
if hasattr(field,'pad_content_field'):
- default[k] = self.pad_generate_url(cr, uid, context)
+ pad = self.pad_generate_url(cr, uid, context)
+ default[k] = pad['url']
return super(pad_common, self).copy(cr, uid, id, default, context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
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 b7c13ba1b89..e598ecca4f5 100644
--- a/addons/pad/static/src/js/pad.js
+++ b/addons/pad/static/src/js/pad.js
@@ -16,10 +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(r) {
- _super.apply(self,[r]);
- 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();
@@ -27,7 +34,6 @@ instance.web.form.FieldPad = instance.web.form.AbstractField.extend({
this._dirty_flag = true;
},
render_value: function() {
- console.log("display");
var self = this;
var value = this.get('value');