mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Upgrade Flask, Flask-SQLAlchemy, Flask-WTF, Flask-Babel, Flask-Security-Too, WTForms, Werkzeug and keep backward compatibility with Python 3.7
This commit is contained in:
parent
5f3965ff0a
commit
96fccd28a9
@ -8,20 +8,26 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
Flask==2.2.*
|
||||
Flask==2.3.*; python_version > '3.7'
|
||||
Flask==2.2.*; python_version <= '3.7'
|
||||
Flask-Gravatar==0.*
|
||||
Flask-Login==0.*
|
||||
Flask-Mail==0.*
|
||||
Flask-Migrate==4.*
|
||||
greenlet==1.1.2; python_version <= '3.10'
|
||||
Flask-SQLAlchemy==3.0.*
|
||||
Flask-WTF==1.1.1
|
||||
Flask-SQLAlchemy==3.1.*; python_version > '3.7'
|
||||
Flask-SQLAlchemy==3.0.*; python_version <= '3.7'
|
||||
Flask-WTF==1.2.*; python_version > '3.7'
|
||||
Flask-WTF==1.1.1; python_version <= '3.7'
|
||||
Flask-Compress==1.*
|
||||
Flask-Paranoid==0.*
|
||||
Flask-Babel==3.1.*
|
||||
Flask-Security-Too==5.1.*
|
||||
Flask-Babel==4.0.*; python_version > '3.7'
|
||||
Flask-Babel==3.1.*; python_version <= '3.7'
|
||||
Flask-Security-Too==5.2.*; python_version > '3.7'
|
||||
Flask-Security-Too==5.1.*; python_version <= '3.7'
|
||||
Flask-SocketIO==5.3.*
|
||||
WTForms==3.0.*
|
||||
WTForms==3.1.*; python_version > '3.7'
|
||||
WTForms==3.0.*; python_version <= '3.7'
|
||||
passlib==1.*
|
||||
pytz==2023.*
|
||||
speaklater3==1.*
|
||||
@ -51,5 +57,7 @@ azure-mgmt-subscription==3.1.1
|
||||
azure-identity==1.15.0
|
||||
google-api-python-client==2.*
|
||||
google-auth-oauthlib==1.1.0
|
||||
Werkzeug==2.2.3
|
||||
keyring==24.*
|
||||
keyring==24.*; python_version > '3.7'
|
||||
keyring==23.*; python_version <= '3.7'
|
||||
Werkzeug==2.3.*; python_version > '3.7'
|
||||
Werkzeug==2.2.3; python_version <= '3.7'
|
||||
|
@ -414,13 +414,7 @@ SECURITY_EMAIL_SUBJECT_PASSWORD_CHANGE_NOTICE = \
|
||||
##########################################################################
|
||||
# Email address validation
|
||||
##########################################################################
|
||||
|
||||
# flask-security-too will validate email addresses and check deliverability
|
||||
# by default. Disable the deliverability check by default, which was the old
|
||||
# behaviour in <= v5.3
|
||||
CHECK_EMAIL_DELIVERABILITY = False
|
||||
SECURITY_EMAIL_VALIDATOR_ARGS = \
|
||||
{"check_deliverability": CHECK_EMAIL_DELIVERABILITY}
|
||||
|
||||
##########################################################################
|
||||
# Upgrade checks
|
||||
|
@ -152,6 +152,8 @@ else:
|
||||
if not app.PGADMIN_RUNTIME:
|
||||
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
||||
|
||||
app.run_before_app_start()
|
||||
|
||||
|
||||
##########################################################################
|
||||
# The entry point
|
||||
|
@ -7,6 +7,7 @@
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
|
||||
class AbsProvider:
|
||||
""" Abstract provider """
|
||||
parser = None
|
||||
|
@ -31,6 +31,7 @@ from flask_mail import Mail
|
||||
from flask_paranoid import Paranoid
|
||||
from flask_security import Security, SQLAlchemyUserDatastore, current_user
|
||||
from flask_security.utils import login_user, logout_user
|
||||
from flask_migrate import Migrate
|
||||
from werkzeug.datastructures import ImmutableDict
|
||||
from werkzeug.local import LocalProxy
|
||||
from werkzeug.utils import find_modules
|
||||
@ -79,6 +80,7 @@ class PgAdmin(Flask):
|
||||
loader=VersionedTemplateLoader(self)
|
||||
)
|
||||
self.logout_hooks = []
|
||||
self.before_app_start = []
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@ -105,13 +107,6 @@ class PgAdmin(Flask):
|
||||
if isinstance(blueprint, PgAdminModule):
|
||||
yield blueprint
|
||||
|
||||
@property
|
||||
def stylesheets(self):
|
||||
stylesheets = []
|
||||
for module in self.submodules:
|
||||
stylesheets.extend(getattr(module, "stylesheets", []))
|
||||
return set(stylesheets)
|
||||
|
||||
@property
|
||||
def messages(self):
|
||||
messages = dict()
|
||||
@ -150,21 +145,6 @@ class PgAdmin(Flask):
|
||||
|
||||
yield 'pgadmin.root', wsgi_root_path
|
||||
|
||||
@property
|
||||
def javascripts(self):
|
||||
scripts = []
|
||||
scripts_names = []
|
||||
|
||||
# Remove duplicate javascripts from the list
|
||||
for module in self.submodules:
|
||||
module_scripts = getattr(module, "javascripts", [])
|
||||
for s in module_scripts:
|
||||
if s['name'] not in scripts_names:
|
||||
scripts.append(s)
|
||||
scripts_names.append(s['name'])
|
||||
|
||||
return scripts
|
||||
|
||||
@property
|
||||
def menu_items(self):
|
||||
from operator import attrgetter
|
||||
@ -182,6 +162,15 @@ class PgAdmin(Flask):
|
||||
isinstance(getattr(module, 'on_logout'), MethodType):
|
||||
self.logout_hooks.append(module)
|
||||
|
||||
def register_before_app_start(self, callback):
|
||||
self.before_app_start.append(callback)
|
||||
|
||||
def run_before_app_start(self):
|
||||
# call before app starts or is exported
|
||||
with self.app_context(), self.test_request_context():
|
||||
for callback in self.before_app_start:
|
||||
callback()
|
||||
|
||||
|
||||
def _find_blueprint():
|
||||
if request.blueprint:
|
||||
@ -348,6 +337,7 @@ def create_app(app_name=None):
|
||||
|
||||
# Create database connection object and mailer
|
||||
db.init_app(app)
|
||||
Migrate(app, db)
|
||||
|
||||
##########################################################################
|
||||
# Upgrade the schema (if required)
|
||||
@ -501,8 +491,6 @@ def create_app(app_name=None):
|
||||
# CSRF Token expiration till session expires
|
||||
'WTF_CSRF_TIME_LIMIT': getattr(config, 'CSRF_TIME_LIMIT', None),
|
||||
'WTF_CSRF_METHODS': ['GET', 'POST', 'PUT', 'DELETE'],
|
||||
# Disable deliverable check for email addresss
|
||||
'SECURITY_EMAIL_VALIDATOR_ARGS': config.SECURITY_EMAIL_VALIDATOR_ARGS
|
||||
}))
|
||||
|
||||
if 'SCRIPT_NAME' in os.environ and os.environ["SCRIPT_NAME"]:
|
||||
|
@ -218,10 +218,6 @@ class CollectionNodeModule(PgAdminModule, PGChildModule, metaclass=ABCMeta):
|
||||
def node_path(self):
|
||||
return self.browser_url_prefix + self.node_type
|
||||
|
||||
@property
|
||||
def javascripts(self):
|
||||
return []
|
||||
|
||||
@property
|
||||
def show_node(self):
|
||||
"""
|
||||
|
@ -35,7 +35,4 @@ class ConstraintRegistry():
|
||||
|
||||
|
||||
class ConstraintTypeModule(CollectionNodeModule):
|
||||
register = Blueprint.register
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
pass
|
||||
|
@ -36,14 +36,6 @@ class DashboardModule(PgAdminModule):
|
||||
def get_own_menuitems(self):
|
||||
return {}
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def register_preferences(self):
|
||||
"""
|
||||
register_preferences
|
||||
|
@ -10,7 +10,8 @@
|
||||
"""A blueprint module providing utility functions for the application."""
|
||||
|
||||
from pgadmin.utils import driver
|
||||
from flask import url_for, render_template, Response, request, current_app
|
||||
from flask import render_template, Response, request, current_app
|
||||
from flask.helpers import url_for
|
||||
from flask_babel import gettext
|
||||
from flask_security import login_required
|
||||
from pgadmin.utils import PgAdminModule, replace_binary_path, \
|
||||
@ -36,10 +37,6 @@ MODULE_NAME = 'misc'
|
||||
class MiscModule(PgAdminModule):
|
||||
LABEL = gettext('Miscellaneous')
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def register_preferences(self):
|
||||
"""
|
||||
Register preferences for this module.
|
||||
|
@ -23,13 +23,6 @@ MODULE_NAME = 'bgprocess'
|
||||
|
||||
|
||||
class BGProcessModule(PgAdminModule):
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
"""
|
||||
|
@ -44,14 +44,6 @@ class CloudModule(PgAdminModule):
|
||||
|
||||
"""
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
"""
|
||||
Returns:
|
||||
|
@ -39,14 +39,6 @@ MODULE_NAME = 'azure'
|
||||
class AzurePostgresqlModule(PgAdminModule):
|
||||
"""Cloud module to deploy on Azure Postgresql"""
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
return ['azure.verify_credentials',
|
||||
'azure.check_cluster_name_availability',
|
||||
|
@ -32,13 +32,6 @@ EHA_CLUSTER_ARCH = 'eha' # Extreme High Availability
|
||||
|
||||
class BigAnimalModule(PgAdminModule):
|
||||
"""Cloud module to deploy on EDB BigAnimal"""
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
return ['biganimal.verification',
|
||||
|
@ -37,14 +37,6 @@ os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # Required for Oauth2
|
||||
class GooglePostgresqlModule(PgAdminModule):
|
||||
"""Cloud module to deploy on Google Cloud"""
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
return ['google.verify_credentials',
|
||||
'google.projects',
|
||||
|
@ -34,13 +34,6 @@ MODULE_NAME = 'rds'
|
||||
|
||||
class RDSModule(PgAdminModule):
|
||||
"""Cloud module to deploy on AWS RDS"""
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
return ['rds.db_versions',
|
||||
|
@ -36,9 +36,6 @@ class PreferencesModule(PgAdminModule):
|
||||
And, allows the user to modify (not add/remove) as per their requirement.
|
||||
"""
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
return []
|
||||
|
||||
def get_own_menuitems(self):
|
||||
return {}
|
||||
|
||||
|
@ -10,13 +10,10 @@
|
||||
import os
|
||||
import flask_migrate
|
||||
|
||||
from pgadmin import db
|
||||
|
||||
|
||||
def db_upgrade(app):
|
||||
from pgadmin.utils import u_encode, fs_encoding
|
||||
with app.app_context():
|
||||
flask_migrate.Migrate(app, db)
|
||||
migration_folder = os.path.join(
|
||||
os.path.dirname(os.path.realpath(u_encode(__file__, fs_encoding))),
|
||||
os.pardir, os.pardir,
|
||||
|
@ -42,14 +42,6 @@ class GrantWizardModule(PgAdminModule):
|
||||
javascript file.
|
||||
"""
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def show_system_objects(self):
|
||||
"""
|
||||
return system preference objects
|
||||
|
@ -35,14 +35,6 @@ class MaintenanceModule(PgAdminModule):
|
||||
"""
|
||||
LABEL = _('Maintenance')
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module.
|
||||
"""
|
||||
stylesheets = []
|
||||
return stylesheets
|
||||
|
||||
def get_exposed_url_endpoints(self):
|
||||
"""
|
||||
Returns:
|
||||
|
@ -49,19 +49,6 @@ class PgAdminModule(Blueprint):
|
||||
|
||||
super().__init__(name, import_name, **kwargs)
|
||||
|
||||
def create_module_preference():
|
||||
# Create preference for each module by default
|
||||
if hasattr(self, 'LABEL'):
|
||||
self.preference = Preferences(self.name, self.LABEL)
|
||||
else:
|
||||
self.preference = Preferences(self.name, None)
|
||||
|
||||
self.register_preferences()
|
||||
|
||||
# Create and register the module preference object and preferences for
|
||||
# it just before the first request
|
||||
self.before_app_first_request(create_module_preference)
|
||||
|
||||
def register_preferences(self):
|
||||
# To be implemented by child classes
|
||||
pass
|
||||
@ -74,20 +61,25 @@ class PgAdminModule(Blueprint):
|
||||
|
||||
super().register(app, options)
|
||||
|
||||
def create_module_preference():
|
||||
# Create preference for each module by default
|
||||
if hasattr(self, 'LABEL'):
|
||||
self.preference = Preferences(self.name, self.LABEL)
|
||||
else:
|
||||
self.preference = Preferences(self.name, None)
|
||||
|
||||
self.register_preferences()
|
||||
|
||||
# Create and register the module preference object and preferences for
|
||||
# it just before starting app
|
||||
app.register_before_app_start(create_module_preference)
|
||||
|
||||
for module in self.submodules:
|
||||
module.parentmodules.append(self)
|
||||
if app.blueprints.get(module.name) is None:
|
||||
app.register_blueprint(module)
|
||||
app.register_logout_hook(module)
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module, not including any
|
||||
stylesheet needed by the submodules.
|
||||
"""
|
||||
return []
|
||||
|
||||
def get_own_messages(self):
|
||||
"""
|
||||
Returns:
|
||||
@ -111,13 +103,6 @@ class PgAdminModule(Blueprint):
|
||||
"""
|
||||
return []
|
||||
|
||||
@property
|
||||
def stylesheets(self):
|
||||
stylesheets = self.get_own_stylesheets()
|
||||
for module in self.submodules:
|
||||
stylesheets.extend(module.stylesheets)
|
||||
return stylesheets
|
||||
|
||||
@property
|
||||
def messages(self):
|
||||
res = self.get_own_messages()
|
||||
|
@ -19,7 +19,6 @@ def validate_email(email):
|
||||
email, check_deliverability=config.CHECK_EMAIL_DELIVERABILITY)
|
||||
|
||||
# Update with the normalized form.
|
||||
email = valid.email
|
||||
return True
|
||||
except EmailNotValidError as e:
|
||||
# email is not valid, exception message is human-readable
|
||||
|
@ -9,12 +9,13 @@
|
||||
|
||||
import re
|
||||
import flask
|
||||
from flask import current_app, request, session, testing
|
||||
from flask import current_app, testing
|
||||
|
||||
from werkzeug.datastructures import Headers
|
||||
from werkzeug.test import EnvironBuilder
|
||||
from flask_wtf.csrf import generate_csrf
|
||||
import config
|
||||
import sys
|
||||
|
||||
|
||||
class RequestShim():
|
||||
@ -26,9 +27,17 @@ class RequestShim():
|
||||
|
||||
def set_cookie(self, key, value='', *args, **kwargs):
|
||||
"Set the cookie on the Flask test client."
|
||||
server_name = current_app.config["SERVER_NAME"] or "localhost"
|
||||
if sys.version_info <= (3, 7, 9999):
|
||||
server_name = current_app.config["SERVER_NAME"] or "localhost"
|
||||
return self.client.set_cookie(
|
||||
server_name, key=key, value=value, *args, **kwargs
|
||||
)
|
||||
|
||||
if kwargs['domain'] is None:
|
||||
kwargs['domain'] = current_app.config["SERVER_NAME"] or "localhost"
|
||||
|
||||
return self.client.set_cookie(
|
||||
server_name, key=key, value=value, *args, **kwargs
|
||||
key=key, value=value, *args, **kwargs
|
||||
)
|
||||
|
||||
def delete_cookie(self, key, *args, **kwargs):
|
||||
@ -90,8 +99,14 @@ class TestClient(testing.FlaskClient):
|
||||
# this test client, such as the secure cookie that
|
||||
# powers `flask.session`,
|
||||
# and make a test request context that has those cookies in it.
|
||||
environ_overrides = {}
|
||||
self.cookie_jar.inject_wsgi(environ_overrides)
|
||||
environ_overrides = {
|
||||
'wsgi.url_scheme': ''
|
||||
}
|
||||
if sys.version_info <= (3, 7, 9999):
|
||||
self.cookie_jar.inject_wsgi(environ_overrides)
|
||||
else:
|
||||
self._add_cookies_to_wsgi(environ_overrides)
|
||||
|
||||
with self.app.test_request_context():
|
||||
# Now, we call Flask-WTF's method of generating a CSRF token...
|
||||
csrf_token = generate_csrf()
|
||||
|
@ -109,7 +109,9 @@ from logging import WARNING
|
||||
config.CONSOLE_LOG_LEVEL = WARNING
|
||||
|
||||
# Create the app
|
||||
app = create_app()
|
||||
from pgAdmin4 import app
|
||||
# app = create_app()
|
||||
app.app_context().push()
|
||||
|
||||
app.PGADMIN_INT_KEY = ''
|
||||
app.config.update({'SESSION_COOKIE_DOMAIN': None})
|
||||
@ -511,8 +513,9 @@ def execute_test(test_module_list_passed, server_passed, driver_passed,
|
||||
test_utils.create_database(server_passed, test_db_name)
|
||||
|
||||
# Configure preferences for the test cases
|
||||
test_utils.configure_preferences(
|
||||
default_binary_path=server_passed['default_binary_paths'])
|
||||
with app.app_context():
|
||||
test_utils.configure_preferences(
|
||||
default_binary_path=server_passed['default_binary_paths'])
|
||||
|
||||
# Create user to run selenoid tests in parallel
|
||||
if parallel_ui_test:
|
||||
|
Loading…
Reference in New Issue
Block a user