From e17c50d304a5d7b508f79d385fffb08ef4ae5206 Mon Sep 17 00:00:00 2001 From: Akshay Joshi Date: Thu, 20 Oct 2022 16:18:41 +0530 Subject: [PATCH] Added support for storing configurations of pgAdmin in an external database. #1832 --- docs/en_US/code_overview.rst | 2 +- docs/en_US/external_database.rst | 63 ++++ docs/en_US/index.rst | 3 +- docs/en_US/master_password.rst | 4 +- docs/en_US/release_notes.rst | 1 + docs/en_US/release_notes_6_16.rst | 26 ++ docs/en_US/restore_locked_user.rst | 13 +- web/config.py | 17 + web/migrations/env.py | 6 +- web/migrations/versions/02b9dccdcfcb_.py | 11 +- web/migrations/versions/09d53fca90c7_.py | 294 +++++++----------- web/migrations/versions/1586db67b98e_.py | 14 +- web/migrations/versions/15c88f765bc8_.py | 20 +- web/migrations/versions/35f29b1701bd_.py | 52 +--- web/migrations/versions/398697dc9550_.py | 86 +++-- web/migrations/versions/3c1e4b6eda55_.py | 18 +- web/migrations/versions/3ce25f562f3b_.py | 17 +- web/migrations/versions/493cd3e39c0c_.py | 18 +- web/migrations/versions/50aad68f99c2_.py | 80 +---- web/migrations/versions/6650c52670c2_.py | 13 +- web/migrations/versions/7c56ea250085_.py | 85 +---- web/migrations/versions/7fedf8531802_.py | 56 ++-- web/migrations/versions/81c7ffeffeee_.py | 31 +- web/migrations/versions/84700139beb0_.py | 31 +- web/migrations/versions/a091c9611d20_.py | 110 +++---- web/migrations/versions/a39bd015b644_.py | 96 +----- web/migrations/versions/a68b374fe373_.py | 36 +-- web/migrations/versions/a77a0932a568_.py | 84 +---- web/migrations/versions/aa86fb60b73d_.py | 7 +- web/migrations/versions/aff1436e3c8c_.py | 23 +- web/migrations/versions/b5b87fdfcb30_.py | 8 +- web/migrations/versions/c465fee44968_.py | 63 ++-- web/migrations/versions/c6974f64df08_.py | 19 +- web/migrations/versions/ca00ec32581b_.py | 13 +- web/migrations/versions/d0bc9f32b2b9_.py | 17 +- web/migrations/versions/d39482714a2e_.py | 28 +- web/migrations/versions/d85a62333272_.py | 19 +- web/migrations/versions/ec1cac3399c9_.py | 44 +-- web/migrations/versions/ece2e76bf60e_.py | 7 +- web/migrations/versions/ef590e979b0d_.py | 41 +-- web/migrations/versions/f195f9a4923d_.py | 20 +- web/migrations/versions/f79844e926ae_.py | 11 +- web/migrations/versions/fdc58d9bd449_.py | 161 +++++----- web/pgadmin/__init__.py | 124 +++++--- web/pgadmin/authenticate/mfa/utils.py | 2 +- .../browser/server_groups/servers/__init__.py | 8 +- web/pgadmin/misc/bgprocess/processes.py | 13 +- web/pgadmin/model/__init__.py | 8 +- web/pgadmin/setup/__init__.py | 2 +- web/pgadmin/setup/db_version.py | 17 +- web/pgadmin/tools/debugger/__init__.py | 18 +- web/setup.py | 65 ++-- 52 files changed, 963 insertions(+), 1062 deletions(-) create mode 100644 docs/en_US/external_database.rst create mode 100644 docs/en_US/release_notes_6_16.rst diff --git a/docs/en_US/code_overview.rst b/docs/en_US/code_overview.rst index 6b00d41a7..31546be30 100644 --- a/docs/en_US/code_overview.rst +++ b/docs/en_US/code_overview.rst @@ -44,7 +44,7 @@ the **Flask-Security** module to manage application security and users, and provides options for self-service password reset and password changes etc. Whether in desktop or server mode, each user's settings are stored in a SQLite -database which is also used to store the user accounts. This is initially +OR external database which is also used to store the user accounts. This is initially created using the **setup.py** script which will create the database file and schema within it, and add the first user account (with administrative privileges) and a default server group for them. A **settings** table is also diff --git a/docs/en_US/external_database.rst b/docs/en_US/external_database.rst new file mode 100644 index 000000000..7ac497aa8 --- /dev/null +++ b/docs/en_US/external_database.rst @@ -0,0 +1,63 @@ +.. _external_database: + +**************************************************** +`External database for pgAdmin configuration`:index: +**************************************************** + +The configurations used by pgAdmin are stored in the SQLite database. +There are many settings stored in this database, like preferences, +user accounts, auto-discovered servers, and many more. + +In SQLite, the database is stored in a single file that may be located anywhere +in the directory, which means it is not prepared for failure (no HA support). +In addition, it is not designed to handle many connections reading/writing data +concurrently. + +pgAdmin added support for storing configurations in an external database to +prevent this. + +Added the 'CONFIG_DATABASE_URI' parameter in the :ref:`config.py ` +file. + +Use SQLite Database +******************* + +To use SQLite Database, make sure CONFIG_DATABASE_URI is empty string, such as +''. + +Use External Database +********************* + +If you want to use an external database, make sure the CONFIG_DATABASE_URI +format is "dialect+driver://username:password@host:port/database". + +**Note** It is recommended to create the database in advance. + +Use PostgreSQL Database +*********************** + +Following are the formats to use PostgreSQL as an external database. + +Basic syntax: + +.. code-block:: bash + + postgresql://username:password@host:port/database + +Using specific schema (It is recommended to create the schema in advance): + +.. code-block:: bash + + postgresql://username:password@host:port/database?options=-csearch_path= + +Using default pgpass path for the service account: + +.. code-block:: bash + + postgresql://username@host:port?options=-csearch_path= + +Specifying pgpass file path: + +.. code-block:: bash + + postgresql://username@host:port?passfile=&options=-csearch_path= diff --git a/docs/en_US/index.rst b/docs/en_US/index.rst index 0bc680f0d..8b21d9b16 100644 --- a/docs/en_US/index.rst +++ b/docs/en_US/index.rst @@ -16,6 +16,7 @@ of database objects. :maxdepth: 2 getting_started + external_database connecting managing_cluster_objects managing_database_objects @@ -31,4 +32,4 @@ of database objects. .. note:: Postgres, PostgreSQL and the Slonik Logo are trademarks or registered trademarks of the `PostgreSQL Community Association of Canada - `_, and used with their permission. \ No newline at end of file + `_, and used with their permission. diff --git a/docs/en_US/master_password.rst b/docs/en_US/master_password.rst index ced1c7eb5..25f3435f9 100644 --- a/docs/en_US/master_password.rst +++ b/docs/en_US/master_password.rst @@ -11,8 +11,8 @@ passwords. This is applicable only for desktop mode users. the first time after starting the application. * Once you set the master password, all the existing saved passwords will be re-encrypted using the master password. -* The server passwords which are saved in the SQLite DB file are encrypted and - decrypted using the master password. +* The server passwords which are saved in the SQLite DB file or External + Database are encrypted and decrypted using the master password. .. image:: images/master_password_set.png :alt: Set master password diff --git a/docs/en_US/release_notes.rst b/docs/en_US/release_notes.rst index 7daec2111..9e110b979 100644 --- a/docs/en_US/release_notes.rst +++ b/docs/en_US/release_notes.rst @@ -11,6 +11,7 @@ notes for it. .. toctree:: :maxdepth: 1 + release_notes_6_16 release_notes_6_15 release_notes_6_14 release_notes_6_13 diff --git a/docs/en_US/release_notes_6_16.rst b/docs/en_US/release_notes_6_16.rst new file mode 100644 index 000000000..111f0d4cb --- /dev/null +++ b/docs/en_US/release_notes_6_16.rst @@ -0,0 +1,26 @@ +************ +Version 6.16 +************ + +Release date: 2022-11-17 + +This release contains a number of bug fixes and new features since the release of pgAdmin 4 v6.15. + +Supported Database Servers +************************** +**PostgreSQL**: 10, 11, 12, 13, 14 and 15 + +**EDB Advanced Server**: 10, 11, 12, 13, 14 and 15 + +New features +************ + + | `Issue #1832 `_ - Added support for storing configurations of pgAdmin in an external database. + +Housekeeping +************ + + +Bug fixes +********* + diff --git a/docs/en_US/restore_locked_user.rst b/docs/en_US/restore_locked_user.rst index 49ae7d017..6d4ca3b47 100644 --- a/docs/en_US/restore_locked_user.rst +++ b/docs/en_US/restore_locked_user.rst @@ -26,7 +26,9 @@ When Administrator itself gets locked, following steps may be considered to rest OR -By updating SQLite DB (pgAdmin4.db): +By updating configuration database + +SQLite DB (pgAdmin4.db): * Locate the pgAdmin4.db file and open it using any DB Browser (or DB Browser for SQLite) * After opening the DB file, head towards 'Execute SQL' section. @@ -34,6 +36,13 @@ By updating SQLite DB (pgAdmin4.db): *UPDATE USER SET LOCKED = false, LOGIN_ATTEMPTS = 0 WHERE USERNAME = * +External database: + +* Connect to the database. +* Run below query - + +*UPDATE USER SET LOCKED = false, LOGIN_ATTEMPTS = 0 WHERE USERNAME = * + * Make sure the query changes are committed. Account locking by failed login attempts: @@ -47,4 +56,4 @@ exceeded. MAX_LOGIN_ATTEMPTS is defaulted to 3 unsuccessful login attempts, after which the account would be locked. -The only way to restore the user account is by contacting the Administrator and ask to unlock it. \ No newline at end of file +The only way to restore the user account is by contacting the Administrator and ask to unlock it. diff --git a/web/config.py b/web/config.py index 7c5320893..9de292882 100644 --- a/web/config.py +++ b/web/config.py @@ -306,6 +306,23 @@ PG_DEFAULT_DRIVER = 'psycopg2' # for the particular session. (in minutes) MAX_SESSION_IDLE_TIME = 60 +########################################################################## +# External Database Settings +# +# All configuration settings are stored by default in the SQLite database. +# In order to use external databases like PostgreSQL sets the value of +# CONFIG_DATABASE_URI like below: +# dialect+driver://username:password@host:port/database +# +# PostgreSQL: +# postgresql://username:password@host:port/database +# Specify Schema Name +# postgresql://username:password@host:port/database?options=-csearch_path=pgadmin +# Using PGPASS file +# postgresql://username@host:port?options=-csearch_path=pgadmin +########################################################################## +CONFIG_DATABASE_URI = '' + ########################################################################## # User account and settings storage ########################################################################## diff --git a/web/migrations/env.py b/web/migrations/env.py index 144ac368f..16c2c115b 100644 --- a/web/migrations/env.py +++ b/web/migrations/env.py @@ -24,8 +24,9 @@ logger = logging.getLogger('alembic.env') # from myapp import mymodel # target_metadata = mymodel.Base.metadata from flask import current_app -config.set_main_option('sqlalchemy.url', - current_app.config.get('SQLALCHEMY_DATABASE_URI')) +db_url_escaped = \ + current_app.config.get('SQLALCHEMY_DATABASE_URI').replace('%', '%%') +config.set_main_option('sqlalchemy.url', db_url_escaped) target_metadata = current_app.extensions['migrate'].db.metadata # other values from the config, defined by the needs of env.py, @@ -87,6 +88,7 @@ def run_migrations_online(): finally: connection.close() + if context.is_offline_mode(): run_migrations_offline() else: diff --git a/web/migrations/versions/02b9dccdcfcb_.py b/web/migrations/versions/02b9dccdcfcb_.py index db5085896..7b3c84f29 100644 --- a/web/migrations/versions/02b9dccdcfcb_.py +++ b/web/migrations/versions/02b9dccdcfcb_.py @@ -14,7 +14,8 @@ Revises: ef590e979b0d Create Date: 2017-11-14 19:09:04.674575 """ -from pgadmin.model import db +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = '02b9dccdcfcb' @@ -24,12 +25,8 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN bgcolor TEXT(10)' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN fgcolor TEXT(10)' - ) + op.add_column('server', sa.Column('bgcolor', sa.String(length=10))) + op.add_column('server', sa.Column('fgcolor', sa.String(length=10))) def downgrade(): diff --git a/web/migrations/versions/09d53fca90c7_.py b/web/migrations/versions/09d53fca90c7_.py index c93f8cef0..fefaed4ec 100644 --- a/web/migrations/versions/09d53fca90c7_.py +++ b/web/migrations/versions/09d53fca90c7_.py @@ -16,11 +16,11 @@ Create Date: 2017-03-13 12:27:30.543908 """ import base64 import os -import sys - import config +import sqlalchemy as sa +from alembic import op from pgadmin.model import db, Server -from pgadmin.setup import get_version +from pgadmin.setup import get_version_for_migration # revision identifiers, used by Alembic. @@ -31,211 +31,147 @@ depends_on = None def upgrade(): - version = get_version() + version = get_version_for_migration(op) # Changes introduced in schema version 2 if version < 2: # Create the 'server' table db.metadata.create_all(db.engine, tables=[Server.__table__]) if version < 3: - db.engine.execute( - 'ALTER TABLE server ADD COLUMN comment TEXT(1024)' - ) + op.add_column('server', sa.Column('comment', sa.String(length=1024))) if version < 4: - db.engine.execute( - 'ALTER TABLE server ADD COLUMN password TEXT(64)' - ) + op.add_column('server', sa.Column('password', sa.String(length=64))) if version < 5: - db.engine.execute('ALTER TABLE server ADD COLUMN role text(64)') + op.add_column('server', sa.Column('role', sa.String(length=64))) if version < 6: - # To Save previous data, create temp table - - db.engine.execute("create table server_old as select * from server") - - db.engine.execute("DROP TABLE server") - - db.engine.execute(""" - CREATE TABLE server ( - id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - servergroup_id INTEGER NOT NULL, - name VARCHAR(128) NOT NULL, - host VARCHAR(128) NOT NULL, - port INTEGER NOT NULL CHECK (port >= 1024 AND port <= 65534), - maintenance_db VARCHAR(64) NOT NULL, - username VARCHAR(64) NOT NULL, - ssl_mode VARCHAR(16) NOT NULL CHECK ( - ssl_mode IN ( - 'allow', 'prefer', 'require', 'disable', 'verify-ca', 'verify-full' - )), - comment VARCHAR(1024), password TEXT(64), role text(64), - PRIMARY KEY (id), - FOREIGN KEY(user_id) REFERENCES user (id), - FOREIGN KEY(servergroup_id) REFERENCES servergroup (id) - )""") - db.engine.execute(""" - INSERT INTO server ( - id, user_id, servergroup_id, name, host, port, maintenance_db, username, - ssl_mode, comment, password, role - ) SELECT - id, user_id, servergroup_id, name, host, port, maintenance_db, username, - ssl_mode, comment, password, role - FROM server_old""") - db.engine.execute("DROP TABLE server_old") + with op.batch_alter_table("server") as batch_op: + batch_op.create_check_constraint( + "ck_port_range", + "port >= 1024 AND port <= 65535" + ) + batch_op.create_check_constraint( + "ck_ssl_mode", + "ssl_mode IN ('allow', 'prefer', 'require', 'disable', \ + 'verify-ca', 'verify-full')" + ) if version < 8: - db.engine.execute(""" - CREATE TABLE module_preference( - id INTEGER PRIMARY KEY, - name VARCHAR(256) NOT NULL - )""") + op.create_table( + 'module_preference', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('name', sa.String(length=256), nullable=False), + sa.PrimaryKeyConstraint('id')) - db.engine.execute(""" - CREATE TABLE preference_category( - id INTEGER PRIMARY KEY, - mid INTEGER, - name VARCHAR(256) NOT NULL, + op.create_table( + 'preference_category', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('mid', sa.Integer(),), + sa.Column('name', sa.String(length=256), nullable=False), + sa.ForeignKeyConstraint(['mid'], ['module_preference.id'], ), + sa.PrimaryKeyConstraint('id')) - FOREIGN KEY(mid) REFERENCES module_preference(id) - )""") + op.create_table( + 'preferences', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('cid', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=256), nullable=False), + sa.ForeignKeyConstraint(['cid'], ['preference_category.id'], ), + sa.PrimaryKeyConstraint('id')) - db.engine.execute(""" - CREATE TABLE preferences ( - - id INTEGER PRIMARY KEY, - cid INTEGER NOT NULL, - name VARCHAR(256) NOT NULL, - - FOREIGN KEY(cid) REFERENCES preference_category (id) - )""") - - db.engine.execute(""" - CREATE TABLE user_preferences ( - - pid INTEGER, - uid INTEGER, - value VARCHAR(1024) NOT NULL, - - PRIMARY KEY (pid, uid), - FOREIGN KEY(pid) REFERENCES preferences (pid), - FOREIGN KEY(uid) REFERENCES user (id) - )""") + op.create_table( + 'user_preferences', + sa.Column('pid', sa.Integer(), nullable=False), + sa.Column('uid', sa.Integer(), nullable=False), + sa.Column('value', sa.String(length=1024), nullable=False), + sa.ForeignKeyConstraint(['pid'], ['preferences.id'], ), + sa.ForeignKeyConstraint(['uid'], ['user.id'], ), + sa.PrimaryKeyConstraint('pid', 'uid')) if version < 9: - db.engine.execute(""" - CREATE TABLE IF NOT EXISTS debugger_function_arguments ( - server_id INTEGER , - database_id INTEGER , - schema_id INTEGER , - function_id INTEGER , - arg_id INTEGER , - is_null INTEGER NOT NULL CHECK (is_null >= 0 AND is_null <= 1) , - is_expression INTEGER NOT NULL CHECK (is_expression >= 0 AND is_expression <= 1) , - use_default INTEGER NOT NULL CHECK (use_default >= 0 AND use_default <= 1) , - value TEXT, - PRIMARY KEY (server_id, database_id, schema_id, function_id, arg_id) - )""") - + op.create_table( + 'debugger_function_arguments', + sa.Column('server_id', sa.Integer(), nullable=False), + sa.Column('database_id', sa.Integer(), nullable=False), + sa.Column('schema_id', sa.Integer(), nullable=False), + sa.Column('function_id', sa.Integer(), nullable=False), + sa.Column('arg_id', sa.Integer(), nullable=False), + sa.Column('is_null', sa.Integer(), nullable=False), + sa.Column('is_expression', sa.Integer(), nullable=False), + sa.Column('use_default', sa.Integer()), + sa.Column('value', sa.String(), nullable=False), + sa.CheckConstraint('is_null >= 0 AND is_null <= 1'), + sa.CheckConstraint('is_expression >= 0 AND is_expression <= 1'), + sa.CheckConstraint('use_default >= 0 AND use_default <= 1'), + sa.PrimaryKeyConstraint('server_id', 'database_id', 'schema_id', + 'function_id', 'arg_id')) if version < 10: - db.engine.execute(""" - CREATE TABLE process( - user_id INTEGER NOT NULL, - pid TEXT NOT NULL, - desc TEXT NOT NULL, - command TEXT NOT NULL, - arguments TEXT, - start_time TEXT, - end_time TEXT, - logdir TEXT, - exit_code INTEGER, - acknowledge TEXT, - PRIMARY KEY(pid), - FOREIGN KEY(user_id) REFERENCES user (id) - )""") + op.create_table( + 'process', + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('pid', sa.String(), nullable=False), + sa.Column('desc', sa.String(), nullable=False), + sa.Column('command', sa.String(), nullable=False), + sa.Column('arguments', sa.String()), + sa.Column('start_time', sa.String()), + sa.Column('end_time', sa.String()), + sa.Column('logdir', sa.String()), + sa.Column('exit_code', sa.Integer()), + sa.Column('acknowledge', sa.String()), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('pid')) if version < 11: - db.engine.execute(""" - UPDATE role - SET name = 'Administrator', - description = 'pgAdmin Administrator Role' - WHERE name = 'Administrators' - """) + # get metadata from current connection + meta = sa.MetaData(bind=op.get_bind()) + # define table representation + meta.reflect(only=('role',)) + role_table = sa.Table('role', meta) - db.engine.execute(""" - INSERT INTO role ( name, description ) - VALUES ('User', 'pgAdmin User Role') - """) + op.execute( + role_table.update().where(role_table.c.name == 'Administrators') + .values(name='Administrator', + description='pgAdmin Administrator Role')) - if version < 12: - db.engine.execute("create table server_old as select * from server") - - db.engine.execute("DROP TABLE server") - - db.engine.execute(""" - CREATE TABLE server ( - id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - servergroup_id INTEGER NOT NULL, - name VARCHAR(128) NOT NULL, - host VARCHAR(128) NOT NULL, - port INTEGER NOT NULL CHECK (port >= 1024 AND port <= 65535), - maintenance_db VARCHAR(64) NOT NULL, - username VARCHAR(64) NOT NULL, - ssl_mode VARCHAR(16) NOT NULL CHECK ( - ssl_mode IN ( - 'allow', 'prefer', 'require', 'disable', 'verify-ca', 'verify-full' - )), - comment VARCHAR(1024), password TEXT(64), role text(64), - PRIMARY KEY (id), - FOREIGN KEY(user_id) REFERENCES user (id), - FOREIGN KEY(servergroup_id) REFERENCES servergroup (id) - )""") - db.engine.execute(""" - INSERT INTO server ( - id, user_id, servergroup_id, name, host, port, maintenance_db, username, - ssl_mode, comment, password, role - ) SELECT - id, user_id, servergroup_id, name, host, port, maintenance_db, username, - ssl_mode, comment, password, role - FROM server_old""") - db.engine.execute("DROP TABLE server_old") + op.bulk_insert(role_table, + [{'name': 'User', 'description': 'pgAdmin User Role'}]) if version < 13: - db.engine.execute(""" - ALTER TABLE SERVER - ADD COLUMN discovery_id TEXT - """) + op.add_column('server', sa.Column('discovery_id', sa.String())) if version < 14: - db.engine.execute(""" - CREATE TABLE keys ( - name TEST NOT NULL, - value TEXT NOT NULL, - PRIMARY KEY (name)) - """) - - sql = "INSERT INTO keys (name, value) VALUES ('CSRF_SESSION_KEY', '%s')" % base64.urlsafe_b64encode( - os.urandom(32)).decode() - db.engine.execute(sql) + keys_table = op.create_table( + 'keys', + sa.Column('name', sa.String(), nullable=False), + sa.Column('value', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('name')) + secret_key = base64.urlsafe_b64encode(os.urandom(32)).decode() if hasattr(config, 'SECRET_KEY'): - sql = "INSERT INTO keys (name, value) VALUES ('SECRET_KEY', '%s')" % config.SECRET_KEY - else: - sql = "INSERT INTO keys (name, value) VALUES ('SECRET_KEY', '%s')" % base64.urlsafe_b64encode( - os.urandom(32)).decode() - db.engine.execute(sql) + secret_key = config.SECRET_KEY - # If SECURITY_PASSWORD_SALT is not in the config, but we're upgrading, then it must (unless the - # user edited the main config - which they shouldn't have done) have been at it's default - # value, so we'll use that. Otherwise, use whatever we can find in the config. + # If SECURITY_PASSWORD_SALT is not in the config, but we're upgrading, + # then it must (unless the user edited the main config - which they + # shouldn't have done) have been at it's default value, so we'll use + # that. Otherwise, use whatever we can find in the config. + security_password_salt = 'SuperSecret3' if hasattr(config, 'SECURITY_PASSWORD_SALT'): - sql = "INSERT INTO keys (name, value) VALUES ('SECURITY_PASSWORD_SALT', '%s')" % config.SECURITY_PASSWORD_SALT - else: - sql = "INSERT INTO keys (name, value) VALUES ('SECURITY_PASSWORD_SALT', 'SuperSecret3')" - db.engine.execute(sql) + security_password_salt = config.SECURITY_PASSWORD_SALT - db.engine.execute( - 'UPDATE version set value="%s" WHERE name = "ConfigDB"' % config.SETTINGS_SCHEMA_VERSION - ) + op.bulk_insert(keys_table, + [{'name': 'CSRF_SESSION_KEY', 'value': + base64.urlsafe_b64encode(os.urandom(32)).decode()}, + {'name': 'SECRET_KEY', 'value': secret_key}, + {'name': 'SECURITY_PASSWORD_SALT', + 'value': security_password_salt}]) + + # get metadata from current connection + meta = sa.MetaData(bind=op.get_bind()) + # define table representation + meta.reflect(only=('version',)) + version_table = sa.Table('version', meta) + + op.execute( + version_table.update().where(version_table.c.name == 'ConfigDB') + .values(value=config.SETTINGS_SCHEMA_VERSION)) # ### end Alembic commands ### diff --git a/web/migrations/versions/1586db67b98e_.py b/web/migrations/versions/1586db67b98e_.py index dfe043fab..775c7bb32 100644 --- a/web/migrations/versions/1586db67b98e_.py +++ b/web/migrations/versions/1586db67b98e_.py @@ -14,8 +14,8 @@ Revises: 15c88f765bc8 Create Date: 2022-01-04 13:08:05.484598 """ -from pgadmin.model import db - +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = '1586db67b98e' @@ -25,12 +25,10 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE process ADD COLUMN server_id INTEGER DEFAULT 0' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN cloud_status INTEGER DEFAULT 0' - ) + op.add_column('process', sa.Column('server_id', sa.Integer(), + server_default='0')) + op.add_column('server', sa.Column('cloud_status', sa.Integer(), + server_default='0')) def downgrade(): diff --git a/web/migrations/versions/15c88f765bc8_.py b/web/migrations/versions/15c88f765bc8_.py index 99340af0d..c4158dfed 100644 --- a/web/migrations/versions/15c88f765bc8_.py +++ b/web/migrations/versions/15c88f765bc8_.py @@ -16,8 +16,8 @@ Revises: 6650c52670c2 Create Date: 2021-11-24 17:33:12.533825 """ -from pgadmin.model import db - +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = '15c88f765bc8' @@ -27,15 +27,13 @@ depends_on = None def upgrade(): - db.engine.execute(""" -CREATE TABLE user_mfa( - user_id INTEGER NOT NULL, - mfa_auth VARCHAR(256) NOT NULL, - options TEXT, - PRIMARY KEY (user_id, mfa_auth), - FOREIGN KEY(user_id) REFERENCES user (id) -) - """) + op.create_table( + 'user_mfa', sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('mfa_auth', sa.String(length=256), nullable=False), + sa.Column('options', sa.String()), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('user_id', 'mfa_auth')) + # ### end Alembic commands ### diff --git a/web/migrations/versions/35f29b1701bd_.py b/web/migrations/versions/35f29b1701bd_.py index 0599a3434..046716ced 100644 --- a/web/migrations/versions/35f29b1701bd_.py +++ b/web/migrations/versions/35f29b1701bd_.py @@ -1,17 +1,20 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: 35f29b1701bd Revises: ec1cac3399c9 Create Date: 2019-04-26 16:38:08.368471 """ -import base64 -import os -import sys - -from pgadmin.model import db, Server - +from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = '35f29b1701bd' @@ -21,33 +24,12 @@ depends_on = None def upgrade(): - - db.engine.execute("create table user_old as select * from user") - - db.engine.execute("DROP TABLE user") - - db.engine.execute(""" - CREATE TABLE user ( - id INTEGER NOT NULL, - email VARCHAR(256) NOT NULL, - password VARCHAR(256), - active BOOLEAN NOT NULL, - confirmed_at DATETIME, - masterpass_check VARCHAR(256), - PRIMARY KEY (id), - UNIQUE (email), - CHECK (active IN (0, 1)) - ); - """) - - db.engine.execute(""" - INSERT INTO user ( - id, email, password, active, confirmed_at - ) SELECT - id, email, password, active, confirmed_at - FROM user_old""") - - db.engine.execute("DROP TABLE user_old") + op.add_column('user', sa.Column('masterpass_check', sa.String(length=256))) + with op.batch_alter_table("user") as batch_op: + batch_op.create_check_constraint( + "ck_active_range", + "active IN (true, false)" + ) def downgrade(): diff --git a/web/migrations/versions/398697dc9550_.py b/web/migrations/versions/398697dc9550_.py index 93b0eb735..09a4cec74 100644 --- a/web/migrations/versions/398697dc9550_.py +++ b/web/migrations/versions/398697dc9550_.py @@ -1,12 +1,20 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: 398697dc9550 Revises: a091c9611d20 Create Date: 2020-09-07 15:17:59.473879 """ -from pgadmin.model import db +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = '398697dc9550' @@ -16,39 +24,49 @@ depends_on = None def upgrade(): - db.engine.execute(""" - CREATE TABLE macros ( - id INTEGER NOT NULL, - alt BOOLEAN NOT NULL, - control BOOLEAN NOT NULL, - key VARCHAR(128) NOT NULL, - key_code INTEGER NOT NULL, - PRIMARY KEY(id) - ); - """) + macro_table = op.create_table( + 'macros', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('alt', sa.Boolean(), nullable=False), + sa.Column('control', sa.Boolean(), nullable=False), + sa.Column('key', sa.String(length=128), nullable=False), + sa.Column('key_code', sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint('id')) - db.engine.execute(""" - CREATE TABLE user_macros ( - mid INTEGER NOT NULL, - uid INTEGER NOT NULL, - name VARCHAR(1024) NOT NULL, - sql TEXT NOT NULL, - PRIMARY KEY(mid, uid), - FOREIGN KEY(mid) REFERENCES macros (id), - FOREIGN KEY(uid) REFERENCES user (id) - ); - """) + op.create_table( + 'user_macros', + sa.Column('mid', sa.Integer(), nullable=False), + sa.Column('uid', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=1024), nullable=False), + sa.Column('sql', sa.String()), + sa.ForeignKeyConstraint(['mid'], ['macros.id']), + sa.ForeignKeyConstraint(['uid'], ['user.id']), + sa.PrimaryKeyConstraint('mid', 'uid')) - db.engine.execute(""" - INSERT INTO macros (id, alt, control, key, key_code) VALUES (1, 0, 1, '1', 49), - (2, 0, 1, '2', 50), (3, 0, 1, '3', 51), (4, 0, 1, '4', 52), - (5, 0, 1, '5', 53), (6, 0, 1, '6', 54), (7, 0, 1, '7', 55), - (8, 0, 1, '8', 56), (9, 0, 1, '9', 57), (10, 0, 1, '0', 48), - (11, 1, 0, 'F1', 112), (12, 1, 0, 'F2', 113), (13, 1, 0, 'F3', 114), - (14, 1, 0, 'F4', 115), (15, 1, 0, 'F5', 116), (16, 1, 0, 'F6', 117), - (17, 1, 0, 'F7', 118), (18, 1, 0, 'F8', 119), (19, 1, 0, 'F9', 120), - (20, 1, 0, 'F10', 121), (21, 1, 0, 'F11', 122), (22, 1, 0, 'F12', 123); - """) + op.bulk_insert(macro_table, [ + {'alt': 0, 'control': 1, 'key': '1', 'key_code': 49}, + {'alt': 0, 'control': 1, 'key': '2', 'key_code': 50}, + {'alt': 0, 'control': 1, 'key': '3', 'key_code': 51}, + {'alt': 0, 'control': 1, 'key': '4', 'key_code': 52}, + {'alt': 0, 'control': 1, 'key': '5', 'key_code': 53}, + {'alt': 0, 'control': 1, 'key': '6', 'key_code': 54}, + {'alt': 0, 'control': 1, 'key': '7', 'key_code': 55}, + {'alt': 0, 'control': 1, 'key': '8', 'key_code': 56}, + {'alt': 0, 'control': 1, 'key': '9', 'key_code': 57}, + {'alt': 0, 'control': 1, 'key': '0', 'key_code': 48}, + {'alt': 1, 'control': 0, 'key': 'F1', 'key_code': 112}, + {'alt': 1, 'control': 0, 'key': 'F2', 'key_code': 113}, + {'alt': 1, 'control': 0, 'key': 'F3', 'key_code': 114}, + {'alt': 1, 'control': 0, 'key': 'F4', 'key_code': 115}, + {'alt': 1, 'control': 0, 'key': 'F5', 'key_code': 116}, + {'alt': 1, 'control': 0, 'key': 'F6', 'key_code': 117}, + {'alt': 1, 'control': 0, 'key': 'F7', 'key_code': 118}, + {'alt': 1, 'control': 0, 'key': 'F8', 'key_code': 119}, + {'alt': 1, 'control': 0, 'key': 'F9', 'key_code': 120}, + {'alt': 1, 'control': 0, 'key': 'F10', 'key_code': 121}, + {'alt': 1, 'control': 0, 'key': 'F11', 'key_code': 122}, + {'alt': 1, 'control': 0, 'key': 'F12', 'key_code': 123} + ]) def downgrade(): diff --git a/web/migrations/versions/3c1e4b6eda55_.py b/web/migrations/versions/3c1e4b6eda55_.py index aa4018a77..843a290cf 100644 --- a/web/migrations/versions/3c1e4b6eda55_.py +++ b/web/migrations/versions/3c1e4b6eda55_.py @@ -1,5 +1,12 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: 3c1e4b6eda55 Revises: 09d53fca90c7 @@ -7,7 +14,8 @@ Create Date: 2017-06-13 17:05:30.671859 """ -from pgadmin.model import db +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = '3c1e4b6eda55' @@ -17,9 +25,7 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN hostaddr TEXT(1024)' - ) + op.add_column('server', sa.Column('hostaddr', sa.String(length=1024))) def downgrade(): diff --git a/web/migrations/versions/3ce25f562f3b_.py b/web/migrations/versions/3ce25f562f3b_.py index 1c2dff929..566fd7cfc 100644 --- a/web/migrations/versions/3ce25f562f3b_.py +++ b/web/migrations/versions/3ce25f562f3b_.py @@ -7,14 +7,13 @@ # ########################################################################## -"""empty message +""" Revision ID: 3ce25f562f3b Revises: 6650c52670c2 Create Date: 2021-12-01 11:52:09.037749 """ -from pgadmin.model import db # revision identifiers, used by Alembic. revision = '3ce25f562f3b' @@ -24,18 +23,8 @@ depends_on = None def upgrade(): - # Rename user table to user_old and again user_old to user to change - # the foreign key refernce of user_old table which is not exists - - db.engine.execute("ALTER TABLE user RENAME TO user_old") - - db.engine.execute("ALTER TABLE user_old RENAME TO user") - - # Rename server table to server_old and again server_old to server to change - # the foreign key refernce of server_old table which is not exists - db.engine.execute("ALTER TABLE server RENAME TO server_old") - - db.engine.execute("ALTER TABLE server_old RENAME TO server") + # After using alembic the old logic is not required. + pass def downgrade(): diff --git a/web/migrations/versions/493cd3e39c0c_.py b/web/migrations/versions/493cd3e39c0c_.py index 371ec4fb6..4dad6c194 100644 --- a/web/migrations/versions/493cd3e39c0c_.py +++ b/web/migrations/versions/493cd3e39c0c_.py @@ -1,5 +1,12 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: 493cd3e39c0c Revises: 7c56ea250085 @@ -8,8 +15,6 @@ Create Date: 2018-06-18 11:26:33.285037 """ from alembic import op import sqlalchemy as sa -from pgadmin.model import db - # revision identifiers, used by Alembic. revision = '493cd3e39c0c' @@ -19,9 +24,8 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN connect_timeout INTEGER DEFAULT 0' - ) + op.add_column('server', sa.Column('connect_timeout', sa.Integer(), + server_default='0')) def downgrade(): diff --git a/web/migrations/versions/50aad68f99c2_.py b/web/migrations/versions/50aad68f99c2_.py index a308dc34f..6d7cca170 100644 --- a/web/migrations/versions/50aad68f99c2_.py +++ b/web/migrations/versions/50aad68f99c2_.py @@ -1,4 +1,11 @@ - +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## """Added service field option in server table (RM#3140) Revision ID: 50aad68f99c2 @@ -6,8 +13,8 @@ Revises: 02b9dccdcfcb Create Date: 2018-03-07 11:53:57.584280 """ -from pgadmin.model import db - +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = '50aad68f99c2' @@ -17,69 +24,10 @@ depends_on = None def upgrade(): - # To Save previous data, create temp table - - db.engine.execute("create table server_old as select * from server") - - db.engine.execute("DROP TABLE server") - - # With service file some fields won't be mandatory as user can provide - # them using service file. Removed NOT NULL constraint from few columns - db.engine.execute(""" - CREATE TABLE server ( - id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - servergroup_id INTEGER NOT NULL, - name VARCHAR(128) NOT NULL, - host VARCHAR(128), - port INTEGER NOT NULL CHECK(port >= 1024 AND port <= 65534), - maintenance_db VARCHAR(64), - username VARCHAR(64) NOT NULL, - password VARCHAR(64), - role VARCHAR(64), - ssl_mode VARCHAR(16) NOT NULL CHECK(ssl_mode IN - ( 'allow' , 'prefer' , 'require' , 'disable' , - 'verify-ca' , 'verify-full' ) - ), - comment VARCHAR(1024), - discovery_id VARCHAR(128), - hostaddr TEXT(1024), - db_res TEXT, - passfile TEXT, - sslcert TEXT, - sslkey TEXT, - sslrootcert TEXT, - sslcrl TEXT, - sslcompression INTEGER DEFAULT 0, - bgcolor TEXT(10), - fgcolor TEXT(10), - PRIMARY KEY(id), - FOREIGN KEY(user_id) REFERENCES user(id), - FOREIGN KEY(servergroup_id) REFERENCES servergroup(id) - ) - """) - - # Copy old data again into table - db.engine.execute(""" - INSERT INTO server ( - id,user_id, servergroup_id, name, host, port, maintenance_db, - username, ssl_mode, comment, password, role, discovery_id, - hostaddr, db_res, passfile, sslcert, sslkey, sslrootcert, sslcrl, - bgcolor, fgcolor - ) SELECT - id,user_id, servergroup_id, name, host, port, maintenance_db, - username, ssl_mode, comment, password, role, discovery_id, - hostaddr, db_res, passfile, sslcert, sslkey, sslrootcert, sslcrl, - bgcolor, fgcolor - FROM server_old""") - - # Remove old data - db.engine.execute("DROP TABLE server_old") - - # Add column for Service - db.engine.execute( - 'ALTER TABLE server ADD COLUMN service TEXT' - ) + op.add_column('server', sa.Column('service', sa.String())) + with op.batch_alter_table("server") as batch_op: + batch_op.alter_column('host', nullable=True) + batch_op.alter_column('maintenance_db', nullable=True) def downgrade(): diff --git a/web/migrations/versions/6650c52670c2_.py b/web/migrations/versions/6650c52670c2_.py index 585b43676..b0aa895b6 100644 --- a/web/migrations/versions/6650c52670c2_.py +++ b/web/migrations/versions/6650c52670c2_.py @@ -17,10 +17,7 @@ Create Date: 2021-07-10 18:12:38.821602 from alembic import op import sqlalchemy as sa - # revision identifiers, used by Alembic. -from pgadmin import db - revision = '6650c52670c2' down_revision = 'c465fee44968' branch_labels = None @@ -28,12 +25,10 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE user ADD COLUMN locked BOOLEAN DEFAULT FALSE' - ) - db.engine.execute( - 'ALTER TABLE user ADD COLUMN login_attempts int DEFAULT 0' - ) + op.add_column('user', sa.Column('locked', sa.Boolean(), + server_default='false')) + op.add_column('user', sa.Column('login_attempts', sa.Integer(), + server_default='0')) def downgrade(): diff --git a/web/migrations/versions/7c56ea250085_.py b/web/migrations/versions/7c56ea250085_.py index 7d0b6f647..9ced14af9 100644 --- a/web/migrations/versions/7c56ea250085_.py +++ b/web/migrations/versions/7c56ea250085_.py @@ -1,4 +1,11 @@ - +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## """Change server port constraint to allow port below 1024 RM#3307 Revision ID: 7c56ea250085 @@ -7,9 +14,6 @@ Create Date: 2018-06-04 14:23:31.472645 """ from alembic import op -import sqlalchemy as sa - -from pgadmin.model import db # revision identifiers, used by Alembic. revision = '7c56ea250085' @@ -19,75 +23,12 @@ depends_on = None def upgrade(): - # To Save previous data, create temp table - - db.engine.execute("create table server_old as select * from server") - - db.engine.execute("DROP TABLE server") - - # Create table with new constraint definition - db.engine.execute(""" - CREATE TABLE server ( - id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - servergroup_id INTEGER NOT NULL, - name VARCHAR(128) NOT NULL, - host VARCHAR(128), - port INTEGER NOT NULL CHECK(port >= 1 AND port <= 65534), - maintenance_db VARCHAR(64), - username VARCHAR(64) NOT NULL, - password VARCHAR(64), - role VARCHAR(64), - ssl_mode VARCHAR(16) NOT NULL CHECK(ssl_mode IN - ( 'allow' , 'prefer' , 'require' , 'disable' , - 'verify-ca' , 'verify-full' ) - ), - comment VARCHAR(1024), - discovery_id VARCHAR(128), - hostaddr TEXT(1024), - db_res TEXT, - passfile TEXT, - sslcert TEXT, - sslkey TEXT, - sslrootcert TEXT, - sslcrl TEXT, - sslcompression INTEGER DEFAULT 0, - bgcolor TEXT(10), - fgcolor TEXT(10), - service TEXT, - use_ssh_tunnel INTEGER DEFAULT 0, - tunnel_host TEXT, - tunnel_port TEXT, - tunnel_username TEXT, - tunnel_authentication INTEGER DEFAULT 0, - tunnel_identity_file TEXT, - PRIMARY KEY(id), - FOREIGN KEY(user_id) REFERENCES user(id), - FOREIGN KEY(servergroup_id) REFERENCES servergroup(id) + with op.batch_alter_table("server") as batch_op: + batch_op.drop_constraint('ck_port_range') + batch_op.create_check_constraint( + "ck_port_range", + "port >= 1 AND port <= 65535" ) - """) - - # Copy old data again into table - db.engine.execute(""" - INSERT INTO server ( - id, user_id, servergroup_id, name, host, port, maintenance_db, - username, password, role, ssl_mode, comment, discovery_id, hostaddr, - db_res, passfile, sslcert, sslkey, sslrootcert, sslcrl, - sslcompression, bgcolor, fgcolor, service, use_ssh_tunnel, - tunnel_host, tunnel_port, tunnel_username, tunnel_authentication, - tunnel_identity_file - - ) SELECT - id, user_id, servergroup_id, name, host, port, maintenance_db, - username, password, role, ssl_mode, comment, discovery_id, hostaddr, - db_res, passfile, sslcert, sslkey, sslrootcert, sslcrl, - sslcompression, bgcolor, fgcolor, service, use_ssh_tunnel, - tunnel_host, tunnel_port, tunnel_username, tunnel_authentication, - tunnel_identity_file - FROM server_old""") - - # Remove old data - db.engine.execute("DROP TABLE server_old") def downgrade(): diff --git a/web/migrations/versions/7fedf8531802_.py b/web/migrations/versions/7fedf8531802_.py index 222f59d8e..9a7d6683b 100644 --- a/web/migrations/versions/7fedf8531802_.py +++ b/web/migrations/versions/7fedf8531802_.py @@ -1,5 +1,12 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: 7fedf8531802 Revises: aff1436e3c8c @@ -8,7 +15,6 @@ Create Date: 2020-02-26 11:24:54.353288 """ from alembic import op import sqlalchemy as sa -from pgadmin.model import db # revision identifiers, used by Alembic. revision = '7fedf8531802' @@ -18,35 +24,25 @@ depends_on = None def upgrade(): + op.add_column('user', sa.Column('username', sa.String(length=256), + nullable=False, server_default='')) + op.add_column('user', sa.Column('auth_source', sa.String(length=256), + nullable=False, server_default='internal')) + with op.batch_alter_table("user") as batch_op: + batch_op.alter_column('email', nullable=True) + batch_op.drop_constraint('user_unique_constraint') + batch_op.create_unique_constraint('user_unique_constraint', + ['username', 'auth_source']) - db.engine.execute("create table user_old as select * from user") + # For internal email is a user name, so update the existing records. + meta = sa.MetaData(bind=op.get_bind()) + # define table representation + meta.reflect(only=('user',)) + user_table = sa.Table('user', meta) - db.engine.execute("DROP TABLE user") - - db.engine.execute(""" - CREATE TABLE user ( - id INTEGER NOT NULL, - username VARCHAR(256) NOT NULL, - email VARCHAR(256), - password VARCHAR(256), - active BOOLEAN NOT NULL, - confirmed_at DATETIME, - masterpass_check VARCHAR(256), - auth_source VARCHAR(256) NOT NULL DEFAULT 'internal', - PRIMARY KEY (id), - UNIQUE (username, auth_source), - CHECK (active IN (0, 1)) - ); - """) - - db.engine.execute(""" - INSERT INTO user ( - id, username, email, password, active, confirmed_at, masterpass_check - ) SELECT - id, email, email, password, active, confirmed_at, masterpass_check - FROM user_old""") - - db.engine.execute("DROP TABLE user_old") + op.execute( + user_table.update().values(username=user_table.c.email) + ) def downgrade(): diff --git a/web/migrations/versions/81c7ffeffeee_.py b/web/migrations/versions/81c7ffeffeee_.py index c4cd78da9..1ee1f2478 100644 --- a/web/migrations/versions/81c7ffeffeee_.py +++ b/web/migrations/versions/81c7ffeffeee_.py @@ -1,5 +1,12 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: 81c7ffeffeee Revises: 398697dc9550 @@ -7,8 +14,8 @@ Create Date: 2020-11-02 09:46:51.250338 """ from alembic import op -import sqlalchemy as sa -from pgadmin.model import db, Preferences +from sqlalchemy.orm.session import Session +from pgadmin.model import Preferences # revision identifiers, used by Alembic. @@ -23,22 +30,22 @@ def upgrade(): Delete older preferences open new tab for Query tool, Debugger, and Schema diff. """ - qt_open_tab_setting = Preferences.query.filter_by( + session = Session(bind=op.get_bind()) + + qt_open_tab_setting = session.query(Preferences).filter_by( name='new_browser_tab').order_by(Preferences.id.desc()).first() - debugger_tab_setting = Preferences.query.filter_by( + debugger_tab_setting = session.query(Preferences).filter_by( name='debugger_new_browser_tab').order_by(Preferences.id.desc()).first() - schema_diff_tab_setting = Preferences.query.filter_by( + schema_diff_tab_setting = session.query(Preferences).filter_by( name='schema_diff_new_browser_tab').order_by( Preferences.id.desc()).first() if qt_open_tab_setting: - db.session.delete(qt_open_tab_setting) + session.delete(qt_open_tab_setting) if debugger_tab_setting: - db.session.delete(debugger_tab_setting) + session.delete(debugger_tab_setting) if schema_diff_tab_setting: - db.session.delete(schema_diff_tab_setting) - - db.session.commit() + session.delete(schema_diff_tab_setting) def downgrade(): diff --git a/web/migrations/versions/84700139beb0_.py b/web/migrations/versions/84700139beb0_.py index 10f26a98e..ead238425 100644 --- a/web/migrations/versions/84700139beb0_.py +++ b/web/migrations/versions/84700139beb0_.py @@ -1,13 +1,20 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: 84700139beb0 Revises: d39482714a2e Create Date: 2020-06-24 15:53:56.489518 """ -from pgadmin.model import db - +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = '84700139beb0' @@ -17,15 +24,13 @@ depends_on = None def upgrade(): - db.engine.execute(""" - CREATE TABLE "database" ( - "id" INTEGER NOT NULL, - "schema_res" TEXT, - "server" INTEGER NOT NULL, - PRIMARY KEY("id","server"), - FOREIGN KEY("server") REFERENCES "server"("id") - ); - """) + op.create_table( + 'database', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('schema_res', sa.String()), + sa.Column('server', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['server'], ['server.id'], ), + sa.PrimaryKeyConstraint('id', 'server')) def downgrade(): diff --git a/web/migrations/versions/a091c9611d20_.py b/web/migrations/versions/a091c9611d20_.py index c8174f5e4..749935316 100644 --- a/web/migrations/versions/a091c9611d20_.py +++ b/web/migrations/versions/a091c9611d20_.py @@ -1,13 +1,20 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: a091c9611d20 Revises: 84700139beb0 Create Date: 2020-07-14 17:20:22.705737 """ -from pgadmin.model import db - +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = 'a091c9611d20' @@ -17,55 +24,54 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN shared BOOLEAN' - ) + op.add_column('server', sa.Column('shared', sa.Boolean())) + op.create_table( + 'sharedserver', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('server_owner', sa.String(length=64)), + sa.Column('servergroup_id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=128), nullable=False), + sa.Column('host', sa.String(length=128)), + sa.Column('port', sa.Integer(), nullable=False), + sa.Column('maintenance_db', sa.String(length=64)), + sa.Column('username', sa.String(length=64)), + sa.Column('password', sa.String(length=64)), + sa.Column('role', sa.String(length=64)), + sa.Column('ssl_mode', sa.String(length=16), nullable=False), + sa.Column('comment', sa.String(length=1024)), + sa.Column('discovery_id', sa.String(length=128)), + sa.Column('hostaddr', sa.String(length=1024)), + sa.Column('db_res', sa.String()), + sa.Column('passfile', sa.String()), + sa.Column('sslcert', sa.String()), + sa.Column('sslkey', sa.String()), + sa.Column('sslrootcert', sa.String()), + sa.Column('sslcrl', sa.String()), + sa.Column('sslcompression', sa.Integer(), server_default='0'), + sa.Column('bgcolor', sa.String(length=10)), + sa.Column('fgcolor', sa.String(length=10)), + sa.Column('service', sa.String()), + sa.Column('use_ssh_tunnel', sa.Integer(), server_default='0'), + sa.Column('tunnel_host', sa.String()), + sa.Column('tunnel_port', sa.String()), + sa.Column('tunnel_username', sa.String()), + sa.Column('tunnel_authentication', sa.Integer(), server_default='0'), + sa.Column('tunnel_identity_file', sa.String()), + sa.Column('shared', sa.Boolean(), nullable=False), + sa.Column('save_password', sa.Boolean(), nullable=False), + sa.Column('tunnel_password', sa.String(length=64)), + sa.Column('connect_timeout', sa.Integer()), + sa.CheckConstraint("ssl_mode IN ('allow', 'prefer', 'require', \ + 'disable', 'verify-ca', 'verify-full')"), + sa.ForeignKeyConstraint(['servergroup_id'], ['servergroup.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('id')) - db.engine.execute(""" - CREATE TABLE sharedserver ( - id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - server_owner VARCHAR(64), - servergroup_id INTEGER NOT NULL, - name VARCHAR(128) NOT NULL, - host VARCHAR(128), - port INTEGER NOT NULL CHECK(port >= 1 AND port <= 65534), - maintenance_db VARCHAR(64), - username VARCHAR(64), - password VARCHAR(64), - role VARCHAR(64), - ssl_mode VARCHAR(16) NOT NULL CHECK(ssl_mode IN - ( 'allow' , 'prefer' , 'require' , 'disable' , - 'verify-ca' , 'verify-full' ) - ), - comment VARCHAR(1024), - discovery_id VARCHAR(128), - hostaddr TEXT(1024), - db_res TEXT, - passfile TEXT, - sslcert TEXT, - sslkey TEXT, - sslrootcert TEXT, - sslcrl TEXT, - sslcompression INTEGER DEFAULT 0, - bgcolor TEXT(10), - fgcolor TEXT(10), - service TEXT, - use_ssh_tunnel INTEGER DEFAULT 0, - tunnel_host TEXT, - tunnel_port TEXT, - tunnel_username TEXT, - tunnel_authentication INTEGER DEFAULT 0, - tunnel_identity_file TEXT, - shared BOOLEAN NOT NULL, - save_password BOOLEAN NOT NULL, - tunnel_password VARCHAR(64), - connect_timeout INTEGER , - PRIMARY KEY(id), - FOREIGN KEY(user_id) REFERENCES user(id), - FOREIGN KEY(servergroup_id) REFERENCES servergroup(id) - ); - """) + # Named constraint + with op.batch_alter_table("sharedserver") as batch_op: + batch_op.create_check_constraint('ck_shared_server_port', + 'port >= 1024 AND port <= 65535') def downgrade(): diff --git a/web/migrations/versions/a39bd015b644_.py b/web/migrations/versions/a39bd015b644_.py index a6f2796e1..8c34ec466 100644 --- a/web/migrations/versions/a39bd015b644_.py +++ b/web/migrations/versions/a39bd015b644_.py @@ -1,13 +1,19 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: a39bd015b644 Revises: 81c7ffeffeee Create Date: 2021-01-12 15:46:49.283021 """ -from pgadmin.model import db - +from alembic import op # revision identifiers, used by Alembic. revision = 'a39bd015b644' @@ -17,84 +23,10 @@ depends_on = None def upgrade(): - - # To Save previous data, create temp table - - db.engine.execute("create table sharedserver_old as " - "select * from sharedserver") - - db.engine.execute("DROP TABLE sharedserver") - - # Create new table with removed not null constraints for port column. - db.engine.execute(""" - CREATE TABLE sharedserver ( - id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - server_owner VARCHAR(64), - servergroup_id INTEGER NOT NULL, - name VARCHAR(128) NOT NULL, - host VARCHAR(128), - port INTEGER, - maintenance_db VARCHAR(64), - username VARCHAR(64), - password VARCHAR(64), - role VARCHAR(64), - ssl_mode VARCHAR(16) NOT NULL CHECK(ssl_mode IN - ( 'allow' , 'prefer' , 'require' , 'disable' , - 'verify-ca' , 'verify-full' ) - ), - comment VARCHAR(1024), - discovery_id VARCHAR(128), - hostaddr TEXT(1024), - db_res TEXT, - passfile TEXT, - sslcert TEXT, - sslkey TEXT, - sslrootcert TEXT, - sslcrl TEXT, - sslcompression INTEGER DEFAULT 0, - bgcolor TEXT(10), - fgcolor TEXT(10), - service TEXT, - use_ssh_tunnel INTEGER DEFAULT 0, - tunnel_host TEXT, - tunnel_port TEXT, - tunnel_username TEXT, - tunnel_authentication INTEGER DEFAULT 0, - tunnel_identity_file TEXT, - shared BOOLEAN NOT NULL, - save_password BOOLEAN NOT NULL, - tunnel_password VARCHAR(64), - connect_timeout INTEGER , - PRIMARY KEY(id), - FOREIGN KEY(user_id) REFERENCES user(id), - FOREIGN KEY(servergroup_id) REFERENCES servergroup(id) - ); - """) - - # Copy old data again into table. - db.engine.execute(""" - INSERT INTO sharedserver ( - id, user_id, server_owner, servergroup_id, name, host, port, - maintenance_db, username, password, role, ssl_mode, comment, - discovery_id, hostaddr, db_res, passfile, sslcert, sslkey, - sslrootcert, sslcrl, sslcompression, bgcolor, fgcolor, service, - use_ssh_tunnel, tunnel_host, tunnel_port, tunnel_username, - tunnel_authentication, tunnel_identity_file, shared, save_password, - tunnel_password, connect_timeout - - ) SELECT - id, user_id, server_owner, servergroup_id, name, host, port, - maintenance_db, username, password, role, ssl_mode, comment, - discovery_id, hostaddr, db_res, passfile, sslcert, sslkey, - sslrootcert, sslcrl, sslcompression, bgcolor, fgcolor, service, - use_ssh_tunnel, tunnel_host, tunnel_port, tunnel_username, - tunnel_authentication, tunnel_identity_file, shared, save_password, - tunnel_password, connect_timeout - FROM sharedserver_old""") - - # Drop older table. - db.engine.execute("DROP TABLE sharedserver_old") + with op.batch_alter_table("sharedserver") as batch_op: + batch_op.drop_constraint('ck_shared_server_port') + batch_op.alter_column('port', nullable=True) + batch_op.alter_column('maintenance_db', nullable=True) def downgrade(): diff --git a/web/migrations/versions/a68b374fe373_.py b/web/migrations/versions/a68b374fe373_.py index 1db15d658..642b28c16 100644 --- a/web/migrations/versions/a68b374fe373_.py +++ b/web/migrations/versions/a68b374fe373_.py @@ -1,4 +1,11 @@ - +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## """Added columns for SSH tunneling Revision ID: a68b374fe373 @@ -8,7 +15,6 @@ Create Date: 2018-04-05 13:59:57.588355 """ from alembic import op import sqlalchemy as sa -from pgadmin.model import db # revision identifiers, used by Alembic. revision = 'a68b374fe373' @@ -18,24 +24,14 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN use_ssh_tunnel INTEGER DEFAULT 0' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN tunnel_host TEXT' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN tunnel_port TEXT' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN tunnel_username TEXT' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN tunnel_authentication INTEGER DEFAULT 0' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN tunnel_identity_file TEXT' - ) + op.add_column('server', sa.Column('use_ssh_tunnel', sa.Integer(), + server_default='0')) + op.add_column('server', sa.Column('tunnel_host', sa.String())) + op.add_column('server', sa.Column('tunnel_port', sa.String())) + op.add_column('server', sa.Column('tunnel_username', sa.String())) + op.add_column('server', sa.Column('tunnel_authentication', sa.Integer(), + server_default='0')) + op.add_column('server', sa.Column('tunnel_identity_file', sa.String())) def downgrade(): diff --git a/web/migrations/versions/a77a0932a568_.py b/web/migrations/versions/a77a0932a568_.py index ff7fa392c..03702fee0 100644 --- a/web/migrations/versions/a77a0932a568_.py +++ b/web/migrations/versions/a77a0932a568_.py @@ -1,4 +1,11 @@ - +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## """Change the not null constraints for port, username as it should not compulsory when service is provided. RM #4642 @@ -8,8 +15,6 @@ Create Date: 2019-09-09 15:41:30.084753 """ from alembic import op -import sqlalchemy as sa -from pgadmin.model import db # revision identifiers, used by Alembic. revision = 'a77a0932a568' @@ -19,74 +24,11 @@ depends_on = None def upgrade(): - # To Save previous data, create temp table - db.engine.execute("create table server_old as select * from server") - - db.engine.execute("DROP TABLE server") - - # Create table with drop constraint for port and username definition - db.engine.execute(""" - CREATE TABLE server ( - id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - servergroup_id INTEGER NOT NULL, - name VARCHAR(128) NOT NULL, - host VARCHAR(128), - port INTEGER, - maintenance_db VARCHAR(64) NOT NULL, - username VARCHAR(64), - password VARCHAR(64), - role VARCHAR(64), - ssl_mode VARCHAR(16) NOT NULL CHECK(ssl_mode IN - ( 'allow' , 'prefer' , 'require' , 'disable' , - 'verify-ca' , 'verify-full' ) - ), - comment VARCHAR(1024), - discovery_id VARCHAR(128), - hostaddr TEXT(1024), - db_res TEXT, - passfile TEXT, - sslcert TEXT, - sslkey TEXT, - sslrootcert TEXT, - sslcrl TEXT, - sslcompression INTEGER DEFAULT 0, - bgcolor TEXT(10), - fgcolor TEXT(10), - service TEXT, - use_ssh_tunnel INTEGER DEFAULT 0, - tunnel_host TEXT, - tunnel_port TEXT, - tunnel_username TEXT, - tunnel_authentication INTEGER DEFAULT 0, - tunnel_identity_file TEXT, connect_timeout INTEGER DEFAULT 0, tunnel_password TEXT(64), - PRIMARY KEY(id), - FOREIGN KEY(user_id) REFERENCES user(id), - FOREIGN KEY(servergroup_id) REFERENCES servergroup(id) - ) - """) - - # Copy old data again into table - db.engine.execute(""" - INSERT INTO server ( - id, user_id, servergroup_id, name, host, port, maintenance_db, - username, password, role, ssl_mode, comment, discovery_id, hostaddr, - db_res, passfile, sslcert, sslkey, sslrootcert, sslcrl, - sslcompression, bgcolor, fgcolor, service, use_ssh_tunnel, - tunnel_host, tunnel_port, tunnel_username, tunnel_authentication, - tunnel_identity_file - - ) SELECT - id, user_id, servergroup_id, name, host, port, maintenance_db, - username, password, role, ssl_mode, comment, discovery_id, hostaddr, - db_res, passfile, sslcert, sslkey, sslrootcert, sslcrl, - sslcompression, bgcolor, fgcolor, service, use_ssh_tunnel, - tunnel_host, tunnel_port, tunnel_username, tunnel_authentication, - tunnel_identity_file - FROM server_old""") - - # Remove old data - db.engine.execute("DROP TABLE server_old") + # Port and Username can be null if service is provided. + with op.batch_alter_table("server") as batch_op: + batch_op.drop_constraint('ck_port_range') + batch_op.alter_column('port', nullable=True) + batch_op.alter_column('username', nullable=True) def downgrade(): diff --git a/web/migrations/versions/aa86fb60b73d_.py b/web/migrations/versions/aa86fb60b73d_.py index bb257cb1e..b0f4b8e28 100644 --- a/web/migrations/versions/aa86fb60b73d_.py +++ b/web/migrations/versions/aa86fb60b73d_.py @@ -13,7 +13,8 @@ Revises: 493cd3e39c0c Create Date: 2018-07-26 11:19:50.879849 """ -from pgadmin.model import db +from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'aa86fb60b73d' @@ -23,9 +24,7 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN tunnel_password TEXT(64)' - ) + op.add_column('server', sa.Column('tunnel_password', sa.String(length=64))) def downgrade(): diff --git a/web/migrations/versions/aff1436e3c8c_.py b/web/migrations/versions/aff1436e3c8c_.py index 7be0428a7..57d3f2732 100644 --- a/web/migrations/versions/aff1436e3c8c_.py +++ b/web/migrations/versions/aff1436e3c8c_.py @@ -1,4 +1,11 @@ - +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## """ Update the default timeout to 10 seconds instead on 0. 0 indicates wait indefinitely which causes trouble when network connection to server is lost. @@ -8,7 +15,8 @@ Revises: a77a0932a568 Create Date: 2019-10-28 12:47:36.828709 """ -from pgadmin.model import db +from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'aff1436e3c8c' @@ -18,8 +26,15 @@ depends_on = None def upgrade(): - db.engine.execute( - 'UPDATE server SET connect_timeout=10 WHERE connect_timeout=0 OR connect_timeout IS NULL' + # get metadata from current connection + meta = sa.MetaData(bind=op.get_bind()) + # define table representation + meta.reflect(only=('server',)) + server_table = sa.Table('server', meta) + op.execute( + server_table.update().where(server_table.c.connect_timeout == 0 or + server_table.c.connect_timeout is None) + .values(connect_timeout=10) ) diff --git a/web/migrations/versions/b5b87fdfcb30_.py b/web/migrations/versions/b5b87fdfcb30_.py index d17767c42..25df5c21d 100644 --- a/web/migrations/versions/b5b87fdfcb30_.py +++ b/web/migrations/versions/b5b87fdfcb30_.py @@ -14,7 +14,8 @@ Revises: ece2e76bf60e Create Date: 2018-10-24 12:37:59.487969 """ -from pgadmin.model import db +from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'b5b87fdfcb30' @@ -24,9 +25,8 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE process ADD COLUMN process_state INTEGER DEFAULT 0' - ) + op.add_column('process', sa.Column('process_state', sa.Integer(), + server_default='0')) def downgrade(): diff --git a/web/migrations/versions/c465fee44968_.py b/web/migrations/versions/c465fee44968_.py index de5b763d2..e07676790 100644 --- a/web/migrations/versions/c465fee44968_.py +++ b/web/migrations/versions/c465fee44968_.py @@ -1,13 +1,20 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: c465fee44968 Revises: d0bc9f32b2b9 Create Date: 2021-06-04 14:42:12.843116 """ -from pgadmin.model import db, User -from sqlalchemy.sql import text +from alembic import op +import sqlalchemy as sa import uuid @@ -19,46 +26,20 @@ depends_on = None def upgrade(): + op.add_column('user', sa.Column('fs_uniquifier', sa.String(), + nullable=True)) - db.engine.execute("create table user_old as select * from user") + meta = sa.MetaData(bind=op.get_bind()) + # define table representation + meta.reflect(only=('user',)) + user_table = sa.Table('user', meta) - db.engine.execute("DROP TABLE user") + op.execute( + user_table.update().values(fs_uniquifier=uuid.uuid4().hex) + ) + with op.batch_alter_table("user") as batch_op: + batch_op.alter_column('fs_uniquifier', nullable=False) - db.engine.execute(""" - CREATE TABLE user ( - id INTEGER NOT NULL, - username VARCHAR(256) NOT NULL, - email VARCHAR(256), - password VARCHAR(256), - active BOOLEAN NOT NULL, - confirmed_at DATETIME, - masterpass_check VARCHAR(256), - auth_source VARCHAR(256) NOT NULL DEFAULT 'internal', - fs_uniquifier NOT NULL UNIQUE, - PRIMARY KEY (id), - UNIQUE (username, auth_source), - CHECK (active IN (0, 1)) - ); - """) - - user_old = db.engine.execute( - 'select id, username, email, password, active, ' - 'confirmed_at, masterpass_check, auth_source ' - 'from user_old') - - statement = text(""" - INSERT INTO user(id, username, email, password, active, - confirmed_at, masterpass_check, auth_source, fs_uniquifier) - VALUES(:id, :username, :email, :password, :active, :confirmed_at, - :masterpass_check, :auth_source, :fs_uniquifier)""") - db.engine.execute(statement, [ - { - **row, - 'fs_uniquifier': uuid.uuid4().hex - } for row in user_old - ]) - - db.engine.execute("DROP TABLE user_old") def downgrade(): # pgAdmin only upgrades, downgrade not implemented. diff --git a/web/migrations/versions/c6974f64df08_.py b/web/migrations/versions/c6974f64df08_.py index 277853631..0a680ff10 100644 --- a/web/migrations/versions/c6974f64df08_.py +++ b/web/migrations/versions/c6974f64df08_.py @@ -1,13 +1,20 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: c6974f64df08 Revises: a39bd015b644 Create Date: 2021-04-22 10:06:21.282770 """ -from pgadmin.model import db - +from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. @@ -18,9 +25,7 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE sharedserver ADD COLUMN osid INTEGER' - ) + op.add_column('sharedserver', sa.Column('osid', sa.Integer())) def downgrade(): diff --git a/web/migrations/versions/ca00ec32581b_.py b/web/migrations/versions/ca00ec32581b_.py index ae93c75a0..8e7a3d626 100644 --- a/web/migrations/versions/ca00ec32581b_.py +++ b/web/migrations/versions/ca00ec32581b_.py @@ -14,8 +14,9 @@ Revises: aa86fb60b73d Create Date: 2018-08-29 15:33:57.855491 """ - -from pgadmin.model import db +from alembic import op +from sqlalchemy.orm.session import Session +from pgadmin.model import DebuggerFunctionArguments # revision identifiers, used by Alembic. revision = 'ca00ec32581b' @@ -25,9 +26,11 @@ depends_on = None def upgrade(): - db.engine.execute( - 'DELETE FROM debugger_function_arguments' - ) + session = Session(bind=op.get_bind()) + + debugger_records = session.query(DebuggerFunctionArguments).all() + if debugger_records: + session.delete(debugger_records) def downgrade(): diff --git a/web/migrations/versions/d0bc9f32b2b9_.py b/web/migrations/versions/d0bc9f32b2b9_.py index 266b6d899..c6dc5ef3a 100644 --- a/web/migrations/versions/d0bc9f32b2b9_.py +++ b/web/migrations/versions/d0bc9f32b2b9_.py @@ -1,5 +1,12 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: d0bc9f32b2b9 Revises: c6974f64df08 @@ -8,7 +15,6 @@ Create Date: 2021-04-27 12:40:08.899712 """ from alembic import op import sqlalchemy as sa -from pgadmin.model import db # revision identifiers, used by Alembic. revision = 'd0bc9f32b2b9' @@ -18,9 +24,8 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN kerberos_conn INTEGER DEFAULT 0' - ) + op.add_column('server', sa.Column('kerberos_conn', sa.Boolean(), + server_default='false')) def downgrade(): diff --git a/web/migrations/versions/d39482714a2e_.py b/web/migrations/versions/d39482714a2e_.py index cebb90142..0496b4bae 100644 --- a/web/migrations/versions/d39482714a2e_.py +++ b/web/migrations/versions/d39482714a2e_.py @@ -16,7 +16,6 @@ Create Date: 2020-04-09 13:20:13.939775 """ from alembic import op import sqlalchemy as sa -from pgadmin.model import db # revision identifiers, used by Alembic. revision = 'd39482714a2e' @@ -26,22 +25,21 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN save_password INTEGER DEFAULT 0' - ) + op.add_column('server', sa.Column('save_password', sa.Integer(), + server_default='0')) # If password is already exists for any existing server then change the # save_password column to 1 (True) else set 0 - db.engine.execute( - """ - UPDATE server SET save_password = ( - CASE WHEN password IS NOT NULL AND password != '' THEN - 1 - ELSE - 0 - END - ) - """ - ) + # get metadata from current connection + meta = sa.MetaData(bind=op.get_bind()) + # define table representation + meta.reflect(only=('server',)) + server_table = sa.Table('server', meta) + + op.execute( + server_table.update().values(save_password=sa.case( + (server_table.c.password != 'NULL' and + server_table.c.password != '', 1), else_=0) + )) def downgrade(): diff --git a/web/migrations/versions/d85a62333272_.py b/web/migrations/versions/d85a62333272_.py index 856362081..2df5dc398 100644 --- a/web/migrations/versions/d85a62333272_.py +++ b/web/migrations/versions/d85a62333272_.py @@ -1,13 +1,20 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: d85a62333272 Revises: 3c1e4b6eda55 Create Date: 2017-07-07 16:03:23.842734 """ -from pgadmin.model import db - +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = 'd85a62333272' @@ -17,9 +24,7 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN db_res TEXT' - ) + op.add_column('server', sa.Column('db_res', sa.String())) def downgrade(): diff --git a/web/migrations/versions/ec1cac3399c9_.py b/web/migrations/versions/ec1cac3399c9_.py index d8e0349b5..5454dbc90 100644 --- a/web/migrations/versions/ec1cac3399c9_.py +++ b/web/migrations/versions/ec1cac3399c9_.py @@ -1,13 +1,21 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## -"""empty message +""" Revision ID: ec1cac3399c9 Revises: b5b87fdfcb30 Create Date: 2019-03-07 16:05:28.874203 """ -from pgadmin.model import db - +from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'ec1cac3399c9' @@ -15,27 +23,19 @@ down_revision = 'b5b87fdfcb30' branch_labels = None depends_on = None -srno = db.Column(db.Integer(), nullable=False, primary_key=True) -uid = db.Column( - db.Integer, db.ForeignKey('user.id'), nullable=False, primary_key=True -) -sid = db.Column(db.Integer(), nullable=False, primary_key=True) -did = db.Column(db.Integer(), nullable=False, primary_key=True) -query = db.Column(db.String(), nullable=False) def upgrade(): - db.engine.execute(""" - CREATE TABLE query_history ( - srno INTEGER NOT NULL, - uid INTEGER NOT NULL, - sid INTEGER NOT NULL, - dbname TEXT NOT NULL, - query_info TEXT NOT NULL, - last_updated_flag TEXT NOT NULL, - PRIMARY KEY (srno, uid, sid, dbname), - FOREIGN KEY(uid) REFERENCES user (id), - FOREIGN KEY(sid) REFERENCES server (id) - )""") + op.create_table( + 'query_history', + sa.Column('srno', sa.Integer(), nullable=False), + sa.Column('uid', sa.Integer(), nullable=False), + sa.Column('sid', sa.Integer(), nullable=False), + sa.Column('dbname', sa.String(), nullable=False), + sa.Column('query_info', sa.String(), nullable=False), + sa.Column('last_updated_flag', sa.String(), nullable=False), + sa.ForeignKeyConstraint(['sid'], ['server.id']), + sa.ForeignKeyConstraint(['uid'], ['user.id']), + sa.PrimaryKeyConstraint('srno', 'uid', 'sid', 'dbname')) def downgrade(): diff --git a/web/migrations/versions/ece2e76bf60e_.py b/web/migrations/versions/ece2e76bf60e_.py index 0a774df28..b7c036546 100644 --- a/web/migrations/versions/ece2e76bf60e_.py +++ b/web/migrations/versions/ece2e76bf60e_.py @@ -15,7 +15,8 @@ Create Date: 2018-10-18 14:45:13.483068 """ -from pgadmin.model import db +from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'ece2e76bf60e' @@ -25,9 +26,7 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE process ADD COLUMN utility_pid INTEGER' - ) + op.add_column('process', sa.Column('utility_pid', sa.Integer())) def downgrade(): diff --git a/web/migrations/versions/ef590e979b0d_.py b/web/migrations/versions/ef590e979b0d_.py index 2c9d422d8..a921733b0 100644 --- a/web/migrations/versions/ef590e979b0d_.py +++ b/web/migrations/versions/ef590e979b0d_.py @@ -1,5 +1,12 @@ - -"""empty message +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +""" Revision ID: ef590e979b0d Revises: d85a62333272 @@ -8,7 +15,6 @@ Create Date: 2017-08-23 18:37:14.836988 """ from alembic import op import sqlalchemy as sa -from pgadmin.model import db # revision identifiers, used by Alembic. revision = 'ef590e979b0d' @@ -18,28 +24,13 @@ depends_on = None def upgrade(): - db.engine.execute( - 'ALTER TABLE server ADD COLUMN passfile TEXT' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN sslcert TEXT' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN sslkey TEXT' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN sslrootcert TEXT' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN sslcrl TEXT' - ) - db.engine.execute( - 'ALTER TABLE server ADD COLUMN sslcompression ' - 'INTEGER default 0' - ) - db.engine.execute( - 'UPDATE server SET sslcompression=0' - ) + op.add_column('server', sa.Column('passfile', sa.String())) + op.add_column('server', sa.Column('sslcert', sa.String())) + op.add_column('server', sa.Column('sslkey', sa.String())) + op.add_column('server', sa.Column('sslrootcert', sa.String())) + op.add_column('server', sa.Column('sslcrl', sa.String())) + op.add_column('server', sa.Column('sslcompression', sa.Integer(), + server_default='0')) def downgrade(): diff --git a/web/migrations/versions/f195f9a4923d_.py b/web/migrations/versions/f195f9a4923d_.py index 0c8132d9b..f4f2bdbab 100644 --- a/web/migrations/versions/f195f9a4923d_.py +++ b/web/migrations/versions/f195f9a4923d_.py @@ -1,4 +1,11 @@ - +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2022, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## """Encrypt the existing user password. Revision ID: f195f9a4923d @@ -10,6 +17,8 @@ import config from flask import current_app from flask_security import Security, SQLAlchemyUserDatastore from flask_security.utils import verify_and_update_password +from alembic import op +from sqlalchemy.orm.session import Session from pgadmin.model import Keys, db, User, Role # revision identifiers, used by Alembic. @@ -21,8 +30,9 @@ depends_on = None def upgrade(): app = current_app - db.session.flush() - current_salt = Keys.query.filter_by(name = 'SECURITY_PASSWORD_SALT').first().value + session = Session(bind=op.get_bind()) + current_salt = session.query(Keys).filter_by( + name='SECURITY_PASSWORD_SALT').first().value app.config.update(dict(SECURITY_PASSWORD_SALT=current_salt)) app.config['SECURITY_PASSWORD_HASH'] = config.SECURITY_PASSWORD_HASH @@ -32,7 +42,7 @@ def upgrade(): else: app.config['SECURITY_PASSWORD_SALT'] = current_salt - users = User.query.with_entities( + users = session.query(User).with_entities( User.id, User.email, User.password, User.active, User.confirmed_at)\ .all() # This will upgrade the plaintext password of all the user as per the @@ -41,8 +51,6 @@ def upgrade(): if user.password is not None: verify_and_update_password(user.password, user) - db.session.commit() - def downgrade(): # pgAdmin only upgrades, downgrade not implemented. diff --git a/web/migrations/versions/f79844e926ae_.py b/web/migrations/versions/f79844e926ae_.py index 5cbbbe991..15b880f91 100644 --- a/web/migrations/versions/f79844e926ae_.py +++ b/web/migrations/versions/f79844e926ae_.py @@ -16,7 +16,8 @@ Revises: 1586db67b98e Create Date: 2022-10-11 11:25:00.000000 """ -from pgadmin.model import db +import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. revision = 'f79844e926ae' @@ -26,12 +27,8 @@ depends_on = None def upgrade(): - db.engine.execute(""" - ALTER TABLE server ADD COLUMN passexec_cmd TEXT(256) null - """) - db.engine.execute(""" - ALTER TABLE server ADD COLUMN passexec_expiration INT null - """) + op.add_column('server', sa.Column('passexec_cmd', sa.String(length=256))) + op.add_column('server', sa.Column('passexec_expiration', sa.Integer())) # ### end Alembic commands ### diff --git a/web/migrations/versions/fdc58d9bd449_.py b/web/migrations/versions/fdc58d9bd449_.py index 636d79ead..5d8df463c 100644 --- a/web/migrations/versions/fdc58d9bd449_.py +++ b/web/migrations/versions/fdc58d9bd449_.py @@ -24,7 +24,6 @@ from flask import current_app from flask_security import Security, SQLAlchemyUserDatastore from flask_security.utils import hash_password from pgadmin.model import db, User, Role -from pgadmin.setup import get_version from pgadmin.setup import user_info # revision identifiers, used by Alembic. @@ -36,80 +35,69 @@ depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - - if get_version() != -1: - return - email, password = user_info() - op.create_table('version', - sa.Column('name', sa.String(length=32), nullable=False), - sa.Column('value', sa.Integer(), nullable=False), - sa.PrimaryKeyConstraint('name') - ) - op.create_table('user', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('email', sa.String(length=256), nullable=False), - sa.Column('password', sa.String(length=256), nullable=True), - sa.Column('active', sa.Boolean(), nullable=False), - sa.Column('confirmed_at', sa.DateTime(), nullable=True), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('email') - ) - op.create_table('role', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(length=128), nullable=False), - sa.Column('description', sa.String(length=256), nullable=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name') - ) - op.create_table('setting', - sa.Column('user_id', sa.Integer(), nullable=False), - sa.Column('setting', sa.String(length=256), nullable=False), - sa.Column('value', sa.String(length=1024), nullable=True), - sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), - sa.PrimaryKeyConstraint('user_id', 'setting') - ) - op.create_table('roles_users', - sa.Column('user_id', sa.Integer(), nullable=True), - sa.Column('role_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['role_id'], ['role.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['user.id'], ) - ) - op.create_table('servergroup', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(length=128), nullable=False), - sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('user_id', 'name') - ) - op.create_table('server', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.Integer(), nullable=False), - sa.Column('servergroup_id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(length=128), nullable=False), - sa.Column('host', sa.String(length=128), nullable=False), - sa.Column('port', sa.Integer(), nullable=False), - sa.Column('maintenance_db', sa.String(length=64), nullable=False), - sa.Column('username', sa.String(length=64), nullable=False), - sa.Column('ssl_mode', sa.String(length=16), nullable=False), - sa.ForeignKeyConstraint(['servergroup_id'], ['servergroup.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), - sa.PrimaryKeyConstraint('id') - ) - db.engine.execute(""" -INSERT INTO "role" -VALUES(1, 'Administrators', 'pgAdmin Administrators Role') - """) - db.engine.execute(""" -INSERT INTO "roles_users" -VALUES(1, 1); - """) - db.engine.execute(""" -INSERT INTO "servergroup" -VALUES(1, 1, 'Servers') -""") + version_table = op.create_table( + 'version', sa.Column('name', sa.String(length=32), nullable=False), + sa.Column('value', sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint('name')) + + user_table = op.create_table( + 'user', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('email', sa.String(length=256), nullable=False), + sa.Column('password', sa.String(length=256), nullable=True), + sa.Column('active', sa.Boolean(), nullable=False), + sa.Column('confirmed_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id')) + + with op.batch_alter_table("user") as batch_op: + batch_op.create_unique_constraint('user_unique_constraint', ['email']) + + role_table = op.create_table( + 'role', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('name', sa.String(length=128), nullable=False), + sa.Column('description', sa.String(length=256), nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name')) + + op.create_table( + 'setting', sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('setting', sa.String(length=256), nullable=False), + sa.Column('value', sa.String(length=1024), nullable=True), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('user_id', 'setting')) + + roles_users_table = op.create_table( + 'roles_users', sa.Column('user_id', sa.Integer(), nullable=True), + sa.Column('role_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['role_id'], ['role.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], )) + + server_group_table = op.create_table( + 'servergroup', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=128), nullable=False), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('user_id', 'name')) + + op.create_table( + 'server', + sa.Column('id', sa.Integer(), nullable=False, autoincrement=True), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('servergroup_id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=128), nullable=False), + sa.Column('host', sa.String(length=128), nullable=False), + sa.Column('port', sa.Integer(), nullable=False), + sa.Column('maintenance_db', sa.String(length=64), nullable=False), + sa.Column('username', sa.String(length=64), nullable=False), + sa.Column('ssl_mode', sa.String(length=16), nullable=False), + sa.ForeignKeyConstraint(['servergroup_id'], ['servergroup.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('id')) current_salt = getattr( config, 'SECURITY_PASSWORD_SALT', base64.urlsafe_b64encode( @@ -135,16 +123,23 @@ VALUES(1, 1, 'Servers') setattr(config, 'SECRET_KEY', secret_key) password = hash_password(password) - db.engine.execute(""" -INSERT INTO "user" - VALUES(1, '%s', - '%s', - 1, NULL) - """ % (email, password)) - db.engine.execute(""" -INSERT INTO "version" -VALUES('ConfigDB', 2); - """) + op.bulk_insert(user_table, + [{'email': email, 'password': password, + 'active': 1, 'confirmed_at': None}]) + + op.bulk_insert(version_table, + [{'name': 'ConfigDB', 'value': 2}]) + + op.bulk_insert(role_table, + [{'name': 'Administrators', + 'description': 'pgAdmin Administrators Role'}]) + + op.bulk_insert(roles_users_table, + [{'user_id': 1, 'role_id': 1}]) + + op.bulk_insert(server_group_table, + [{'user_id': 1, 'name': 'Servers'}]) + # ### end Alembic commands ### diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index 978278ecd..a7924354a 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -341,11 +341,14 @@ def create_app(app_name=None): ########################################################################## # Setup authentication ########################################################################## - - app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///{0}?timeout={1}' \ - .format(config.SQLITE_PATH.replace('\\', '/'), - getattr(config, 'SQLITE_TIMEOUT', 500) - ) + if config.CONFIG_DATABASE_URI is not None and \ + len(config.CONFIG_DATABASE_URI) > 0: + app.config['SQLALCHEMY_DATABASE_URI'] = config.CONFIG_DATABASE_URI + else: + app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///{0}?timeout={1}' \ + .format(config.SQLITE_PATH.replace('\\', '/'), + getattr(config, 'SQLITE_TIMEOUT', 500) + ) # Override USER_DOES_NOT_EXIST and INVALID_PASSWORD messages from flask. app.config['SECURITY_MSG_USER_DOES_NOT_EXIST'] = \ @@ -358,6 +361,9 @@ def create_app(app_name=None): ########################################################################## # Upgrade the schema (if required) ########################################################################## + from config import SQLITE_PATH + from pgadmin.setup import db_upgrade + def backup_db_file(): """ Create a backup of the current database file @@ -396,48 +402,76 @@ def create_app(app_name=None): ' database'.format(invalid_tb_names)) backup_db_file() - with app.app_context(): - # Run migration for the first time i.e. create database - from config import SQLITE_PATH - from pgadmin.setup import db_upgrade - - # If version not available, user must have aborted. Tables are not - # created and so its an empty db - if not os.path.exists(SQLITE_PATH) or get_version() == -1: - # If running in cli mode then don't try to upgrade, just raise - # the exception - if not cli_mode: - upgrade_db() + def run_migration_for_sqlite(): + with app.app_context(): + # Run migration for the first time i.e. create database + # If version not available, user must have aborted. Tables are not + # created and so its an empty db + if not os.path.exists(SQLITE_PATH) or get_version() == -1: + # If running in cli mode then don't try to upgrade, just raise + # the exception + if not cli_mode: + upgrade_db() + else: + if not os.path.exists(SQLITE_PATH): + raise FileNotFoundError( + 'SQLite database file "' + SQLITE_PATH + + '" does not exists.') + raise RuntimeError( + 'The configuration database file is not valid.') else: - if not os.path.exists(SQLITE_PATH): - raise FileNotFoundError( - 'SQLite database file "' + SQLITE_PATH + - '" does not exists.') - raise RuntimeError( - 'The configuration database file is not valid.') - else: - schema_version = get_version() + schema_version = get_version() - # Run migration if current schema version is greater than the - # schema version stored in version table - if CURRENT_SCHEMA_VERSION >= schema_version: - upgrade_db() - else: - # check all tables are present in the db. - is_db_error, invalid_tb_names = check_db_tables() - if is_db_error: - app.logger.error( - 'Table(s) {0} are missing in the' - ' database'.format(invalid_tb_names)) - backup_db_file() + # Run migration if current schema version is greater than the + # schema version stored in version table + if CURRENT_SCHEMA_VERSION >= schema_version: + upgrade_db() + else: + # check all tables are present in the db. + is_db_error, invalid_tb_names = check_db_tables() + if is_db_error: + app.logger.error( + 'Table(s) {0} are missing in the' + ' database'.format(invalid_tb_names)) + backup_db_file() - # Update schema version to the latest - if CURRENT_SCHEMA_VERSION > schema_version: - set_version(CURRENT_SCHEMA_VERSION) - db.session.commit() + # Update schema version to the latest + if CURRENT_SCHEMA_VERSION > schema_version: + set_version(CURRENT_SCHEMA_VERSION) + db.session.commit() - if os.name != 'nt': - os.chmod(config.SQLITE_PATH, 0o600) + if os.name != 'nt': + os.chmod(config.SQLITE_PATH, 0o600) + + def run_migration_for_others(): + with app.app_context(): + # Run migration for the first time i.e. create database + # If version not available, user must have aborted. Tables are not + # created and so its an empty db + try: + if get_version() == -1: + db_upgrade(app) + else: + schema_version = get_version() + + # Run migration if current schema version is greater than + # the schema version stored in version table + if CURRENT_SCHEMA_VERSION >= schema_version: + db_upgrade(app) + + # Update schema version to the latest + if CURRENT_SCHEMA_VERSION > schema_version: + set_version(CURRENT_SCHEMA_VERSION) + db.session.commit() + except Exception as e: + app.logger.error(e) + + # Run the migration as per specified by the user. + if config.CONFIG_DATABASE_URI is not None and \ + len(config.CONFIG_DATABASE_URI) > 0: + run_migration_for_others() + else: + run_migration_for_sqlite() Mail(app) @@ -553,7 +587,7 @@ def create_app(app_name=None): user_id=user_id ).order_by("id") - if servergroups.count() > 0: + if int(servergroups.count()) > 0: servergroup = servergroups.first() servergroup_id = servergroup.id @@ -567,7 +601,7 @@ def create_app(app_name=None): discovery_id=svr_discovery_id ).order_by("id") - if servers.count() > 0: + if int(servers.count()) > 0: return svr = Server(user_id=user_id, diff --git a/web/pgadmin/authenticate/mfa/utils.py b/web/pgadmin/authenticate/mfa/utils.py index c41979880..eafcbe26e 100644 --- a/web/pgadmin/authenticate/mfa/utils.py +++ b/web/pgadmin/authenticate/mfa/utils.py @@ -347,7 +347,7 @@ def mfa_delete(auth_name: str) -> bool: user_id=current_user.id, mfa_auth=auth_name ) - if auth.count() != 0: + if int(auth.count()) != 0: auth.delete() db.session.commit() diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index e34b3d9b8..ff5c96243 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -831,7 +831,8 @@ class ServerNode(PGChildNodeView): # Delete the shared server from DB if server # owner uncheck shared property self.delete_shared_server(server.name, gid, server.id) - if arg == 'sslcompression': + if arg in ('sslcompression', 'use_ssh_tunnel', + 'tunnel_authentication', 'kerberos_conn', 'shared'): value = 1 if value else 0 self._update_server_details(server, sharedserver, config_param_map, arg, value) @@ -1091,11 +1092,12 @@ class ServerNode(PGChildNodeView): fgcolor=data.get('fgcolor', None), service=data.get('service', None), connect_timeout=data.get('connect_timeout', 0), - use_ssh_tunnel=data.get('use_ssh_tunnel', 0), + use_ssh_tunnel=1 if data.get('use_ssh_tunnel', False) else 0, tunnel_host=data.get('tunnel_host', None), tunnel_port=data.get('tunnel_port', 22), tunnel_username=data.get('tunnel_username', None), - tunnel_authentication=data.get('tunnel_authentication', 0), + tunnel_authentication=1 if data.get('tunnel_authentication', + False) else 0, tunnel_identity_file=data.get('tunnel_identity_file', None), shared=data.get('shared', None), passfile=data.get('passfile', None), diff --git a/web/pgadmin/misc/bgprocess/processes.py b/web/pgadmin/misc/bgprocess/processes.py index 521ce8c30..18b9e94bf 100644 --- a/web/pgadmin/misc/bgprocess/processes.py +++ b/web/pgadmin/misc/bgprocess/processes.py @@ -137,7 +137,10 @@ class BatchProcess(object): if p is None: raise LookupError(PROCESS_NOT_FOUND) - tmp_desc = loads(p.desc) + try: + tmp_desc = loads(bytes.fromhex(p.desc)) + except Exception: + tmp_desc = loads(p.desc) # ID self.id = _id @@ -228,7 +231,7 @@ class BatchProcess(object): csv_writer.writerow(_args) args_val = args_csv_io.getvalue().strip(str('\r\n')) - tmp_desc = dumps(self.desc) + tmp_desc = dumps(self.desc).hex() j = Process( pid=int(uid), @@ -679,7 +682,11 @@ class BatchProcess(object): :return: return value for details, type_desc and desc related to process """ - desc = loads(p.desc) + try: + desc = loads(bytes.fromhex(p.desc)) + except Exception: + desc = loads(p.desc) + details = desc type_desc = '' current_storage_dir = None diff --git a/web/pgadmin/model/__init__.py b/web/pgadmin/model/__init__.py index ad8dc03d5..2629950c4 100644 --- a/web/pgadmin/model/__init__.py +++ b/web/pgadmin/model/__init__.py @@ -169,8 +169,8 @@ class Server(db.Model): db.CheckConstraint('sslcompression >= 0 AND sslcompression <= 1'), nullable=False ) - bgcolor = db.Column(db.Text(10), nullable=True) - fgcolor = db.Column(db.Text(10), nullable=True) + bgcolor = db.Column(db.String(10), nullable=True) + fgcolor = db.Column(db.String(10), nullable=True) service = db.Column(db.Text(), nullable=True) connect_timeout = db.Column(db.Integer(), nullable=False) use_ssh_tunnel = db.Column( @@ -437,8 +437,8 @@ class SharedServer(db.Model): db.CheckConstraint('sslcompression >= 0 AND sslcompression <= 1'), nullable=False ) - bgcolor = db.Column(db.Text(10), nullable=True) - fgcolor = db.Column(db.Text(10), nullable=True) + bgcolor = db.Column(db.String(10), nullable=True) + fgcolor = db.Column(db.String(10), nullable=True) service = db.Column(db.Text(), nullable=True) connect_timeout = db.Column(db.Integer(), nullable=False) use_ssh_tunnel = db.Column( diff --git a/web/pgadmin/setup/__init__.py b/web/pgadmin/setup/__init__.py index 56b31588f..2fccdd9e9 100644 --- a/web/pgadmin/setup/__init__.py +++ b/web/pgadmin/setup/__init__.py @@ -8,7 +8,7 @@ ########################################################################## from .user_info import user_info -from .db_version import get_version, set_version +from .db_version import get_version, set_version, get_version_for_migration from .db_upgrade import db_upgrade from .data_directory import create_app_data_directory from .db_table_check import check_db_tables diff --git a/web/pgadmin/setup/db_version.py b/web/pgadmin/setup/db_version.py index b097c6cc6..7b53bbbc1 100644 --- a/web/pgadmin/setup/db_version.py +++ b/web/pgadmin/setup/db_version.py @@ -7,12 +7,27 @@ # ########################################################################## -from pgadmin.model import Version +from pgadmin.model import Version, db +from sqlalchemy.orm.session import Session def get_version(): try: version = Version.query.filter_by(name='ConfigDB').first() + except Exception: + db.session.rollback() + return -1 + + if version: + return version.value + else: + return -1 + + +def get_version_for_migration(op): + try: + session = Session(bind=op.get_bind()) + version = session.query(Version).filter_by(name='ConfigDB').first() except Exception: return -1 diff --git a/web/pgadmin/tools/debugger/__init__.py b/web/pgadmin/tools/debugger/__init__.py index dbf00dc93..e1cdea8ef 100644 --- a/web/pgadmin/tools/debugger/__init__.py +++ b/web/pgadmin/tools/debugger/__init__.py @@ -1730,12 +1730,12 @@ def get_arguments_sqlite(sid, did, scid, func_id): """ """Get the count of the existing data available in sqlite database""" - dbg_func_args_count = DebuggerFunctionArguments.query.filter_by( + dbg_func_args_count = int(DebuggerFunctionArguments.query.filter_by( server_id=sid, database_id=did, schema_id=scid, function_id=func_id - ).count() + ).count()) args_data = [] @@ -1819,13 +1819,13 @@ def set_arguments_sqlite(sid, did, scid, func_id): try: for i in range(0, len(data)): - dbg_func_args_exists = DebuggerFunctionArguments.query.filter_by( - server_id=data[i]['server_id'], - database_id=data[i]['database_id'], - schema_id=data[i]['schema_id'], - function_id=data[i]['function_id'], - arg_id=data[i]['arg_id'] - ).count() + dbg_func_args_exists = int( + DebuggerFunctionArguments.query.filter_by( + server_id=data[i]['server_id'], + database_id=data[i]['database_id'], + schema_id=data[i]['schema_id'], + function_id=data[i]['function_id'], + arg_id=data[i]['arg_id']).count()) # handle the Array list sent from the client array_string = '' diff --git a/web/setup.py b/web/setup.py index 74ba4eb9f..4dac1c103 100644 --- a/web/setup.py +++ b/web/setup.py @@ -97,28 +97,55 @@ def setup_db(app): print("pgAdmin 4 - Application Initialisation") print("======================================\n") - with app.app_context(): - # Run migration for the first time i.e. create database - from config import SQLITE_PATH - if not os.path.exists(SQLITE_PATH): - db_upgrade(app) - else: - version = Version.query.filter_by(name='ConfigDB').first() - schema_version = version.value - - # Run migration if current schema version is greater than the - # schema version stored in version table - if CURRENT_SCHEMA_VERSION >= schema_version: + def run_migration_for_sqlite(): + with app.app_context(): + # Run migration for the first time i.e. create database + from config import SQLITE_PATH + if not os.path.exists(SQLITE_PATH): db_upgrade(app) - - # Update schema version to the latest - if CURRENT_SCHEMA_VERSION > schema_version: + else: version = Version.query.filter_by(name='ConfigDB').first() - version.value = CURRENT_SCHEMA_VERSION - db.session.commit() + schema_version = version.value - if os.name != 'nt': - os.chmod(config.SQLITE_PATH, 0o600) + # Run migration if current schema version is greater than the + # schema version stored in version table + if CURRENT_SCHEMA_VERSION >= schema_version: + db_upgrade(app) + + # Update schema version to the latest + if CURRENT_SCHEMA_VERSION > schema_version: + version = Version.query.filter_by(name='ConfigDB').first() + version.value = CURRENT_SCHEMA_VERSION + db.session.commit() + + if os.name != 'nt': + os.chmod(config.SQLITE_PATH, 0o600) + + def run_migration_for_others(): + with app.app_context(): + version = Version.query.filter_by(name='ConfigDB').first() + if version == -1: + db_upgrade(app) + else: + schema_version = version.value + + # Run migration if current schema version is greater than the + # schema version stored in version table + if CURRENT_SCHEMA_VERSION >= schema_version: + db_upgrade(app) + + # Update schema version to the latest + if CURRENT_SCHEMA_VERSION > schema_version: + version = Version.query.filter_by(name='ConfigDB').first() + version.value = CURRENT_SCHEMA_VERSION + db.session.commit() + + # Run the migration as per specified by the user. + if config.CONFIG_DATABASE_URI is not None and \ + len(config.CONFIG_DATABASE_URI) > 0: + run_migration_for_others() + else: + run_migration_for_sqlite() def clear_servers():