# Copyright 2024 Akretion (https://www.akretion.com). # @author Kévin Roche # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import logging from odoo import _, api, fields, models from odoo.exceptions import UserError from odoo.http import request from odoo.service import security logger = logging.getLogger(__name__) class Users(models.Model): _inherit = "res.users" def _get_partner_name(self, user_id): return self.env["res.users"].browse(user_id).partner_id.name def _is_impersonate_user(self): self.ensure_one() return self.has_group("impersonate_login.group_impersonate_login") def impersonate_login(self): if request: if request.session.impersonate_from_uid: if self.id == request.session.impersonate_from_uid: return self.back_to_origin_login() else: raise UserError(_("You are already Logged as another user.")) if self.id == request.session.uid: raise UserError(_("It's you.")) if ( request.env.user._is_impersonate_user() and request.env.user._is_internal() ): target_uid = self.id request.session.impersonate_from_uid = self._uid request.session.uid = target_uid impersonate_log = ( self.env["impersonate.log"] .sudo() .create( { "user_id": self._uid, "impersonated_partner_id": self.env["res.users"] .browse(target_uid) .partner_id.id, "date_start": fields.datetime.now(), } ) ) request.session.impersonate_log_id = impersonate_log.id logger.info( f"IMPERSONATE: {self._get_partner_name(self._uid)} " f"Login as {self._get_partner_name(self.id)}" ) # invalidate session token cache as we've changed the uid request.env["res.users"].clear_caches() request.session.session_token = security.compute_session_token( request.session, request.env ) # reload the client; open the first available root menu menu = self.env["ir.ui.menu"].search([("parent_id", "=", False)])[:1] return { "type": "ir.actions.client", "tag": "reload", "params": {"menu_id": menu.id}, } @api.model def action_impersonate_login(self): if request: from_uid = request.session.impersonate_from_uid if not from_uid: action = self.env["ir.actions.act_window"]._for_xml_id( "base.action_res_users" ) action["views"] = [[self.env.ref("base.view_users_tree").id, "tree"]] action["domain"] = [ ("id", "!=", self.env.user.id), ("share", "=", False), ] action["target"] = "new" return action @api.model def back_to_origin_login(self): if request: from_uid = request.session.impersonate_from_uid if from_uid: request.session.uid = from_uid self.env["impersonate.log"].sudo().browse( request.session.impersonate_log_id ).write( { "date_end": fields.datetime.now(), } ) # invalidate session token cache as we've changed the uid request.env["res.users"].clear_caches() request.session.impersonate_from_uid = False request.session.impersonate_log_id = False request.session.session_token = security.compute_session_token( request.session, request.env ) logger.info( f"IMPERSONATE: {self._get_partner_name(from_uid)} " f"Logout as {self._get_partner_name(self._uid)}" ) # reload the client; open the first available root menu menu = self.env["ir.ui.menu"].search([("parent_id", "=", False)])[:1] return { "type": "ir.actions.client", "tag": "reload", "params": {"menu_id": menu.id}, }