Manage custom login process

The password is removed from the login window. The login parameters are filled
using asks pop-up until login success. The same login method is used to renew
the session.

issue5521
review23011002
This commit is contained in:
Cédric Krier committed 2016-05-31 12:51:46 +02:00
1 parent 5e7fc37b10
commit 2f065da300
6 files changed
+88 -92

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Manage custom login process
* Add clear icon on Many2One
* Re-position icons on Many2One widget
+46 -22
View File
@@ -1082,31 +1082,25 @@ def process_exception(exception, *args, **kwargs):
elif exception.faultCode.startswith('403'):
from tryton.gui.main import Main
if not PLOCK.acquire(False):
return False
hostname = rpc._HOST
port = rpc._PORT
return
language = CONFIG['client.lang']
func = lambda parameters: rpc.login(
rpc._HOST, rpc._PORT, rpc._DATABASE, rpc._USERNAME, parameters,
language)
try:
while True:
password = ask(_('Password:'), visibility=False)
if password is None:
Main.get_main().sig_quit()
res = rpc.login(rpc._USERNAME, password, hostname, port,
rpc._DATABASE)
if res == -1:
message(_('Connection error!\n'
'Unable to connect to the server!'))
return False
if res < 0:
continue
if args:
try:
return rpc_execute(*args)
except TrytonServerError, exception:
return process_exception(exception, *args,
rpc_execute=rpc_execute)
return True
Login(func)
except TrytonError, exception:
if exception.faultCode == 'QueryCanceled':
Main.get_main().sig_quit()
raise
finally:
PLOCK.release()
if args:
try:
return rpc_execute(*args)
except TrytonServerError, exception:
return process_exception(exception, *args,
rpc_execute=rpc_execute)
elif isinstance(exception, (socket.error, TrytonServerUnavailable)):
warning(str(exception), _('Network Error!'))
return False
@@ -1120,6 +1114,36 @@ def process_exception(exception, *args, **kwargs):
return False
class Login(object):
def __init__(self, func):
parameters = {}
while True:
try:
func(parameters)
except TrytonServerError, exception:
if exception.faultCode.startswith('403'):
parameters.clear()
continue
if exception.faultCode != 'LoginException':
raise
name, message, type = exception.args
value = getattr(self, 'get_%s' % type)(message)
if value is None:
raise TrytonError('QueryCanceled')
parameters[name] = value
continue
else:
return
@classmethod
def get_char(self, message):
return ask(message)
@classmethod
def get_password(self, message):
return ask(message, visibility=False)
def node_attributes(node):
result = {}
attrs = node.attributes
+14 -21
View File
@@ -874,32 +874,25 @@ class Main(object):
self._sig_remove_book(widget,
self.notebook.get_nth_page(self.notebook.get_current_page()))
def sig_login(self, widget=None, res=None):
def sig_login(self, widget=None):
if not self.sig_logout(widget, disconnect=False):
return
if not res:
try:
res = DBLogin().run()
except TrytonError, exception:
if exception.faultCode == 'QueryCanceled':
return False
except TrytonServerError, exception:
common.process_exception(exception)
return
language = CONFIG['client.lang']
host, port, database, username = DBLogin().run()
func = lambda parameters: rpc.login(
host, port, database, username, parameters, language)
try:
log_response = rpc.login(*res)
except TrytonServerError, exception:
common.Login(func)
except Exception, exception:
if (isinstance(exception, TrytonError)
and exception.faultCode == 'QueryCanceled'):
return
if (isinstance(exception, TrytonServerError)
and exception.faultCode.startswith('403')):
return self.sig_login()
common.process_exception(exception)
return
if log_response > 0:
self.get_preferences()
elif log_response == -1:
common.message(_('Connection error!\n'
'Unable to connect to the server!'))
elif log_response == -2:
common.message(_('Connection error!\n'
'Bad username or password!'))
return self.sig_login()
self.get_preferences()
self.favorite_unset()
self.menuitem_favorite.set_sensitive(True)
self.menuitem_user.set_sensitive(True)
+7 -20
View File
@@ -443,19 +443,9 @@ class DBLogin(object):
self.table_main.attach(self.label_database, 0, 1, 5, 6,
xoptions=gtk.FILL)
self.table_main.attach(self.entry_database, 1, 3, 5, 6)
self.entry_password = gtk.Entry()
self.entry_password.set_visibility(False)
self.entry_password.set_activates_default(True)
self.table_main.attach(self.entry_password, 1, 3, 7, 8)
self.entry_login = gtk.Entry()
self.entry_login.set_activates_default(True)
self.table_main.attach(self.entry_login, 1, 3, 6, 7)
label_password = gtk.Label(str=_("Password:"))
label_password.set_justify(gtk.JUSTIFY_RIGHT)
label_password.set_alignment(1, 0.5)
label_password.set_padding(3, 3)
label_password.set_mnemonic_widget(self.entry_password)
self.table_main.attach(label_password, 0, 1, 7, 8, xoptions=gtk.FILL)
label_username = gtk.Label(str=_("User name:"))
label_username.set_alignment(1, 0.5)
label_username.set_padding(3, 3)
@@ -572,10 +562,7 @@ class DBLogin(object):
self.entry_login.set_text(CONFIG['login.login'])
self.dialog.show_all()
if not self.entry_login.get_text():
self.entry_login.grab_focus()
else:
self.entry_password.grab_focus()
self.entry_login.grab_focus()
# Reshow dialog for gtk-quarks
self.dialog.reshow_with_initial_size()
@@ -583,10 +570,10 @@ class DBLogin(object):
# The previous action did not called expand_hostspec
self.expand_hostspec(self.expander)
res, result = None, ('', '', '', '', '')
response, result = None, ('', '', '', '')
while not all(result):
res = self.dialog.run()
if res != gtk.RESPONSE_OK:
response = self.dialog.run()
if response != gtk.RESPONSE_OK:
break
active_profile = self.combo_profile.get_active()
if active_profile != -1:
@@ -610,12 +597,12 @@ class DBLogin(object):
CONFIG['login.db'] = database
CONFIG['login.expanded'] = self.expander.props.expanded
CONFIG['login.login'] = login
result = (self.entry_login.get_text(),
self.entry_password.get_text(), host, port, database)
result = (
host, port, database, self.entry_login.get_text())
self.parent.present()
self.dialog.destroy()
if res != gtk.RESPONSE_OK:
if response != gtk.RESPONSE_OK:
rpc.logout()
raise TrytonError('QueryCanceled')
return result
+11 -12
View File
@@ -6,9 +6,9 @@ import gtk
import copy
from tryton.gui.window.view_form.screen import Screen
from tryton.config import TRYTON_ICON
import tryton.common as common
from tryton.common import RPCExecute, RPCException
from tryton.common import RPCExecute, RPCException, process_exception, Login
from tryton.gui.window.nomodal import NoModal
from tryton.exceptions import TrytonError
import tryton.rpc as rpc
_ = gettext.gettext
@@ -84,17 +84,16 @@ class Preference(NoModal):
if response_id == gtk.RESPONSE_OK:
if self.screen.current_record.validate():
vals = copy.copy(self.screen.get())
if 'password' in vals:
password = common.ask(_('Current Password:'),
visibility=False)
if not password:
return
else:
password = False
context = rpc.CONTEXT.copy()
func = lambda parameters: rpc.execute(
'model', 'res.user', 'set_preferences', vals, parameters,
context)
try:
RPCExecute('model', 'res.user', 'set_preferences',
vals, password)
except RPCException:
Login(func)
except TrytonError, exception:
if exception.faultCode == 'QueryCanceled':
return
process_exception(exception)
return
self.parent.present()
self.destroy()
+9 -17
View File
@@ -69,27 +69,20 @@ def server_version(host, port):
raise
def login(username, password, host, port, database):
def login(host, port, database, username, parameters, language=None):
global CONNECTION, _USER, _USERNAME, _HOST, _PORT, _DATABASE
global _VIEW_CACHE, _TOOLBAR_CACHE, _KEYWORD_CACHE
_VIEW_CACHE = {}
_TOOLBAR_CACHE = {}
_KEYWORD_CACHE = {}
try:
if CONNECTION is not None:
CONNECTION.close()
CONNECTION = ServerPool(host, port, database)
logging.getLogger(__name__).info('common.db.login(%s, %s)' %
(username, 'x' * 10))
with CONNECTION() as conn:
result = conn.common.db.login(username, password)
logging.getLogger(__name__).debug(repr(result))
except socket.error:
_USER = None
return -1
if not result:
_USER = None
return -2
if CONNECTION is not None:
CONNECTION.close()
CONNECTION = ServerPool(host, port, database)
logging.getLogger(__name__).info('common.db.login(%s, %s, %s)'
% (username, 'x' * 10, language))
with CONNECTION() as conn:
result = conn.common.db.login(username, parameters, language)
logging.getLogger(__name__).debug(repr(result))
_USER = result[0]
_USERNAME = username
session = ':'.join(map(str, [username] + result))
@@ -98,7 +91,6 @@ def login(username, password, host, port, database):
_PORT = port
_DATABASE = database
IPCServer(host, port, database).run()
return 1
def logout():