diff --git a/CHANGELOG.md b/CHANGELOG.md index fb0a73df5..450577001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ It was already required in v1.22.2. ### Migrations and checks #### Schema migrations +- [#165](https://github.com/LayerManager/layman/issues/165) Add column `role_name` to table `rights` in prime DB schema. Add constraint that exactly one of columns `role_name` and `id_user` is not null. #### Data migrations ### Changes - All changes from [v1.22.1](#v1221) and [v1.22.2](#v1222). diff --git a/src/layman/upgrade/__init__.py b/src/layman/upgrade/__init__.py index 28b85d024..fc1d6555f 100644 --- a/src/layman/upgrade/__init__.py +++ b/src/layman/upgrade/__init__.py @@ -2,7 +2,7 @@ from db import util as db_util from layman.upgrade import upgrade_v1_8, upgrade_v1_9, upgrade_v1_10, upgrade_v1_12, upgrade_v1_16, upgrade_v1_17, upgrade_v1_18, \ - upgrade_v1_20, upgrade_v1_21, upgrade_v1_22 + upgrade_v1_20, upgrade_v1_21, upgrade_v1_22, upgrade_v1_23 from layman import settings from . import consts @@ -41,6 +41,9 @@ ((1, 22, 0), [ upgrade_v1_22.create_map_layer_relation_table, ]), + ((1, 23, 0), [ + upgrade_v1_23.adjust_db_for_roles, + ]), ], consts.MIGRATION_TYPE_DATA: [ ((1, 16, 0), [ diff --git a/src/layman/upgrade/upgrade_v1_23.py b/src/layman/upgrade/upgrade_v1_23.py new file mode 100644 index 000000000..308d67951 --- /dev/null +++ b/src/layman/upgrade/upgrade_v1_23.py @@ -0,0 +1,26 @@ +import logging + +from db import util as db_util +from layman import settings + +logger = logging.getLogger(__name__) +DB_SCHEMA = settings.LAYMAN_PRIME_SCHEMA + + +def adjust_db_for_roles(): + logger.info(f' Alter DB prime schema for roles') + + statement = f''' +ALTER TABLE {DB_SCHEMA}.rights ADD COLUMN IF NOT EXISTS + role_name VARCHAR(64) COLLATE pg_catalog."default"; + +ALTER TABLE {DB_SCHEMA}.rights ALTER COLUMN id_user DROP NOT NULL; + +ALTER TABLE {DB_SCHEMA}.rights ADD CONSTRAINT rights_role_xor_user + CHECK ((id_user IS NULL) != (role_name IS NULL)); + +ALTER TABLE {DB_SCHEMA}.rights DROP CONSTRAINT IF EXISTS rights_unique_key; +ALTER TABLE {DB_SCHEMA}.rights ADD CONSTRAINT rights_unique_key unique (id_user, role_name, id_publication, type); + ''' + + db_util.run_statement(statement) diff --git a/src/layman/upgrade/upgrade_v1_23_test.py b/src/layman/upgrade/upgrade_v1_23_test.py new file mode 100644 index 000000000..4a6c21256 --- /dev/null +++ b/src/layman/upgrade/upgrade_v1_23_test.py @@ -0,0 +1,60 @@ +import pytest + +from db import util as db_util +from layman import app, settings +from test_tools import process_client +from . import upgrade_v1_23 + +DB_SCHEMA = settings.LAYMAN_PRIME_SCHEMA + + +@pytest.mark.usefixtures('ensure_layman', 'oauth2_provider_mock') +def test_adjust_db_for_roles(): + username = 'test_adjust_db_for_roles_ws' + username2 = 'test_adjust_db_for_roles_ws2' + layer_name = 'test_adjust_db_for_roles_layer' + + headers = process_client.get_authz_headers(username) + process_client.reserve_username(username, headers=headers) + headers2 = process_client.get_authz_headers(username2) + process_client.reserve_username(username2, headers=headers2) + + process_client.publish_workspace_layer(username, layer_name, headers=headers, access_rights={ + 'read': f"{username},{username2}", + }) + + statement = f''' +ALTER TABLE {DB_SCHEMA}.rights ALTER COLUMN id_user SET NOT NULL; +ALTER TABLE {DB_SCHEMA}.rights DROP CONSTRAINT rights_role_xor_user; +ALTER TABLE {DB_SCHEMA}.rights DROP CONSTRAINT rights_unique_key; +ALTER TABLE {DB_SCHEMA}.rights ADD CONSTRAINT rights_unique_key unique (id_user, id_publication, type); +ALTER TABLE {DB_SCHEMA}.rights DROP COLUMN role_name; + ''' + with app.app_context(): + db_util.run_statement(statement) + + query = f'''select * from {DB_SCHEMA}.rights;''' + with app.app_context(): + rights_rows = db_util.run_query(query) + assert len(rights_rows[0]) == 4, f"Exactly 4 columns expected before migration" + + with app.app_context(): + upgrade_v1_23.adjust_db_for_roles() + + query = f''' +select id, id_user, role_name, id_publication, type +from {DB_SCHEMA}.rights +where id_publication in ( + select id from {DB_SCHEMA}.publications + where name='{layer_name}' + and id_workspace in ( + select id from {DB_SCHEMA}.workspaces + where name='{username}' + ) +) +''' + with app.app_context(): + rights_rows = db_util.run_query(query) + assert len(rights_rows) == 1 + assert rights_rows[0][1] is not None, f"id_user is none!" + assert rights_rows[0][2] is None, f"role_name is not none!" diff --git a/test_tools/process.py b/test_tools/process.py index f2db1a565..300f686d9 100644 --- a/test_tools/process.py +++ b/test_tools/process.py @@ -72,6 +72,8 @@ def oauth2_provider_mock(): 'layer_map_relation_user': None, 'wrong_input_owner': None, 'wrong_input_editor': None, + 'test_adjust_db_for_roles_ws': None, + 'test_adjust_db_for_roles_ws2': None, }, }, 'host': '0.0.0.0',