[MERGE] Sync with trunk
bzr revid: tde@openerp.com-20130507093818-9hlt7e43r3y6002c
This commit is contained in:
commit
83a6705cf3
|
@ -0,0 +1,95 @@
|
|||
|
||||
import openerp.service.security as security
|
||||
import openerp.service.model as model
|
||||
import openerp
|
||||
|
||||
def _sessions():
|
||||
if getattr(_thread_data, "sessions", None) is None:
|
||||
_thread_data.sessions = []
|
||||
return _thread_data.sessions
|
||||
|
||||
class Session(object):
|
||||
def __init__(self, db, uid, password):
|
||||
self.db = db
|
||||
self.uid = uid
|
||||
self.password = password
|
||||
self.cr = None
|
||||
|
||||
def model(self, model_name):
|
||||
return Model(self, model_name)
|
||||
|
||||
def _execute(self, model_name, method, args, kwargs):
|
||||
self.ensure_transation()
|
||||
return model.execute_cr(self.cr, self.uid, model_name, method, *args, **kwargs)
|
||||
|
||||
def ensure_transation(self):
|
||||
if self.cr is None:
|
||||
security.check(self.db, self.uid, self.password)
|
||||
threading.currentThread().dbname = self.db
|
||||
self.cr = openerp.registry(self.db).db.cursor()
|
||||
|
||||
def close_transaction(self, has_exception=False):
|
||||
if self.cr is None:
|
||||
return
|
||||
if has_exception:
|
||||
try:
|
||||
self.cr.rollback()
|
||||
except:
|
||||
pass # nothing
|
||||
else:
|
||||
try:
|
||||
self.cr.commit()
|
||||
except:
|
||||
pass # nothing
|
||||
try:
|
||||
self.cr.close()
|
||||
except:
|
||||
pass # nothing
|
||||
self.cr = None
|
||||
|
||||
class Model(object):
|
||||
def __init__(self, session, name):
|
||||
self.session = session
|
||||
self.name = name
|
||||
|
||||
def __getattr__(self, method):
|
||||
def proxy(*args, **kw):
|
||||
result = self.session._execute(self.name, method, args, kw)
|
||||
# reorder read
|
||||
if method == "read":
|
||||
if isinstance(result, list) and len(result) > 0 and "id" in result[0]:
|
||||
index = {}
|
||||
for r in result:
|
||||
index[r['id']] = r
|
||||
result = [index[x] for x in args[0] if x in index]
|
||||
return result
|
||||
return proxy
|
||||
|
||||
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None, context=None):
|
||||
record_ids = self.search(domain or [], offset, limit or False, order or False, context or {})
|
||||
if not record_ids: return []
|
||||
records = self.read(record_ids, fields or [], context or {})
|
||||
return records
|
||||
|
||||
import threading
|
||||
_thread_data = threading.local()
|
||||
|
||||
class _ThreadSession:
|
||||
def __getattr__(self, name):
|
||||
if len(_sessions()) == 0:
|
||||
raise Exception("Session not initialized")
|
||||
return getattr(_sessions()[-1], name)
|
||||
def __setattr__(self, name, value):
|
||||
if len(_sessions()) == 0:
|
||||
raise Exception("Session not initialized")
|
||||
return setattr(_sessions()[-1], name, value)
|
||||
def init(self, db, uid, password):
|
||||
ses = self
|
||||
class with_obj:
|
||||
def __enter__(self):
|
||||
_sessions().append(Session(db, uid, password))
|
||||
def __exit__(self, type, value, traceback):
|
||||
_sessions().pop().close_transaction(type is not None)
|
||||
return with_obj()
|
||||
|
||||
transaction = _ThreadSession()
|
|
@ -19,6 +19,7 @@ import time
|
|||
import traceback
|
||||
import urlparse
|
||||
import uuid
|
||||
import errno
|
||||
|
||||
import babel.core
|
||||
import simplejson
|
||||
|
@ -117,6 +118,11 @@ class WebRequest(object):
|
|||
# we use _ as seprator where RFC2616 uses '-'
|
||||
self.lang = lang.replace('-', '_')
|
||||
|
||||
def wrap_transaction(self, fct):
|
||||
from openerp.addons.web.com import transaction
|
||||
with transaction.init(self.session._db, self.session._uid, self.session._password):
|
||||
return fct()
|
||||
|
||||
def reject_nonliteral(dct):
|
||||
if '__ref' in dct:
|
||||
raise ValueError(
|
||||
|
@ -199,8 +205,8 @@ class JsonRequest(WebRequest):
|
|||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug("--> %s.%s\n%s", method.im_class.__name__, method.__name__, pprint.pformat(self.jsonrequest))
|
||||
response['id'] = self.jsonrequest.get('id')
|
||||
response["result"] = method(self, **self.params)
|
||||
except session.AuthenticationError:
|
||||
response["result"] = self.wrap_transaction(lambda: method(self, **self.params))
|
||||
except session.AuthenticationError, e:
|
||||
se = serialize_exception(e)
|
||||
error = {
|
||||
'code': 100,
|
||||
|
@ -293,7 +299,7 @@ class HttpRequest(WebRequest):
|
|||
akw[key] = type(value)
|
||||
_logger.debug("%s --> %s.%s %r", self.httprequest.method, method.im_class.__name__, method.__name__, akw)
|
||||
try:
|
||||
r = method(self, **self.params)
|
||||
r = self.wrap_transaction(lambda: method(self, **self.params))
|
||||
except Exception, e:
|
||||
_logger.exception("An exception occured during an http request")
|
||||
se = serialize_exception(e)
|
||||
|
@ -354,17 +360,31 @@ def httprequest(f):
|
|||
addons_module = {}
|
||||
addons_manifest = {}
|
||||
controllers_class = []
|
||||
controllers_class_path = {}
|
||||
controllers_object = {}
|
||||
controllers_object_path = {}
|
||||
controllers_path = {}
|
||||
|
||||
class ControllerType(type):
|
||||
def __init__(cls, name, bases, attrs):
|
||||
super(ControllerType, cls).__init__(name, bases, attrs)
|
||||
controllers_class.append(("%s.%s" % (cls.__module__, cls.__name__), cls))
|
||||
name_class = ("%s.%s" % (cls.__module__, cls.__name__), cls)
|
||||
controllers_class.append(name_class)
|
||||
path = attrs.get('_cp_path')
|
||||
if path not in controllers_class_path:
|
||||
controllers_class_path[path] = name_class
|
||||
|
||||
class Controller(object):
|
||||
__metaclass__ = ControllerType
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
subclasses = [c for c in cls.__subclasses__() if c._cp_path == cls._cp_path]
|
||||
if subclasses:
|
||||
name = "%s (extended by %s)" % (cls.__name__, ', '.join(sub.__name__ for sub in subclasses))
|
||||
cls = type(name, tuple(reversed(subclasses)), {})
|
||||
|
||||
return object.__new__(cls)
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Session context manager
|
||||
#----------------------------------------------------------
|
||||
|
@ -476,8 +496,15 @@ def session_path():
|
|||
except Exception:
|
||||
username = "unknown"
|
||||
path = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
|
||||
if not os.path.exists(path):
|
||||
try:
|
||||
os.mkdir(path, 0700)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST:
|
||||
# directory exists: ensure it has the correct permissions
|
||||
# this will fail if the directory is not owned by the current user
|
||||
os.chmod(path, 0700)
|
||||
else:
|
||||
raise
|
||||
return path
|
||||
|
||||
class Root(object):
|
||||
|
@ -541,7 +568,7 @@ class Root(object):
|
|||
controllers and configure them. """
|
||||
|
||||
for addons_path in openerp.modules.module.ad_paths:
|
||||
for module in sorted(os.listdir(addons_path)):
|
||||
for module in sorted(os.listdir(str(addons_path))):
|
||||
if module not in addons_module:
|
||||
manifest_path = os.path.join(addons_path, module, '__openerp__.py')
|
||||
path_static = os.path.join(addons_path, module, 'static')
|
||||
|
@ -557,10 +584,11 @@ class Root(object):
|
|||
addons_manifest[module] = manifest
|
||||
self.statics['/%s/static' % module] = path_static
|
||||
|
||||
for k, v in controllers_class:
|
||||
if k not in controllers_object:
|
||||
o = v()
|
||||
controllers_object[k] = o
|
||||
for k, v in controllers_class_path.items():
|
||||
if k not in controllers_object_path and hasattr(v[1], '_cp_path'):
|
||||
o = v[1]()
|
||||
controllers_object[v[0]] = o
|
||||
controllers_object_path[k] = o
|
||||
if hasattr(o, '_cp_path'):
|
||||
controllers_path[o._cp_path] = o
|
||||
|
||||
|
@ -591,6 +619,9 @@ class Root(object):
|
|||
elif exposed == 'http':
|
||||
_logger.debug("Dispatch http to %s %s %s", ps, c, method_name)
|
||||
return lambda request: HttpRequest(request).dispatch(method)
|
||||
elif method_name != "index":
|
||||
method_name = "index"
|
||||
continue
|
||||
ps, _slash, method_name = ps.rpartition('/')
|
||||
if not ps and method_name:
|
||||
ps = '/'
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,7 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-04-29 04:42+0000\n"
|
||||
"X-Launchpad-Export-Date: 2013-04-30 05:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16580)\n"
|
||||
|
||||
#. module: web_kanban
|
||||
|
|
|
@ -133,12 +133,16 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
|
|||
}
|
||||
switch (node.tag) {
|
||||
case 'field':
|
||||
if (this.fields_view.fields[node.attrs.name].type === 'many2many') {
|
||||
var ftype = this.fields_view.fields[node.attrs.name].type;
|
||||
ftype = node.attrs.widget ? node.attrs.widget : ftype;
|
||||
if (ftype === 'many2many') {
|
||||
if (_.indexOf(this.many2manys, node.attrs.name) < 0) {
|
||||
this.many2manys.push(node.attrs.name);
|
||||
}
|
||||
node.tag = 'div';
|
||||
node.attrs['class'] = (node.attrs['class'] || '') + ' oe_form_field oe_tags';
|
||||
} else if (instance.web_kanban.fields_registry.contains(ftype)) {
|
||||
// do nothing, the kanban record will handle it
|
||||
} else {
|
||||
node.tag = QWeb.prefix;
|
||||
node.attrs[QWeb.prefix + '-esc'] = 'record.' + node.attrs['name'] + '.value';
|
||||
|
@ -766,6 +770,7 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({
|
|||
};
|
||||
}
|
||||
this.state = this.view.state.records[this.id];
|
||||
this.fields = {};
|
||||
},
|
||||
set_record: function(record) {
|
||||
var self = this;
|
||||
|
@ -779,7 +784,16 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({
|
|||
this.record = this.transform_record(record);
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
this.init_content();
|
||||
},
|
||||
init_content: function() {
|
||||
var self = this;
|
||||
self.sub_widgets = [];
|
||||
this.$("[data-field_id]").each(function() {
|
||||
self.add_widget($(this));
|
||||
});
|
||||
this.$el.data('widget', this);
|
||||
this.bind_events();
|
||||
},
|
||||
|
@ -815,6 +829,28 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({
|
|||
'content': this.view.qweb.render('kanban-box', this.qweb_context)
|
||||
});
|
||||
this.replaceElement($el);
|
||||
this.replace_fields();
|
||||
},
|
||||
replace_fields: function() {
|
||||
var self = this;
|
||||
this.$("field").each(function() {
|
||||
var $field = $(this);
|
||||
var $nfield = $("<span></span");
|
||||
var id = _.uniqueId("kanbanfield");
|
||||
self.fields[id] = $field;
|
||||
$nfield.attr("data-field_id", id);
|
||||
$field.replaceWith($nfield);
|
||||
});
|
||||
},
|
||||
add_widget: function($node) {
|
||||
var $orig = this.fields[$node.data("field_id")];
|
||||
var field = this.record[$orig.attr("name")];
|
||||
var type = field.type;
|
||||
type = $orig.attr("widget") ? $orig.attr("widget") : type;
|
||||
var obj = instance.web_kanban.fields_registry.get_object(type);
|
||||
var widget = new obj(this, field, $orig);
|
||||
this.sub_widgets.push(widget);
|
||||
widget.replace($node);
|
||||
},
|
||||
bind_events: function() {
|
||||
var self = this;
|
||||
|
@ -956,11 +992,14 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({
|
|||
do_reload: function() {
|
||||
var self = this;
|
||||
this.view.dataset.read_ids([this.id], this.view.fields_keys.concat(['__last_update'])).done(function(records) {
|
||||
_.each(self.sub_widgets, function(el) {
|
||||
el.destroy();
|
||||
});
|
||||
self.sub_widgets = [];
|
||||
if (records.length) {
|
||||
self.set_record(records[0]);
|
||||
self.renderElement();
|
||||
self.$el.data('widget', self);
|
||||
self.bind_events();
|
||||
self.init_content();
|
||||
self.group.compute_cards_auto_height();
|
||||
self.view.postprocess_m2m_tags();
|
||||
} else {
|
||||
|
@ -1114,6 +1153,44 @@ instance.web_kanban.QuickCreate = instance.web.Widget.extend({
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Interface to be implemented by kanban fields.
|
||||
*
|
||||
*/
|
||||
instance.web_kanban.FieldInterface = {
|
||||
/**
|
||||
Constructor.
|
||||
- parent: The widget's parent.
|
||||
- field: A dictionary giving details about the field, including the current field's value in the
|
||||
raw_value field.
|
||||
- $node: The field <field> tag as it appears in the view, encapsulated in a jQuery object.
|
||||
*/
|
||||
init: function(parent, field, $node) {},
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract class for classes implementing FieldInterface.
|
||||
*
|
||||
* Properties:
|
||||
* - value: useful property to hold the value of the field. By default, the constructor
|
||||
* sets value property.
|
||||
*
|
||||
*/
|
||||
instance.web_kanban.AbstractField = instance.web.Widget.extend(instance.web_kanban.FieldInterface, {
|
||||
/**
|
||||
Constructor that saves the field and $node parameters and sets the "value" property.
|
||||
*/
|
||||
init: function(parent, field, $node) {
|
||||
this._super(parent);
|
||||
this.field = field;
|
||||
this.$node = $node;
|
||||
this.options = instance.web.py_eval(this.$node.attr("options") || '{}');
|
||||
this.set("value", field.raw_value);
|
||||
},
|
||||
});
|
||||
|
||||
instance.web_kanban.fields_registry = new instance.web.Registry({});
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||
|
|
Loading…
Reference in New Issue