Merge pull request #611 from odoo-dev/saas-3-really-fix-session-expired-fme
authorodony <odo@openerp.com>
Fri, 20 Jun 2014 09:02:22 +0000 (11:02 +0200)
committerodony <odo@openerp.com>
Fri, 20 Jun 2014 09:02:22 +0000 (11:02 +0200)
[MERGE]  http routing: fix handle_exception logic and _authenticate exceptions

* Better separate JsonRequest and HttpRequest handling
for exceptions, so each type of request handles exception
the right way. Previously HttpRequest would supersede
JsonRequest in some cases and generate pure HTML
responses where a JSON result was expected.
* Also ensure that ir.http._authenticate() only raises
two possible exception types, hiding any other kind
of internal errors:
 - openerp.exceptions.AccessDenied
 - openerp.http.SessionExpiredException

15 files changed:
addons/account_voucher/voucher_sales_purchase_view.xml
addons/auth_crypt/auth_crypt.py
addons/l10n_be_invoice_bba/invoice.py
addons/mail/mail_thread.py
addons/mrp/mrp.py
addons/project/project_demo.xml
addons/sale/sale.py
addons/web/static/src/css/base.css
addons/web/static/src/css/base.sass
addons/web/static/src/js/formats.js
addons/web/static/src/js/search.js
addons/web/static/src/js/view_form.js
addons/web/static/src/js/view_list_editable.js
addons/web_calendar/static/src/js/web_calendar.js
addons/website/static/src/js/website.editor.js

index 97f96f7..2dd5383 100644 (file)
                         <page string="Bill Information">
                             <field name="line_dr_ids" on_change="onchange_price(line_dr_ids, tax_id, partner_id)" context="{'journal_id':journal_id,'partner_id':partner_id}">
                                 <tree string="Expense Lines" editable="bottom">
-                                    <field name="account_id" widget="selection" domain="[('user_type.report_type','=','expense'), ('type','!=','view')]"/>
+                                    <field name="account_id" domain="[('user_type.report_type','=','expense'), ('type','!=','view')]"/>
                                     <field name="name"/>
                                     <field name="amount"/>
                                     <field name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
index 4651d27..c5bd579 100644 (file)
@@ -117,10 +117,22 @@ def sh256crypt(cls, password, salt, magic=magic_sha256):
 class res_users(osv.osv):
     _inherit = "res.users"
 
+    def init(self, cr):
+        """Encrypt all passwords at module installation"""
+        cr.execute("SELECT id, password FROM res_users WHERE password IS NOT NULL and password != ''")
+        for user in cr.fetchall():
+            self._set_encrypted_password(cr, user[0], user[1])
+
+    def _set_encrypted_password(self, cr, uid, plain_password):
+        """Set an encrypted password for a given user"""
+        salt = gen_salt()
+        stored_password_crypt = md5crypt(plain_password, salt)
+        cr.execute("UPDATE res_users SET password = '', password_crypt = %s WHERE id = %s",
+                   (stored_password_crypt, uid))
+
     def set_pw(self, cr, uid, id, name, value, args, context):
         if value:
-            encrypted = md5crypt(value, gen_salt())
-            cr.execute("update res_users set password='', password_crypt=%s where id=%s", (encrypted, id))
+            self._set_encrypted_password(cr, id, value)
         del value
 
     def get_pw( self, cr, uid, ids, name, args, context ):
@@ -144,9 +156,7 @@ class res_users(osv.osv):
         if cr.rowcount:
             stored_password, stored_password_crypt = cr.fetchone()
             if stored_password and not stored_password_crypt:
-                salt = gen_salt()
-                stored_password_crypt = md5crypt(stored_password, salt)
-                cr.execute("UPDATE res_users SET password='', password_crypt=%s WHERE id=%s", (stored_password_crypt, uid))
+                self._set_encrypted_password(cr, uid, stored_password)
         try:
             return super(res_users, self).check_credentials(cr, uid, password)
         except openerp.exceptions.AccessDenied:
index 854593a..499e6e6 100644 (file)
@@ -141,7 +141,7 @@ class account_invoice(osv.osv):
                 elif algorithm == 'random':\r
                     if not self.check_bbacomm(reference):\r
                         base = random.randint(1, 9999999999)\r
-                        bbacomm = str(base).rjust(7, '0')\r
+                        bbacomm = str(base).rjust(10, '0')\r
                         base = int(bbacomm)\r
                         mod = base % 97 or 97\r
                         mod = str(mod).rjust(2, '0')\r
index a264d58..8324b60 100644 (file)
@@ -33,6 +33,7 @@ import pytz
 import socket
 import time
 import xmlrpclib
+import re
 from email.message import Message
 
 from openerp import tools
@@ -46,6 +47,8 @@ from openerp.tools.translate import _
 _logger = logging.getLogger(__name__)
 
 
+mail_header_msgid_re = re.compile('<[^<>]+>')
+
 def decode_header(message, header, separator=' '):
     return separator.join(map(decode, filter(None, message.get_all(header, []))))
 
@@ -1259,13 +1262,13 @@ class mail_thread(osv.AbstractModel):
             msg_dict['date'] = stored_date.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
 
         if message.get('In-Reply-To'):
-            parent_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', decode(message['In-Reply-To']))])
+            parent_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', decode(message['In-Reply-To'].strip()))])
             if parent_ids:
                 msg_dict['parent_id'] = parent_ids[0]
 
         if message.get('References') and 'parent_id' not in msg_dict:
-            parent_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', 'in',
-                                                                         [x.strip() for x in decode(message['References']).split()])])
+            msg_list =  mail_header_msgid_re.findall(decode(message['References']))
+            parent_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', 'in', [x.strip() for x in msg_list])])
             if parent_ids:
                 msg_dict['parent_id'] = parent_ids[0]
 
index 6b629a1..bdcf0ab 100644 (file)
@@ -1046,8 +1046,8 @@ class mrp_production(osv.osv):
 
             # Take routing location as a Source Location.
             source_location_id = production.location_src_id.id
-            if production.bom_id.routing_id and production.bom_id.routing_id.location_id:
-                source_location_id = production.bom_id.routing_id.location_id.id
+            if production.routing_id and production.routing_id.location_id:
+                source_location_id = production.routing_id.location_id.id
 
             for line in production.product_lines:
                 consume_move_id = self._make_production_consume_line(cr, uid, line, produce_move_id, source_location_id=source_location_id, context=context)
index ff225c4..bb09e68 100644 (file)
@@ -50,8 +50,8 @@
             <field name="user_id" ref="base.user_demo"/>
             <field name="alias_model">project.task</field>
             <field name="message_follower_ids" eval="[(6, 0, [
-                    ref('base.user_root'),
-                    ref('base.user_demo')])]"/>
+                    ref('base.partner_root'),
+                    ref('base.partner_demo')])]"/>
         </record>
 
         <!-- We assign after so that default values applies -->
index 8e89519..1a26d51 100644 (file)
@@ -128,13 +128,12 @@ class sale_order(osv.osv):
         sale_clause = ''
         no_invoiced = False
         for arg in args:
-            if arg[1] == '=':
-                if arg[2]:
-                    clause += 'AND inv.state = \'paid\''
-                else:
-                    clause += 'AND inv.state != \'cancel\' AND sale.state != \'cancel\'  AND inv.state <> \'paid\'  AND rel.order_id = sale.id '
-                    sale_clause = ',  sale_order AS sale '
-                    no_invoiced = True
+            if (arg[1] == '=' and arg[2]) or (arg[1] == '!=' and not arg[2]):
+                clause += 'AND inv.state = \'paid\''
+            else:
+                clause += 'AND inv.state != \'cancel\' AND sale.state != \'cancel\'  AND inv.state <> \'paid\'  AND rel.order_id = sale.id '
+                sale_clause = ',  sale_order AS sale '
+                no_invoiced = True
 
         cursor.execute('SELECT rel.order_id ' \
                 'FROM sale_order_invoice_rel AS rel, account_invoice AS inv '+ sale_clause + \
index 8c2da02..5f9ecc5 100644 (file)
 }
 .openerp .oe_fileupload .oe_add button.oe_attach .oe_e {
   position: relative;
-  top: -1px;
+  top: -10px;
   left: -9px;
 }
 .openerp .oe_fileupload .oe_add input.oe_form_binary_file {
@@ -3392,6 +3392,9 @@ body.oe_single_form .oe_single_form_container {
 .openerp_ie .ui-dialog-buttonpane .ui-dialog-buttonset .ui-button {
   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#EFEFEF', endColorstr='#D8D8D8');
 }
+.openerp_ie .oe_webclient {
+  height: auto !important;
+}
 
 @media print {
   .openerp {
index b18e4fc..e63092f 100644 (file)
@@ -1984,7 +1984,7 @@ $sheet-padding: 16px
                 text-shadow: none
                 .oe_e
                     position: relative
-                    top: -1px
+                    top: -10px
                     left: -9px                    
             input.oe_form_binary_file
                 display: inline-block
@@ -2736,6 +2736,8 @@ body.oe_single_form
     // jquery ui for ie
     .ui-dialog-buttonpane .ui-dialog-buttonset .ui-button
         filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#EFEFEF', endColorstr='#D8D8D8')
+    .oe_webclient
+        height: auto !important
 // }}}
 
 // @media print {{{
index a56ab6b..f08dc31 100644 (file)
@@ -271,6 +271,11 @@ instance.web.parse_value = function (value, descriptor, value_if_empty) {
                     value, (date_pattern + ' ' + time_pattern));
             if (datetime !== null)
                 return instance.web.datetime_to_str(datetime);
+            datetime = Date.parseExact(value.replace(/\d+/g, function(m){
+                return m.length === 1 ? "0" + m : m ;
+            }), (date_pattern + ' ' + time_pattern));
+            if (datetime !== null)
+                return instance.web.datetime_to_str(datetime);
             datetime = Date.parse(value);
             if (datetime !== null)
                 return instance.web.datetime_to_str(datetime);
@@ -279,6 +284,11 @@ instance.web.parse_value = function (value, descriptor, value_if_empty) {
             var date = Date.parseExact(value, date_pattern);
             if (date !== null)
                 return instance.web.date_to_str(date);
+            date = Date.parseExact(value.replace(/\d+/g, function(m){
+                return m.length === 1 ? "0" + m : m ;
+            }), date_pattern);
+            if (date !== null)
+                return instance.web.date_to_str(date);
             date = Date.parse(value);
             if (date !== null)
                 return instance.web.date_to_str(date);
index 8b400be..3a84849 100644 (file)
@@ -345,11 +345,11 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
         'keydown .oe_searchview_input, .oe_searchview_facet': function (e) {
             switch(e.which) {
             case $.ui.keyCode.LEFT:
-                this.focusPreceding(this);
+                this.focusPreceding(e.target);
                 e.preventDefault();
                 break;
             case $.ui.keyCode.RIGHT:
-                this.focusFollowing(this);
+                this.focusFollowing(e.target);
                 e.preventDefault();
                 break;
             }
index b645db4..f5af096 100644 (file)
@@ -2440,6 +2440,7 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
     type_of_date: "datetime",
     events: {
         'change .oe_datepicker_master': 'change_datetime',
+        'keypress .oe_datepicker_master': 'change_datetime',
     },
     init: function(parent) {
         this._super(parent);
@@ -2558,8 +2559,8 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
     format_client: function(v) {
         return instance.web.format_value(v, {"widget": this.type_of_date});
     },
-    change_datetime: function() {
-        if (this.is_valid_()) {
+    change_datetime: function(e) {
+        if ((e.type !== "keypress" || e.which === 13) && this.is_valid_()) {
             this.set_value_from_ui_();
             this.trigger("datetime_changed");
         }
index fb70454..ea2c28d 100644 (file)
                     }, options).then(function () {
                         $recordRow.addClass('oe_edition');
                         self.resize_fields();
-                        var focus_field = options && options.focus_field ? options.focus_field : (self.visible_columns.length ? self.visible_columns[0].name : undefined);
+                        var focus_field = options && options.focus_field ? options.focus_field : undefined;
+                        if (!focus_field){
+                            focus_field = _.find(self.editor.form.fields_order, function(field){ return fields[field] && fields[field].$el.is(':visible:has(input)'); });
+                        }
                         if (focus_field) fields[focus_field].$el.find('input').select();
                         return record.attributes;
                     });
index 6db2d97..ad49ff9 100644 (file)
@@ -212,7 +212,12 @@ openerp.web_calendar = function(instance) {
                 this.info_fields.push(fv.arch.children[fld].attrs.name);
             }
 
-            return (new instance.web.Model(this.dataset.model))
+            var edit_check = new instance.web.Model(this.dataset.model)
+                .call("check_access_rights", ["write", false])
+                .then(function (write_right) {
+                    self.write_right = write_right;
+                });
+            var init = new instance.web.Model(this.dataset.model)
                 .call("check_access_rights", ["create", false])
                 .then(function (create_right) {
                     self.create_right = create_right;
@@ -222,6 +227,7 @@ openerp.web_calendar = function(instance) {
                         self.ready.resolve();
                     });
                 });
+            return $.when(edit_check, init);
         },
 
         get_fc_init_options: function () {
@@ -834,7 +840,11 @@ openerp.web_calendar = function(instance) {
             if (! this.open_popup_action) {
                 var index = this.dataset.get_id_index(id);
                 this.dataset.index = index;
-                this.do_switch_view('form', null, { mode: "edit" });
+                if (this.write_right) {
+                    this.do_switch_view('form', null, { mode: "edit" });
+                } else {
+                    this.do_switch_view('form', null, { mode: "view" });
+                }
             }
             else {
                 var pop = new instance.web.form.FormOpenPopup(this);
index 7151987..e741b80 100644 (file)
                     }
                 );
             });
-            menu.on('click', 'a[data-action!=ace]', function (event) {
+            menu.on('click', 'a[data-view-id]', function (event) {
                 var view_id = $(event.currentTarget).data('view-id');
                 openerp.jsonRpc('/website/customize_template_toggle', 'call', {
                     'view_id': view_id