diff options
| author | Antony Lesuisse <al@openerp.com> | 2012-09-21 01:53:43 +0200 |
|---|---|---|
| committer | Antony Lesuisse <al@openerp.com> | 2012-09-21 01:53:43 +0200 |
| commit | 283131289d8cccd1f05acb262dfc19cf27a2b539 (patch) | |
| tree | 4538feca71972ef9cbdd53083cdaca5f418ec59b | |
| parent | eafe3416291a08d114d75d2e8259590070889eac (diff) | |
| parent | f154707dcb6bcecfb978a37104a3fdeb2a71194d (diff) | |
[MERGE] note: remove optionals tags, pad: fix lazy pad creation
bzr revid: al@openerp.com-20120920235343-tveo33j410atkt2y
| -rw-r--r-- | addons/note/note.py | 1 | ||||
| -rw-r--r-- | addons/note/note_demo.xml | 50 | ||||
| -rw-r--r-- | addons/note/note_view.xml | 8 | ||||
| -rw-r--r-- | addons/note/security/res.groups.csv | 1 | ||||
| -rw-r--r-- | addons/pad/pad.py | 49 | ||||
| -rw-r--r-- | addons/pad/py_etherpad/__init__.py | 253 | ||||
| -rw-r--r-- | addons/pad/static/src/js/pad.js | 14 |
7 files changed, 320 insertions, 56 deletions
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 @@ <record model="note.stage" id="demo_note_stage_01"> <field name="name">Today</field> <field name="sequence">1</field> - <field name="user_id" eval="ref('base.user_demo')"/> + <field name="user_id" ref="base.user_demo"/> </record> <record model="note.stage" id="demo_note_stage_02"> <field name="name">Tomorrow</field> <field name="sequence">2</field> - <field name="user_id" eval="ref('base.user_demo')"/> + <field name="user_id" ref="base.user_demo"/> </record> <record model="note.stage" id="demo_note_stage_03"> <field name="name">Later</field> <field name="sequence">3</field> - <field name="user_id" eval="ref('base.user_demo')"/> + <field name="user_id" ref="base.user_demo"/> </record> <record model="note.stage" id="demo_note_stage_04"> - <field name="name">Notes</field> + <field name="name">Morning</field> <field name="sequence">4</field> - <field name="user_id" eval="ref('base.user_demo')"/> + <field name="user_id" ref="base.user_root"/> </record> - <record id="note_1" model="note.note"> <field name="name">Customer report #349872</field> <field name="memo"><![CDATA[<b>Customer report #349872</b> @@ -35,8 +34,9 @@ <br/>* We should use the term Calendar, not Meeting. ]]> </field> - <field name="stage_id" ref="note_stage_01"/> + <field name="stage_id" ref="demo_note_stage_01"/> <field name="color">2</field> + <field name="message_follower_ids" eval="[(4, ref('base.group_user'))]"/> </record> <record id="note_2" model="note.note"> @@ -44,14 +44,7 @@ <br/><br/>* Followed by the telephone conversation and mail about D.544.3 ]]> </field> - <field name="stage_id" ref="note_stage_01"/> - </record> - - <record id="note_3" model="note.note"> - <field name="memo"><![CDATA[<b>Call Marc</b> - <br/><br/>]]> - </field> - <field name="stage_id" ref="note_stage_01"/> + <field name="stage_id" ref="demo_note_stage_01"/> </record> <record id="note_4" model="note.note"> @@ -67,7 +60,8 @@ <br/>* wine ]]> </field> - <field name="stage_id" ref="note_stage_02"/> + <field name="stage_id" ref="demo_note_stage_02"/> + <field name="message_follower_ids" eval="[(4, ref('base.group_user'))]"/> </record> <record id="note_6" model="note.note"> @@ -79,15 +73,6 @@ <field name="stage_id" ref="note_stage_02"/> </record> - <record id="note_7" model="note.note"> - <field name="memo"><![CDATA[<b>Read some documentation about OpenERP before diving into the code</b> - <br/><br/>* Open ERP: a modern approach to integrated business management - <br/>* Open ERP for Retail and Industrial Management - ]]> - </field> - <field name="stage_id" ref="note_stage_03"/> - </record> - <record id="note_8" model="note.note"> <field name="memo"><![CDATA[<b>New computer specs</b> <br/><br/>* Motherboard @@ -108,6 +93,7 @@ </field> <field name="stage_id" ref="note_stage_03"/> <field name="color">3</field> + <field name="message_follower_ids" eval="[(4, ref('base.group_user'))]"/> </record> <record id="note_9" model="note.note"> @@ -116,16 +102,7 @@ <br/>* Open ERP for Retail and Industrial Management ]]> </field> - <field name="stage_id" ref="note_stage_02"/> - </record> - - <record id="note_10" model="note.note"> - <field name="memo"><![CDATA[<b>Read some documentation about OpenERP before diving into the code</b> - <br/><br/>* Open ERP: a modern approach to integrated business management - <br/>* Open ERP for Retail and Industrial Management - ]]> - </field> - <field name="stage_id" ref="note_stage_03"/> + <field name="stage_id" ref="demo_note_stage_02"/> </record> <record id="note_12" model="note.note"> @@ -134,8 +111,9 @@ <br/>* Open ERP for Retail and Industrial Management ]]> </field> - <field name="stage_id" ref="note_stage_03"/> + <field name="message_follower_ids" eval="[(4, ref('base.group_user'))]"/> <field name="color">7</field> + <field name="stage_ids" eval="['note_stage_03','demo_note_stage_04']"/> </record> </data> 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 @@ <field name="name"/> <field name="open"/> <field name="stage_id"/> - <field name="tag_ids" widget="many2many_tags" groups="note.group_note_tags"/> + <field name="tag_ids" widget="many2many_tags"/> </tree> </field> </record> @@ -130,7 +130,7 @@ <field name="arch" type="xml"> <search string="Notes"> <field name="memo" string="Note"/> - <field name="tag_ids" groups="note.group_note_tags"/> + <field name="tag_ids"/> <filter name="open_true" string="Active" domain="['|',('open', '=', True),('date_done','=',time.strftime('%%Y-%%m-%%d'))]"/> <filter name="open_false" string="Archive" domain="[('open', '=', False)]"/> <group expand="0" string="Group By..."> @@ -159,10 +159,6 @@ <field name="group_note_fancy" class="oe_inline"/> <label for="group_note_fancy"/> </div> - <div> - <field name="group_note_tags" class="oe_inline"/> - <label for="group_note_tags"/> - </div> </div> </group> </xpath> 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'); |
