diff --git a/docs/en_US/release_notes_3_2.rst b/docs/en_US/release_notes_3_2.rst index 0b451ec55..c9ecb807c 100644 --- a/docs/en_US/release_notes_3_2.rst +++ b/docs/en_US/release_notes_3_2.rst @@ -10,6 +10,7 @@ This release contains a number of features and fixes reported since the release Features ******** +| `Feature #2136 `_ - Added version number for URL's to ensure that files are only cached on a per-version basis. | `Feature #2214 `_ - Add support for SCRAM password changes (requires psycopg2 >= 2.8). | `Feature #3074 `_ - Add support for reset saved password. | `Feature #3397 `_ - Add support for Trigger and JIT stats in the graphical query plan viewer. diff --git a/web/config.py b/web/config.py index 9e7d7d92a..f853e6636 100644 --- a/web/config.py +++ b/web/config.py @@ -155,6 +155,15 @@ SECURITY_PASSWORD_HASH = 'pbkdf2_sha512' # has no effect on <= Python 2.7. MINIFY_PAGE = True +# This will be added to static urls as url parameter with value as +# APP_VERSION_INT for cache busting on version upgrade. If the value is set as +# None or empty string then it will not be added. +# eg - http:localhost:5050/pgadmin.css?intver=3.13 +APP_VERSION_PARAM = 'ver' + +# Add the internal version param to below extensions only +APP_VERSION_EXTN = ('.css', '.js', '.html', '.svg', '.png', '.gif', '.ico') + # Data directory for storage of config settings etc. This shouldn't normally # need to be changed - it's here as various other settings depend on it. # On Windows, we always store data in %APPDATA%\pgAdmin. On other platforms, diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index 5926559d8..1c290a94e 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -598,6 +598,40 @@ def create_app(app_name=None): return response + ########################################################################## + # Cache busting + ########################################################################## + + # Version number to be added to all static file url requests + # This is used by url_for function when generating urls + # This will solve caching issues when application is upgrading + # This is called - Cache Busting + @app.url_defaults + def add_internal_version(endpoint, values): + extensions = config.APP_VERSION_EXTN + + # Add the internal version only if it is set + if config.APP_VERSION_PARAM is not None and \ + config.APP_VERSION_PARAM != '': + # If there is a filename, add the version + if 'filename' in values \ + and values['filename'].endswith(extensions): + values[config.APP_VERSION_PARAM] = config.APP_VERSION_INT + else: + # Sometimes there may be direct endpoint for some files + # There will be only one rule for such endpoints + urls = [url for url in app.url_map.iter_rules(endpoint)] + if len(urls) == 1 and urls[0].rule.endswith(extensions): + values[config.APP_VERSION_PARAM] = \ + config.APP_VERSION_INT + + # Strip away internal version param before sending further to app as it was + # required for cache busting only + @app.url_value_preprocessor + def strip_version_number(endpoint, values): + if (config.APP_VERSION_PARAM in values): + values.pop(config.APP_VERSION_PARAM) + ########################################################################## # Minify output ########################################################################## diff --git a/web/pgadmin/browser/tests/test_internal_version.py b/web/pgadmin/browser/tests/test_internal_version.py new file mode 100644 index 000000000..b90f900bf --- /dev/null +++ b/web/pgadmin/browser/tests/test_internal_version.py @@ -0,0 +1,65 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2018, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +from pgadmin.utils.route import BaseTestGenerator +from flask import url_for +import config +from pgadmin import create_app + + +class InternalVersionTestCase(BaseTestGenerator): + """ + """ + scenarios = [ + ('TestCase with INTERNAL_VERSION_PARAM none', dict( + app_version=30100, + version_param='', + version_extn=('.js',), + endpoint='static', + filename='js/generated/pgadmin_commons.js', + version_expected=False + )), + ('TestCase with INTERNAL_VERSION_PARAM present', dict( + app_version=30100, + version_param='intver', + version_extn=('.js',), + endpoint='static', + filename='js/generated/pgadmin_commons.js', + version_expected=True + )), + ('TestCase with INTERNAL_VERSION_EXTN different', dict( + app_version=30100, + version_param='intver', + version_extn=('.css',), + endpoint='static', + filename='js/generated/pgadmin_commons.js', + version_expected=False + )), + ] + + def setUp(self): + self.config_bak = config + + def runTest(self): + config.APP_VERSION_INT = self.app_version + config.INTERNAL_VERSION_PARAM = self.version_param + config.INTERNAL_VERSION_EXTN = self.version_extn + + version_string = "?{0}={1}".format(config.INTERNAL_VERSION_PARAM, + config.APP_VERSION_INT) + app = create_app() + with app.app_context(), app.test_request_context(): + url = url_for(self.endpoint, filename=self.filename) + if self.version_expected: + self.assertTrue(url.endswith(version_string)) + else: + self.assertFalse(url.endswith(version_string)) + + def tearDown(self): + config = self.config_bak diff --git a/web/pgadmin/templates/base.html b/web/pgadmin/templates/base.html index 72a3156c0..7a53c3111 100644 --- a/web/pgadmin/templates/base.html +++ b/web/pgadmin/templates/base.html @@ -34,6 +34,9 @@