From a5324c4bed220125f88acbcfebeaf012a5d17f24 Mon Sep 17 00:00:00 2001 From: Dennis Sluijk Date: Thu, 8 Mar 2018 11:45:26 +0100 Subject: [PATCH] [11.0][ADD] easy_switch_user (#6) * [ADD] easy_switch_user --- easy_switch_user/README.rst | 55 +++++++ easy_switch_user/__init__.py | 4 + easy_switch_user/__manifest__.py | 23 +++ easy_switch_user/controllers/__init__.py | 4 + easy_switch_user/controllers/main.py | 14 ++ easy_switch_user/static/src/js/switch_user.js | 153 ++++++++++++++++++ .../static/src/xml/switch_user.xml | 36 +++++ easy_switch_user/templates/assets.xml | 11 ++ easy_switch_user/tests/__init__.py | 4 + easy_switch_user/tests/test_controller.py | 30 ++++ 10 files changed, 334 insertions(+) create mode 100644 easy_switch_user/README.rst create mode 100644 easy_switch_user/__init__.py create mode 100644 easy_switch_user/__manifest__.py create mode 100644 easy_switch_user/controllers/__init__.py create mode 100644 easy_switch_user/controllers/main.py create mode 100644 easy_switch_user/static/src/js/switch_user.js create mode 100644 easy_switch_user/static/src/xml/switch_user.xml create mode 100644 easy_switch_user/templates/assets.xml create mode 100644 easy_switch_user/tests/__init__.py create mode 100644 easy_switch_user/tests/test_controller.py diff --git a/easy_switch_user/README.rst b/easy_switch_user/README.rst new file mode 100644 index 0000000..0117357 --- /dev/null +++ b/easy_switch_user/README.rst @@ -0,0 +1,55 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: https://www.gnu.org/licenses/agpl + :alt: License: AGPL-3 + +================ +Easy Switch User +================ + +This module lets administrators and developers quickly change user to test e.g. access rights. + +Usage +===== + +To use this module, you need to: + +#. Click on the caret in the system tray +#. Select the user you want to switch to +#. Login (only required once) + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/250/11.0 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smash it by providing detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Dennis Sluijk + +Do not contact contributors directly about support or help with technical issues. + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/easy_switch_user/__init__.py b/easy_switch_user/__init__.py new file mode 100644 index 0000000..5c69a9b --- /dev/null +++ b/easy_switch_user/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import controllers diff --git a/easy_switch_user/__manifest__.py b/easy_switch_user/__manifest__.py new file mode 100644 index 0000000..526e902 --- /dev/null +++ b/easy_switch_user/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2018 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Easy Switch User', + 'summary': 'Lets administrators and developers quickly ' + 'change user to test e.g. access rights', + 'category': 'Tools', + 'version': '11.0.1.0.0', + 'author': 'Onestein, Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/server-ux', + 'license': 'AGPL-3', + 'depends': [ + 'web' + ], + 'qweb': [ + 'static/src/xml/switch_user.xml' + ], + 'data': [ + 'templates/assets.xml' + ], + 'installable': True, +} diff --git a/easy_switch_user/controllers/__init__.py b/easy_switch_user/controllers/__init__.py new file mode 100644 index 0000000..ee08f2d --- /dev/null +++ b/easy_switch_user/controllers/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import main diff --git a/easy_switch_user/controllers/main.py b/easy_switch_user/controllers/main.py new file mode 100644 index 0000000..d1a8335 --- /dev/null +++ b/easy_switch_user/controllers/main.py @@ -0,0 +1,14 @@ +# Copyright 2018 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import http +from odoo.http import route + + +class SwitchController(http.Controller): + @route('/easy_switch_user/switch', type='json', auth="none") + def switch(self, login, password): + request = http.request + uid = request.session.authenticate(request.db, login, password) + if uid is False: + raise Exception('Login Failed') diff --git a/easy_switch_user/static/src/js/switch_user.js b/easy_switch_user/static/src/js/switch_user.js new file mode 100644 index 0000000..a8b3d08 --- /dev/null +++ b/easy_switch_user/static/src/js/switch_user.js @@ -0,0 +1,153 @@ +/* Copyright 2018 Onestein + * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ + +odoo.define('easy_switch_user', function(require) { + var Widget = require('web.Widget'); + var SystrayMenu = require('web.SystrayMenu'); + var UserMenu = require('web.UserMenu'); + var session = require('web.session'); + var Dialog = require('web.Dialog'); + var core = require('web.core'); + var ajax = require('web.ajax'); + var qweb = core.qweb; + var _t = core._t; + + var SwitchUserMenu = Widget.extend({ + template: 'SwitchUserMenu', + events: { + 'click .dropdown-menu li a[data-user-login]': 'user_selected' + }, + start: function() { + var res = this._super.apply(this, arguments); + this.loadUsers().then(this.populate.bind(this)); + return res; + }, + loadUsers: function() { + return this._rpc({ + model: 'res.users', + method: 'search_read', + order: 'name asc' + }); + }, + populate: function(users) { + var stored = this.get_stored_passwords(); + var users_stored = []; + var users_not_stored = []; + for(var i in users) { + if(users[i].login in stored) { + users_stored.push(users[i]); + } else { + users_not_stored.push(users[i]); + } + } + + this.$('.dropdown-menu').html(''); + this.populate_users(users_stored); + if(users_stored.length > 0) { + this.$('.dropdown-menu').append('
  • '); + } + this.populate_users(users_not_stored); + }, + populate_users: function(users) { + var self = this; + _.each(users, function(user) { + var inside = session.uid === user.id + ? '' + user.name + ' (' + user.login + ')' + : user.name + ' (' + user.login + ')'; + self.$('.dropdown-menu').append( + '
  • ' + inside + '
  • ' + ); + }); + }, + get_stored_passwords: function() { + var val = sessionStorage.getItem('easy_switch_user'); + if (!val) { + return {}; + } + return JSON.parse(val); + }, + store_password: function(login, password) { + var store = {}; + var val = sessionStorage.getItem('easy_switch_user'); + if (val) { + store = JSON.parse(val); + } + store[login] = password; + sessionStorage.setItem('easy_switch_user', JSON.stringify(store)); + }, + user_selected: function(e) { + var self = this; + var user_login = $(e.currentTarget).attr('data-user-login'); + var passwords = this.get_stored_passwords(); + if (user_login in passwords) { + this.switch_user(user_login, passwords[user_login]); + } else { + var dialog = new SwitchUserLoginDialog(this, user_login); + dialog.on('login', this, function(result) { + dialog.hideError(); + self.switch_user(user_login, result.password, result.store).fail(function() { + dialog.showError(); + }); + }); + dialog.open(); + } + }, + switch_user: function(login, password, store) { + if (typeof(store) === 'undefined') { + store = false; + } + var self = this; + return ajax.jsonRpc('/easy_switch_user/switch', 'call', { + login: login, + password: password + }).then(function() { + if(store) { + self.store_password(login, password); + } + window.location.reload(); + }); + } + }); + + SystrayMenu.Items.push(SwitchUserMenu); + + UserMenu.include({ + do_action: function(action, options) { + var def = this._super(action, options); + if (action == 'logout') { + sessionStorage.removeItem('easy_switch_user'); + } + return def; + } + }); + + var SwitchUserLoginDialog = Dialog.extend({ + init: function(parent, user_login) { + this._super(parent, { + title: _t('Switch User'), + $content: $(qweb.render('SwitchUserLoginDialog', {'login': user_login})), + buttons: [ + { text: _t("Login"), classes: 'btn-primary', click: this.login }, + { text: _t("Cancel"), close: true } + ] + }); + }, + login: function() { + this.trigger('login', { + 'password': this.$('input[type="password"]').val(), + 'store': this.$('input[type="checkbox"]').is(':checked') + }); + }, + showError: function() { + this.$('.alert-danger').removeClass('hidden'); + }, + hideError: function() { + this.$('.alert-danger').addClass('hidden'); + } + }); + + return { + Menu: SwitchUserMenu, + Dialog: SwitchUserLoginDialog + }; +}); diff --git a/easy_switch_user/static/src/xml/switch_user.xml b/easy_switch_user/static/src/xml/switch_user.xml new file mode 100644 index 0000000..72b496a --- /dev/null +++ b/easy_switch_user/static/src/xml/switch_user.xml @@ -0,0 +1,36 @@ + + + + diff --git a/easy_switch_user/templates/assets.xml b/easy_switch_user/templates/assets.xml new file mode 100644 index 0000000..166344d --- /dev/null +++ b/easy_switch_user/templates/assets.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/easy_switch_user/tests/__init__.py b/easy_switch_user/tests/__init__.py new file mode 100644 index 0000000..63c4f95 --- /dev/null +++ b/easy_switch_user/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_controller diff --git a/easy_switch_user/tests/test_controller.py b/easy_switch_user/tests/test_controller.py new file mode 100644 index 0000000..8512a7d --- /dev/null +++ b/easy_switch_user/tests/test_controller.py @@ -0,0 +1,30 @@ +# Copyright 2018 Onestein +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import http +from odoo.tests.common import TransactionCase +from odoo.addons.easy_switch_user.controllers.main import SwitchController + + +class FakeRequest(object): + def __init__(self, env): + self.db = env.cr.dbname + self.session = FakeSession() + + +class FakeSession(object): + def authenticate(self, db, login, password): + return False + + +class TestController(TransactionCase): + def setUp(self): + super(TestController, self).setUp() + self.ctrl = SwitchController() + + def test_switch(self): + old_request = http.request + http.request = FakeRequest(self.env) + with self.assertRaises(Exception): + self.ctrl.switch('unknown_user', '1234567890') + http.request = old_request