From 4f377825c79c70aa0b1b66b6cf7d46909a292e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 26 Nov 2019 22:16:00 +0100 Subject: [PATCH] Add __href__ and is_secure, host and http_host to url module This ease the composition of URL pointing to Tryton route. issue8767 review264461005 --- CHANGELOG | 2 + trytond/res/email_reset_password.html | 4 +- trytond/res/user.py | 5 ++- trytond/tests/test_mixins.py | 28 ++++++++++++- trytond/url.py | 57 ++++++++++++++++++++++++--- 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e64487e9ff..032506905c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Add is_secure, host and http_host to url module +* Add __href__ to URLMixin * Add validate attribute to wizard's Button * Return 400 instead of 500 for Tryton exception * Fill the reverse field in the One2Many setter diff --git a/trytond/res/email_reset_password.html b/trytond/res/email_reset_password.html index ec48b3e81d..f1a3ffb360 100644 --- a/trytond/res/email_reset_password.html +++ b/trytond/res/email_reset_password.html @@ -10,8 +10,8 @@

The password for your account, ${record.login}, has been reset.
You must set a new one from the user's preferences.
You can connect with this temporary password ${record.password_reset} to

- tryton://${hostname}/${database}
- https://${hostname}/#${database}
+ tryton://${host}/${database}
+ ${http_host}/#${database}

diff --git a/trytond/res/user.py b/trytond/res/user.py index eb7c503668..e39a1f7e6b 100644 --- a/trytond/res/user.py +++ b/trytond/res/user.py @@ -51,7 +51,7 @@ from ..rpc import RPC from ..exceptions import LoginException, RateLimitException from trytond.report import Report, get_email from trytond.sendmail import sendmail_transactional -from trytond.url import HOSTNAME +from trytond.url import host, http_host __all__ = [ 'User', 'LoginAttempt', 'UserAction', 'UserGroup', 'Warning_', @@ -973,7 +973,8 @@ class EmailResetPassword(Report): Lang = pool.get('ir.lang') context = super(EmailResetPassword, cls).get_context(records, data) lang = Lang.get() - context['hostname'] = HOSTNAME + context['host'] = host() + context['http_host'] = http_host() context['database'] = Transaction().database.name context['expire'] = lang.strftime( records[0].password_reset_expire, diff --git a/trytond/tests/test_mixins.py b/trytond/tests/test_mixins.py index abaef90253..eaf891e6bd 100644 --- a/trytond/tests/test_mixins.py +++ b/trytond/tests/test_mixins.py @@ -9,7 +9,7 @@ from trytond.tests.test_tryton import activate_module, with_transaction from trytond.transaction import Transaction from trytond.model import ModelView from trytond.pool import Pool -from trytond.url import HOSTNAME +from trytond.url import http_host, HOSTNAME from .mixin import TestMixin, TestSecondMixin, NotMixin @@ -36,6 +36,21 @@ class UrlTestCase(unittest.TestCase): 'tryton://%s/%s/model/test.urlobject/1' % ( HOSTNAME, urllib.parse.quote(db_name))) + @with_transaction() + def testModelHref(self): + "Test model href" + pool = Pool() + UrlObject = pool.get('test.urlobject') + db_name = Transaction().database.name + + self.assertEqual(UrlObject.__href__, + '%s/#%s/model/test.urlobject' % ( + http_host(), urllib.parse.quote(db_name))) + + self.assertEqual(UrlObject(1).__href__, + '%s/#%s/model/test.urlobject/1' % ( + http_host(), urllib.parse.quote(db_name))) + @with_transaction() def testWizardURL(self): "Test wizard URLs" @@ -47,6 +62,17 @@ class UrlTestCase(unittest.TestCase): 'tryton://%s/%s/wizard/test.test_wizard' % ( HOSTNAME, urllib.parse.quote(db_name))) + @with_transaction() + def testWizardHref(self): + "Test wizard href" + pool = Pool() + UrlWizard = pool.get('test.test_wizard', type='wizard') + db_name = Transaction().database.name + + self.assertEqual(UrlWizard.__href__, + '%s/#%s/wizard/test.test_wizard' % ( + http_host(), urllib.parse.quote(db_name))) + class MixinTestCase(unittest.TestCase): "Test Mixin" diff --git a/trytond/url.py b/trytond/url.py index 7f8c034405..27ef789d2f 100644 --- a/trytond/url.py +++ b/trytond/url.py @@ -8,7 +8,7 @@ import urllib.parse from trytond.config import config from trytond.transaction import Transaction -__all__ = ['URLMixin', 'HOSTNAME'] +__all__ = ['URLMixin', 'is_secure', 'host', 'http_host'] HOSTNAME = (config.get('web', 'hostname') or socket.getfqdn()) @@ -17,7 +17,46 @@ HOSTNAME = '.'.join(encodings.idna.ToASCII(part).decode('ascii') class URLAccessor(object): - __slots__ = () + __slots__ = ('_protocol',) + + def __init__(self, protocol='tryton'): + self._protocol = protocol + + @classmethod + def is_secure(cls): + context = Transaction().context + if context: + request = context.get('_request') + if request: + return request['is_secure'] + return bool(config.get('ssl', 'certificate')) + + @classmethod + def host(cls): + context = Transaction().context + if context: + request = context.get('_request') + if request: + return request['http_host'] + return HOSTNAME + + @classmethod + def http_host(cls): + return urllib.parse.urlunsplit(( + 'http' + ('s' if cls.is_secure() else ''), + cls.host(), '', '', '')) + + @property + def protocol(self): + if self._protocol == 'http': + return 'http' + ('s' if self.is_secure() else '') + return self._protocol + + @property + def separator(self): + if self._protocol == 'http': + return '#' + return '' def __get__(self, inst, cls): from trytond.model import Model @@ -37,12 +76,20 @@ class URLAccessor(object): url_part['name'] = cls.__name__ url_part['database'] = Transaction().database.name - local_part = urllib.parse.quote('%(database)s/%(type)s/%(name)s' % url_part) + local_part = urllib.parse.quote( + '%(database)s/%(type)s/%(name)s' % url_part) if isinstance(inst, Model) and inst.id: local_part += '/%d' % inst.id - return 'tryton://%s/%s' % (HOSTNAME, local_part) + return '%s://%s/%s%s' % ( + self.protocol, self.host(), self.separator, local_part) -class URLMixin(object): +is_secure = URLAccessor.is_secure +host = URLAccessor.host +http_host = URLAccessor.http_host + + +class URLMixin: __slots__ = () __url__ = URLAccessor() + __href__ = URLAccessor('http')