Set of label improvements to Open ERP Server.
[odoo/odoo.git] / bin / addons / base / ir / ir_model.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 from osv import fields,osv
24 import ir, re
25 import netsvc
26 from osv.orm import except_orm, browse_record
27
28 import time
29 import tools
30 from tools import config
31 import pooler
32
33 def _get_fields_type(self, cr, uid, context=None):
34     cr.execute('select distinct ttype,ttype from ir_model_fields')
35     return cr.fetchall()
36
37 class ir_model(osv.osv):
38     _name = 'ir.model'
39     _description = "Objects"
40     _rec_name = 'name'
41     _columns = {
42         'name': fields.char('Object Name', size=64, translate=True, required=True),
43         'model': fields.char('Object Name', size=64, required=True, select=1),
44         'info': fields.text('Information'),
45         'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True),
46         'state': fields.selection([('manual','Custom Object'),('base','Base Object')],'Manually Created',readonly=True),
47         'access_ids': fields.one2many('ir.model.access', 'model_id', 'Access'),
48     }
49     _defaults = {
50         'model': lambda *a: 'x_',
51         'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
52     }
53     def _check_model_name(self, cr, uid, ids):
54         for model in self.browse(cr, uid, ids):
55             if model.state=='manual':
56                 if not model.model.startswith('x_'):
57                     return False
58             if not re.match('^[a-z_A-Z0-9.]+$',model.model):
59                 return False
60         return True
61
62     _constraints = [
63         (_check_model_name, 'The Object name must start with x_ and not contain any special character !', ['model']),
64     ]
65     def unlink(self, cr, user, ids, context=None):
66         for model in self.browse(cr, user, ids, context):
67             if model.state <> 'manual':
68                 raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(model.name,))
69         res = super(ir_model, self).unlink(cr, user, ids, context)
70         pooler.restart_pool(cr.dbname)
71         return res
72
73     def create(self, cr, user, vals, context=None):
74         if context and context.get('manual',False):
75             vals['state']='manual'
76         res = super(ir_model,self).create(cr, user, vals, context)
77         if vals.get('state','base')=='manual':
78             self.instanciate(cr, user, vals['model'], context)
79             self.pool.get(vals['model']).__init__(self.pool, cr)
80             self.pool.get(vals['model'])._auto_init(cr,{})
81             #pooler.restart_pool(cr.dbname)
82         return res
83
84     def instanciate(self, cr, user, model, context={}):
85         class x_custom_model(osv.osv):
86             pass
87         x_custom_model._name = model
88         x_custom_model._module = False
89         x_custom_model.createInstance(self.pool, '', cr)
90         x_custom_model._rec_name = 'x_name'
91 ir_model()
92
93
94 class ir_model_grid(osv.osv):
95     _name = 'ir.model.grid'
96     _table = 'ir_model'
97     _inherit = 'ir.model'
98     _description = "Objects Security Grid"
99     #_rec_name = 'name'
100     #_columns = {
101     #    'name': fields.char('Object', size=64),
102     #    'model': fields.char('Object Name', size=64),
103     #}
104
105     def create(self, cr, uid, vals, context=None):
106         raise osv.except_osv('Error !', 'You cannot add an entry to this view !')
107
108     def unlink(self, *args, **argv):
109         raise osv.except_osv('Error !', 'You cannot delete an entry of this view !')
110
111     def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
112         result = super(osv.osv, self).read(cr, uid, ids, fields, context, load)
113         allgr = self.pool.get('res.groups').search(cr, uid, [], context=context)
114         acc_obj = self.pool.get('ir.model.access')
115         
116         if not isinstance(result,list):
117             result=[result]
118             
119         for res in result:
120             rules = acc_obj.search(cr, uid, [('model_id', '=', res['id'])])
121             rules_br = acc_obj.browse(cr, uid, rules, context=context)
122             for g in allgr:
123                 res['group_'+str(g)] = ''
124             for rule in rules_br:
125                 perm_list = []
126                 if rule.perm_read:
127                     perm_list.append('r')
128                 if rule.perm_write:
129                     perm_list.append('w')
130                 if rule.perm_create:
131                     perm_list.append('c')
132                 if rule.perm_unlink:
133                     perm_list.append('u')
134                 perms = ",".join(perm_list)
135                 if rule.group_id:
136                     res['group_%d'%rule.group_id.id] = perms
137                 else:
138                     res['group_0'] = perms
139         return result
140
141     #
142     # This function do not write fields from ir.model because
143     # access rights may be different for managing models and
144     # access rights
145     #
146     def write(self, cr, uid, ids, vals, context=None):
147         vals_new = vals.copy()
148         acc_obj = self.pool.get('ir.model.access')
149         for grid in self.browse(cr, uid, ids, context=context):
150             model_id = grid.id
151             perms_rel = ['read','write','create','unlink']
152             for val in vals:
153                 if not val[:6]=='group_':
154                     continue
155                 group_id = int(val[6:]) or False
156                 rules = acc_obj.search(cr, uid, [('model_id', '=', model_id),('group_id', '=', group_id)])
157                 if not rules:
158                     rules = [acc_obj.create(cr, uid, {
159                         'name': grid.name,
160                         'model_id':model_id,
161                         'group_id':group_id
162                     }) ]
163                 vals2 = dict(map(lambda x: ('perm_'+x, x[0] in (vals[val] or '')), perms_rel))
164                 acc_obj.write(cr, uid, rules, vals2, context=context)
165         return True
166
167     def fields_get(self, cr, uid, fields=None, context=None, read_access=True):
168         result = super(ir_model_grid, self).fields_get(cr, uid, fields, context)
169         groups = self.pool.get('res.groups').search(cr, uid, [])
170         groups_br = self.pool.get('res.groups').browse(cr, uid, groups)
171         result['group_0'] = {'string': 'All Users','type': 'char','size': 7}
172         for group in groups_br:
173             result['group_%d'%group.id] = {'string': '%s'%group.name,'type': 'char','size': 7}
174         return result
175
176     def fields_view_get(self, cr, uid, view_id=None, view_type='form', context={}, toolbar=False):
177         result = super(ir_model_grid, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar)
178         groups = self.pool.get('res.groups').search(cr, uid, [])
179         groups_br = self.pool.get('res.groups').browse(cr, uid, groups)
180         cols = ['model', 'name']
181         xml = '''<?xml version="1.0"?>
182 <%s editable="bottom">
183     <field name="name" select="1" readonly="1" required="1"/>
184     <field name="model" select="1" readonly="1" required="1"/>
185     <field name="group_0"/>
186     ''' % (view_type,)
187         for group in groups_br:
188             xml += '''<field name="group_%d"/>''' % (group.id, )
189         xml += '''</%s>''' % (view_type,)
190         result['arch'] = xml
191         result['fields'] = self.fields_get(cr, uid, cols, context)
192         return result
193 ir_model_grid()
194
195 class ir_model_fields(osv.osv):
196     _name = 'ir.model.fields'
197     _description = "Fields"
198     _columns = {
199         'name': fields.char('Name', required=True, size=64, select=1),
200         'model': fields.char('Object Name', size=64, required=True),
201         'relation': fields.char('Object Relation', size=64),
202         'relation_field': fields.char('Relation Field', size=64),
203         'model_id': fields.many2one('ir.model', 'Object ID', required=True, select=True, ondelete='cascade'),
204         'field_description': fields.char('Field Label', required=True, size=256),
205         'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True),
206         'selection': fields.char('Field Selection',size=128),
207         'required': fields.boolean('Required'),
208         'readonly': fields.boolean('Readonly'),
209         'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search')],'Searchable', required=True),
210         'translate': fields.boolean('Translate'),
211         'size': fields.integer('Size'),
212         'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Manually Created', required=True, readonly=True),
213         'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'),
214         'domain': fields.char('Domain', size=256),
215         'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
216         'view_load': fields.boolean('View Auto-Load'),
217     }
218     _rec_name='field_description'
219     _defaults = {
220         'view_load': lambda *a: 0,
221         'selection': lambda *a: "[]",
222         'domain': lambda *a: "[]",
223         'name': lambda *a: 'x_',
224         'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
225         'on_delete': lambda *a: 'set null',
226         'select_level': lambda *a: '0',
227         'size': lambda *a: 64,
228         'field_description': lambda *a: '',
229     }
230     _order = "id"
231     def unlink(self, cr, user, ids, context=None):
232         for field in self.browse(cr, user, ids, context):
233             if field.state <> 'manual':
234                 raise except_orm(_('Error'), _("You can not remove the field '%s' !") %(field.name,))
235         #
236         # MAY BE ADD A ALTER TABLE DROP ?
237         #
238         return super(ir_model_fields, self).unlink(cr, user, ids, context)
239
240     def create(self, cr, user, vals, context=None):
241         if 'model_id' in vals:
242             model_data = self.pool.get('ir.model').browse(cr, user, vals['model_id'])
243             vals['model'] = model_data.model
244         if context and context.get('manual',False):
245             vals['state'] = 'manual'
246         res = super(ir_model_fields,self).create(cr, user, vals, context)
247         if vals.get('state','base') == 'manual':
248             if not vals['name'].startswith('x_'):
249                 raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !"))
250             if self.pool.get(vals['model']):
251                 self.pool.get(vals['model']).__init__(self.pool, cr)
252                 self.pool.get(vals['model'])._auto_init(cr, {})
253         return res
254 ir_model_fields()
255
256 class ir_model_access(osv.osv):
257     _name = 'ir.model.access'
258     _columns = {
259         'name': fields.char('Name', size=64, required=True),
260         'model_id': fields.many2one('ir.model', 'Object', required=True),
261         'group_id': fields.many2one('res.groups', 'Group'),
262         'perm_read': fields.boolean('Read Access'),
263         'perm_write': fields.boolean('Write Access'),
264         'perm_create': fields.boolean('Create Access'),
265         'perm_unlink': fields.boolean('Delete Permission'),
266     }
267
268     def check_groups(self, cr, uid, group):
269         res = False
270         grouparr  = group.split('.')
271         if not grouparr:
272             return False
273
274         cr.execute("select 1 from res_groups_users_rel where uid=%s and gid in(select res_id from ir_model_data where module=%s and name=%s)", (uid, grouparr[0], grouparr[1],))
275         return bool(cr.fetchone())
276
277     def check_group(self, cr, uid, model, mode, group_ids):
278         """ Check if a specific group has the access mode to the specified model"""
279         assert mode in ['read','write','create','unlink'], 'Invalid access mode'
280
281         if isinstance(model, browse_record):
282             assert model._table_name == 'ir.model', 'Invalid model object'
283             model_name = model.name
284         else:
285             model_name = model
286
287         if isinstance(group_ids, (int, long)):
288             group_ids = [group_ids]
289         for group_id in group_ids:
290             cr.execute("SELECT perm_" + mode + " "
291                    "  FROM ir_model_access a "
292                    "  JOIN ir_model m ON (m.id = a.model_id) "
293                    " WHERE m.model = %s AND a.group_id = %s", (model_name, group_id)
294                    )
295             r = cr.fetchone()
296             if r is None:
297                 cr.execute("SELECT perm_" + mode + " "
298                        "  FROM ir_model_access a "
299                        "  JOIN ir_model m ON (m.id = a.model_id) "
300                        " WHERE m.model = %s AND a.group_id IS NULL", (model_name, )
301                        )
302                 r = cr.fetchone()
303
304             access = bool(r and r[0])
305             if access:
306                 return True
307         # pass no groups -> no access
308         return False
309
310     def check(self, cr, uid, model, mode='read', raise_exception=True):
311         if uid==1:
312             # User root have all accesses
313             # TODO: exclude xml-rpc requests
314             return True
315
316         assert mode in ['read','write','create','unlink'], 'Invalid access mode'
317
318         if isinstance(model, browse_record):
319             assert model._table_name == 'ir.model', 'Invalid model object'
320             model_name = model.name
321         else:
322             model_name = model
323
324         # We check if a specific rule exists
325         cr.execute('SELECT MAX(CASE WHEN perm_' + mode + ' THEN 1 ELSE 0 END) '
326                    '  FROM ir_model_access a '
327                    '  JOIN ir_model m ON (m.id = a.model_id) '
328                    '  JOIN res_groups_users_rel gu ON (gu.gid = a.group_id) '
329                    ' WHERE m.model = %s '
330                    '   AND gu.uid = %s '
331                    , (model_name, uid,)
332                    )
333         r = cr.fetchone()[0]
334
335         if r is None:
336             # there is no specific rule. We check the generic rule
337             cr.execute('SELECT MAX(CASE WHEN perm_' + mode + ' THEN 1 ELSE 0 END) '
338                        '  FROM ir_model_access a '
339                        '  JOIN ir_model m ON (m.id = a.model_id) '
340                        ' WHERE a.group_id IS NULL '
341                        '   AND m.model = %s '
342                        , (model_name,)
343                        )
344             r = cr.fetchone()[0]
345
346         if not r and raise_exception:
347             msgs = {
348                 'read':   _('You can not read this document! (%s)'),
349                 'write':  _('You can not write in this document! (%s)'),
350                 'create': _('You can not create this kind of document! (%s)'),
351                 'unlink': _('You can not delete this document! (%s)'),
352             }
353             raise except_orm(_('AccessError'), msgs[mode] % model_name )
354         return r
355
356     check = tools.cache()(check)
357
358     __cache_clearing_methods = []
359
360     def register_cache_clearing_method(self, model, method):
361         self.__cache_clearing_methods.append((model, method))
362
363     def unregister_cache_clearing_method(self, model, method):
364         try:
365             i = self.__cache_clearing_methods.index((model, method))
366             del self.__cache_clearing_methods[i]
367         except ValueError:
368             pass
369
370     def call_cache_clearing_methods(self):
371         for model, method in self.__cache_clearing_methods:
372             getattr(self.pool.get(model), method)()
373
374     #
375     # Check rights on actions
376     #
377     def write(self, cr, uid, *args, **argv):
378         self.call_cache_clearing_methods()
379         res = super(ir_model_access, self).write(cr, uid, *args, **argv)
380         self.check.clear_cache(cr.dbname)    # clear the cache of check function
381         return res
382
383     def create(self, cr, uid, *args, **argv):
384         self.call_cache_clearing_methods()
385         res = super(ir_model_access, self).create(cr, uid, *args, **argv)
386         self.check.clear_cache(cr.dbname)    # clear the cache of check function
387         return res
388
389     def unlink(self, cr, uid, *args, **argv):
390         self.call_cache_clearing_methods()
391         res = super(ir_model_access, self).unlink(cr, uid, *args, **argv)
392         self.check.clear_cache(cr.dbname)    # clear the cache of check function
393         return res
394
395 ir_model_access()
396
397 class ir_model_data(osv.osv):
398     _name = 'ir.model.data'
399     _columns = {
400         'name': fields.char('XML Identifier', required=True, size=64),
401         'model': fields.char('Object', required=True, size=64),
402         'module': fields.char('Module', required=True, size=64),
403         'res_id': fields.integer('Resource ID'),
404         'noupdate': fields.boolean('Non Updatable'),
405         'date_update': fields.datetime('Update Date'),
406         'date_init': fields.datetime('Init Date')
407     }
408     _defaults = {
409         'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
410         'date_update': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
411         'noupdate': lambda *a: False
412     }
413
414     def __init__(self, pool, cr):
415         osv.osv.__init__(self, pool, cr)
416         self.loads = {}
417         self.doinit = True
418         self.unlink_mark = {}
419
420     def _get_id(self,cr, uid, module, xml_id):
421         ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)])
422         assert len(ids)==1, '%d reference(s) to %s.%s. You should have one and only one !' % (len(ids), module, xml_id)
423         return ids[0]
424     _get_id = tools.cache(skiparg=2)(_get_id)
425
426     def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True):
427         if not xml_id:
428             return False
429         try:
430             id = self.read(cr, uid, [self._get_id(cr, uid, module, xml_id)], ['res_id'])[0]['res_id']
431             self.loads[(module,xml_id)] = (model,id)
432         except:
433             id = False
434         return id
435
436     def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False):
437         warning = True
438         model_obj = self.pool.get(model)
439         context = {}
440         if xml_id and ('.' in xml_id):
441             assert len(xml_id.split('.'))==2, _('"%s" contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id') % (xml_id)
442             warning = False
443             module, xml_id = xml_id.split('.')
444         if (not xml_id) and (not self.doinit):
445             return False
446         action_id = False
447         if xml_id:
448             cr.execute('select id,res_id from ir_model_data where module=%s and name=%s', (module,xml_id))
449             results = cr.fetchall()
450             for action_id2,res_id2 in results:
451                 cr.execute('select id from '+self.pool.get(model)._table+' where id=%s', (res_id2,))
452                 result3 = cr.fetchone()
453                 if not result3:
454                     cr.execute('delete from ir_model_data where id=%s', (action_id2,))
455                 else:
456                     res_id,action_id = res_id2,action_id2
457
458         if action_id and res_id:
459             model_obj.write(cr, uid, [res_id], values)
460             self.write(cr, uid, [action_id], {
461                 'date_update': time.strftime('%Y-%m-%d %H:%M:%S'),
462                 })
463         elif res_id:
464             model_obj.write(cr, uid, [res_id], values)
465             if xml_id:
466                 self.create(cr, uid, {
467                     'name': xml_id,
468                     'model': model,
469                     'module':module,
470                     'res_id':res_id,
471                     'noupdate': noupdate,
472                     })
473                 if model_obj._inherits:
474                     for table in model_obj._inherits:
475                         inherit_id = model_obj.browse(cr, uid,
476                                 res_id)[model_obj._inherits[table]]
477                         self.create(cr, uid, {
478                             'name': xml_id + '_' + table.replace('.', '_'),
479                             'model': table,
480                             'module': module,
481                             'res_id': inherit_id,
482                             'noupdate': noupdate,
483                             })
484         else:
485             if mode=='init' or (mode=='update' and xml_id):
486                 res_id = model_obj.create(cr, uid, values)
487                 if xml_id:
488                     self.create(cr, uid, {
489                         'name': xml_id,
490                         'model': model,
491                         'module': module,
492                         'res_id': res_id,
493                         'noupdate': noupdate
494                         })
495                     if model_obj._inherits:
496                         for table in model_obj._inherits:
497                             inherit_id = model_obj.browse(cr, uid,
498                                     res_id)[model_obj._inherits[table]]
499                             self.create(cr, uid, {
500                                 'name': xml_id + '_' + table.replace('.', '_'),
501                                 'model': table,
502                                 'module': module,
503                                 'res_id': inherit_id,
504                                 'noupdate': noupdate,
505                                 })
506         if xml_id:
507             if res_id:
508                 self.loads[(module, xml_id)] = (model, res_id)
509                 if model_obj._inherits:
510                     for table in model_obj._inherits:
511                         inherit_field = model_obj._inherits[table]
512                         inherit_id = model_obj.read(cr, uid, res_id,
513                                 [inherit_field])[inherit_field]
514                         self.loads[(module, xml_id + '_' + \
515                                 table.replace('.', '_'))] = (table, inherit_id)
516         return res_id
517
518     def _unlink(self, cr, uid, model, ids, direct=False):
519         #self.pool.get(model).unlink(cr, uid, ids)
520         for id in ids:
521             self.unlink_mark[(model, id)]=False
522             cr.execute('delete from ir_model_data where res_id=%s and model=\'%s\'', (id,model))
523         return True
524
525     def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False):
526         obj = self.pool.get('ir.values')
527         if type(models[0])==type([]) or type(models[0])==type(()):
528             model,res_id = models[0]
529         else:
530             res_id=None
531             model = models[0]
532
533         if res_id:
534             where = ' and res_id=%s' % (res_id,)
535         else:
536             where = ' and (res_id is null)'
537
538         if key2:
539             where += ' and key2=\'%s\'' % (key2,)
540         else:
541             where += ' and (key2 is null)'
542
543         cr.execute('select * from ir_values where model=%s and key=%s and name=%s'+where,(model, key, name))
544         res = cr.fetchone()
545         if not res:
546             res = ir.ir_set(cr, uid, key, key2, name, models, value, replace, isobject, meta)
547         elif xml_id:
548             cr.execute('UPDATE ir_values set value=%s WHERE model=%s and key=%s and name=%s'+where,(value, model, key, name))
549         return True
550
551     def _process_end(self, cr, uid, modules):
552         if not modules:
553             return True
554         modules = list(modules)    
555         module_in = ",".join(["%s"] * len(modules))
556         cr.execute('select id,name,model,res_id,module from ir_model_data where module in (' + module_in + ') and noupdate=%s', modules + [False])
557         wkf_todo = []
558         for (id, name, model, res_id,module) in cr.fetchall():
559             if (module,name) not in self.loads:
560                 self.unlink_mark[(model,res_id)] = id
561                 if model=='workflow.activity':
562                     cr.execute('select res_type,res_id from wkf_instance where id in (select inst_id from wkf_workitem where act_id=%s)', (res_id,))
563                     wkf_todo.extend(cr.fetchall())
564                     cr.execute("update wkf_transition set condition='True', role_id=NULL, signal=NULL,act_to=act_from,act_from=%s where act_to=%s", (res_id,res_id))
565                     cr.execute("delete from wkf_transition where act_to=%s", (res_id,))
566
567         for model,id in wkf_todo:
568             wf_service = netsvc.LocalService("workflow")
569             wf_service.trg_write(uid, model, id, cr)
570
571         cr.commit()
572         if not config.get('import_partial', False):
573             for (model,id) in self.unlink_mark.keys():
574                 if self.pool.get(model):
575                     logger = netsvc.Logger()
576                     logger.notifyChannel('init', netsvc.LOG_INFO, 'Deleting %s@%s' % (id, model))
577                     try:
578                         self.pool.get(model).unlink(cr, uid, [id])
579                         if self.unlink_mark[(model,id)]:
580                             self.unlink(cr, uid, [self.unlink_mark[(model,id)]])
581                             cr.execute('DELETE FROM ir_values WHERE value=%s', (model+','+str(id),))
582                         cr.commit()
583                     except:
584                         logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\tThere should be some relation that points to this resource\tYou should manually fix this and restart --update=module' % (id, model))
585         return True
586 ir_model_data()
587
588 class ir_model_config(osv.osv):
589     _name = 'ir.model.config'
590     _columns = {
591         'password': fields.char('Password', size=64),
592         'password_check': fields.char('Confirmation', size=64),
593     }
594
595     def action_cancel(self, cr, uid, ids, context={}):
596         return {
597             'view_type': 'form',
598             "view_mode": 'form',
599             'res_model': 'ir.actions.configuration.wizard',
600             'type': 'ir.actions.act_window',
601             'target':'new',
602         }
603
604     def action_update_pw(self, cr, uid, ids, context={}):
605         res = self.read(cr,uid,ids)[0]
606         root = self.pool.get('res.users').browse(cr, uid, [1])[0]
607         self.unlink(cr, uid, [res['id']])
608         if res['password']!=res['password_check']:
609             raise except_orm(_('Error'), _("Password mismatch !"))
610         elif not res['password']:
611             raise except_orm(_('Error'), _("Password empty !"))
612         self.pool.get('res.users').write(cr, uid, [root.id], {'password':res['password']})
613         return {
614             'view_type': 'form',
615             "view_mode": 'form',
616             'res_model': 'ir.actions.configuration.wizard',
617             'type': 'ir.actions.act_window',
618             'target':'new',
619         }
620 ir_model_config()
621
622 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: