[MERGE] forward port of branch saas-2 up to revid 5021 chs@openerp.com-20140318105837...
[odoo/odoo.git] / openerp / addons / base / res / res_users.py
index 00000b2..1668cbd 100644 (file)
@@ -3,7 +3,7 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-#    Copyright (C) 2010-2013 OpenERP s.a. (<http://openerp.com>).
+#    Copyright (C) 2010-2014 OpenERP s.a. (<http://openerp.com>).
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -34,7 +34,11 @@ from openerp.tools.translate import _
 
 _logger = logging.getLogger(__name__)
 
-class groups(osv.osv):
+#----------------------------------------------------------
+# Basic res.groups and res.users
+#----------------------------------------------------------
+
+class res_groups(osv.osv):
     _name = "res.groups"
     _description = "Access Groups"
     _rec_name = 'full_name'
@@ -81,29 +85,27 @@ class groups(osv.osv):
     def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
         # add explicit ordering if search is sorted on full_name
         if order and order.startswith('full_name'):
-            ids = super(groups, self).search(cr, uid, args, context=context)
+            ids = super(res_groups, self).search(cr, uid, args, context=context)
             gs = self.browse(cr, uid, ids, context)
             gs.sort(key=lambda g: g.full_name, reverse=order.endswith('DESC'))
             gs = gs[offset:offset+limit] if limit else gs[offset:]
             return map(int, gs)
-        return super(groups, self).search(cr, uid, args, offset, limit, order, context, count)
+        return super(res_groups, self).search(cr, uid, args, offset, limit, order, context, count)
 
     def copy(self, cr, uid, id, default=None, context=None):
         group_name = self.read(cr, uid, [id], ['name'])[0]['name']
         default.update({'name': _('%s (copy)')%group_name})
-        return super(groups, self).copy(cr, uid, id, default, context)
+        return super(res_groups, self).copy(cr, uid, id, default, context)
 
     def write(self, cr, uid, ids, vals, context=None):
         if 'name' in vals:
             if vals['name'].startswith('-'):
                 raise osv.except_osv(_('Error'),
                         _('The name of the group can not start with "-"'))
-        res = super(groups, self).write(cr, uid, ids, vals, context=context)
+        res = super(res_groups, self).write(cr, uid, ids, vals, context=context)
         self.pool['ir.model.access'].call_cache_clearing_methods(cr)
         return res
 
-groups()
-
 class res_users(osv.osv):
     """ User class. A res.users record models an OpenERP user and is different
         from an employee.
@@ -171,13 +173,6 @@ class res_users(osv.osv):
             return {'value': {'email': login}}
         return {}
 
-    def on_change_company_id(self, cr, uid, ids, company_id):
-        return {'warning' : {
-                    'title': _("Company Switch Warning"),
-                    'message': _("Please keep in mind that documents currently displayed may not be relevant after switching to another company. If you have unsaved changes, please make sure to save and close all forms before switching to a different company. (You can click on Cancel in the User Preferences now)"),
-                }
-        }
-
     def onchange_state(self, cr, uid, ids, state_id, context=None):
         partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)]
         return self.pool.get('res.partner').onchange_state(cr, uid, partner_ids, state_id, context=context)
@@ -518,12 +513,13 @@ class res_users(osv.osv):
                    (uid, module, ext_id))
         return bool(cr.fetchone())
 
-
-#
-# Extension of res.groups and res.users with a relation for "implied" or
-# "inherited" groups.  Once a user belongs to a group, it automatically belongs
-# to the implied groups (transitively).
+#----------------------------------------------------------
+# Implied groups
 #
+# Extension of res.groups and res.users with a relation for "implied"
+# or "inherited" groups.  Once a user belongs to a group, it
+# automatically belongs to the implied groups (transitively).
+#----------------------------------------------------------
 
 class cset(object):
     """ A cset (constrained set) is a set of elements that may be constrained to
@@ -553,7 +549,6 @@ def concat(ls):
     return res
 
 
-
 class groups_implied(osv.osv):
     _inherit = 'res.groups'
 
@@ -606,6 +601,7 @@ class users_implied(osv.osv):
         if groups:
             # delegate addition of groups to add implied groups
             self.write(cr, uid, [user_id], {'groups_id': groups}, context)
+            self.pool['ir.ui.view'].clear_cache()
         return user_id
 
     def write(self, cr, uid, ids, values, context=None):
@@ -618,8 +614,11 @@ class users_implied(osv.osv):
                 gs = set(concat([g.trans_implied_ids for g in user.groups_id]))
                 vals = {'groups_id': [(4, g.id) for g in gs]}
                 super(users_implied, self).write(cr, uid, [user.id], vals, context)
+            self.pool['ir.ui.view'].clear_cache()
         return res
 
+#----------------------------------------------------------
+# Vitrual checkbox and selection for res.user form view
 #
 # Extension of res.groups and res.users for the special groups view in the users
 # form.  This extension presents groups with selection and boolean widgets:
@@ -640,6 +639,7 @@ class users_implied(osv.osv):
 #       any of ID1, ..., IDk is in 'groups_id'
 # - selection field 'sel_groups_ID1_..._IDk' is ID iff
 #       ID is in 'groups_id' and ID is maximal in the set {ID1, ..., IDk}
+#----------------------------------------------------------
 
 def name_boolean_group(id): return 'in_group_' + str(id)
 def name_boolean_groups(ids): return 'in_groups_' + '_'.join(map(str, ids))
@@ -663,7 +663,6 @@ def partition(f, xs):
     return yes, nos
 
 
-
 class groups_view(osv.osv):
     _inherit = 'res.groups'
 
@@ -685,8 +684,10 @@ class groups_view(osv.osv):
     def update_user_groups_view(self, cr, uid, context=None):
         # the view with id 'base.user_groups_view' inherits the user form view,
         # and introduces the reified group fields
-        view = self.get_user_groups_view(cr, uid, context)
-        if view:
+        # we have to try-catch this, because at first init the view does not exist
+        # but we are already creating some basic groups
+        view = self.pool['ir.model.data'].xmlid_to_object(cr, SUPERUSER_ID, 'base.user_groups_view', context=context)
+        if view and view.exists() and view._table_name == 'ir.ui.view':
             xml1, xml2 = [], []
             xml1.append(E.separator(string=_('Application'), colspan="4"))
             for app, kind, gs in self.get_groups_by_application(cr, uid, context):
@@ -711,14 +712,6 @@ class groups_view(osv.osv):
             view.write({'arch': xml_content})
         return True
 
-    def get_user_groups_view(self, cr, uid, context=None):
-        try:
-            view = self.pool['ir.model.data'].get_object(cr, SUPERUSER_ID, 'base', 'user_groups_view', context)
-            assert view and view._table_name == 'ir.ui.view'
-        except Exception:
-            view = False
-        return view
-
     def get_application_groups(self, cr, uid, domain=None, context=None):
         return self.search(cr, uid, domain or [])
 
@@ -877,4 +870,73 @@ class users_view(osv.osv):
                     }
         return res
 
+#----------------------------------------------------------
+# change password wizard
+#----------------------------------------------------------
+
+class change_password_wizard(osv.TransientModel):
+    """
+        A wizard to manage the change of users' passwords
+    """
+
+    _name = "change.password.wizard"
+    _description = "Change Password Wizard"
+    _columns = {
+        'user_ids': fields.one2many('change.password.user', 'wizard_id', string='Users'),
+    }
+
+    def default_get(self, cr, uid, fields, context=None):
+        if context == None:
+            context = {}
+        user_ids = context.get('active_ids', [])
+        wiz_id = context.get('active_id', None)
+        res = []
+        users = self.pool.get('res.users').browse(cr, uid, user_ids, context=context)
+        for user in users:
+            res.append((0, 0, {
+                'wizard_id': wiz_id,
+                'user_id': user.id,
+                'user_login': user.login,
+            }))
+        return {'user_ids': res}
+
+    def change_password_button(self, cr, uid, id, context=None):
+        wizard = self.browse(cr, uid, id, context=context)[0]
+        need_reload = any(uid == user.user_id.id for user in wizard.user_ids)
+        line_ids = [user.id for user in wizard.user_ids]
+
+        self.pool.get('change.password.user').change_password_button(cr, uid, line_ids, context=context)
+        # don't keep temporary password copies in the database longer than necessary
+        self.pool.get('change.password.user').write(cr, uid, line_ids, {'new_passwd': False}, context=context)
+
+        if need_reload:
+            return {
+                'type': 'ir.actions.client',
+                'tag': 'reload'
+            }
+
+        return {'type': 'ir.actions.act_window_close'}
+
+class change_password_user(osv.TransientModel):
+    """
+        A model to configure users in the change password wizard
+    """
+
+    _name = 'change.password.user'
+    _description = 'Change Password Wizard User'
+    _columns = {
+        'wizard_id': fields.many2one('change.password.wizard', string='Wizard', required=True),
+        'user_id': fields.many2one('res.users', string='User', required=True),
+        'user_login': fields.char('User Login', readonly=True),
+        'new_passwd': fields.char('New Password'),
+    }
+    _defaults = {
+        'new_passwd': '',
+    }
+
+    def change_password_button(self, cr, uid, ids, context=None):
+        for user in self.browse(cr, uid, ids, context=context):
+            self.pool.get('res.users').write(cr, uid, user.user_id.id, {'password': user.new_passwd})
+
+
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: