ir.attachment: revise the access control code, let it be overriden
[odoo/odoo.git] / bin / addons / base / ir / ir_attachment.py
index ba93c95..0811e3b 100644 (file)
@@ -24,16 +24,29 @@ from osv.orm import except_orm
 import tools
 
 class ir_attachment(osv.osv):
-    def check(self, cr, uid, ids, mode, context=None):
+    def check(self, cr, uid, ids, mode, context=None, values=None):
+        """Restricts the access to an ir.attachment, according to referred model
+        In the 'document' module, it is overriden to relax this hard rule, since
+        more complex ones apply there.
+        """
         if not ids:
             return
         ima = self.pool.get('ir.model.access')
-        if isinstance(ids, (int, long)):
-            ids = [ids]
-        cr.execute('select distinct res_model from ir_attachment where id IN %s', (tuple(ids),))
-        for obj in cr.fetchall():
-            if obj[0]:
-                ima.check(cr, uid, obj[0], mode, context=context)
+        res_ids = {}
+        if ids:
+            if isinstance(ids, (int, long)):
+                ids = [ids]
+            cr.execute('SELECT DISTINCT res_model, res_id FROM ir_attachment WHERE id = ANY (%s)', (ids,), self._debug)
+            for rmod, rid in cr.fetchall():
+                if not (rmod and rid):
+                    continue
+                res_ids.setdefault(rmod,[]).append(rid)
+        if values:
+            if 'res_model' in values and 'res_id' in values:
+                res_ids.setdefault(values['res_model'],[]).append(values['res_id'])
+        
+        for model, mids in res_ids.items():
+            self.pool.get(model).check_access_rule(cr, uid, mids, mode, context=context)
 
     def search(self, cr, uid, args, offset=0, limit=None, order=None,
             context=None, count=False):
@@ -64,7 +77,7 @@ class ir_attachment(osv.osv):
         return super(ir_attachment, self).read(cr, uid, ids, fields_to_read, context, load)
 
     def write(self, cr, uid, ids, vals, context=None):
-        self.check(cr, uid, ids, 'write', context=context)
+        self.check(cr, uid, ids, 'write', context=context, values=vals)
         return super(ir_attachment, self).write(cr, uid, ids, vals, context)
 
     def copy(self, cr, uid, id, default=None, context=None):
@@ -76,8 +89,7 @@ class ir_attachment(osv.osv):
         return super(ir_attachment, self).unlink(cr, uid, ids, context)
 
     def create(self, cr, uid, values, context=None):
-        if 'res_model' in values and values['res_model'] != '':
-            self.pool.get('ir.model.access').check(cr, uid, values['res_model'], 'create', context=context)
+        self.check(cr, uid, [], mode='create', context=context, values=values)
         return super(ir_attachment, self).create(cr, uid, values, context)
 
     def action_get(self, cr, uid, context=None):
@@ -94,7 +106,7 @@ class ir_attachment(osv.osv):
             if model_object and res_id:
                 model_pool = self.pool.get(model_object)
                 res = model_pool.name_get(cr,uid,[res_id],context)
-                data[attachment.id] = res[0][1]
+                data[attachment.id] = (res and res[0][1]) or False
             else:
                  data[attachment.id] = False
         return data
@@ -105,8 +117,8 @@ class ir_attachment(osv.osv):
         'datas': fields.binary('Data'),
         'datas_fname': fields.char('Filename',size=256),
         'description': fields.text('Description'),
-        'res_name': fields.function(_name_get_resname, type='char', 
-                string='Resource Name', method=True),
+        'res_name': fields.function(_name_get_resname, type='char', size=128,
+                string='Resource Name', method=True, store=True),
         'res_model': fields.char('Resource Object',size=64, readonly=True,
                 help="The database object this attachment will be attached to"),
         'res_id': fields.integer('Resource ID', readonly=True,
@@ -114,16 +126,25 @@ class ir_attachment(osv.osv):
         'url': fields.char('Url', size=512, oldname="link"),
         'type': fields.selection(
                 [ ('url','URL'), ('binary','Binary'), ],
-                'Type', help="Binary File or external URL", required=True),
+                'Type', help="Binary File or external URL", required=True, change_default=True),
 
         'create_date': fields.datetime('Date Created', readonly=True),
-        'create_uid':  fields.many2one('res.users', 'Creator', readonly=True),
+        'create_uid':  fields.many2one('res.users', 'Owner', readonly=True),
+        'company_id': fields.many2one('res.company', 'Company', change_default=True),
     }
     
     _defaults = {
         'type': 'binary',
+        'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.attachment', context=c),
     }
 
+    def _auto_init(self, cr, context=None):
+        super(ir_attachment, self)._auto_init(cr, context)
+        cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('ir_attachment_res_idx',))
+        if not cr.fetchone():
+            cr.execute('CREATE INDEX ir_attachment_res_idx ON ir_attachment (res_model, res_id)')
+            cr.commit()
+
 ir_attachment()