diff --git a/backend/dataall/core/permissions/services/resource_policy_service.py b/backend/dataall/core/permissions/services/resource_policy_service.py index 95de63743..c39c354d4 100644 --- a/backend/dataall/core/permissions/services/resource_policy_service.py +++ b/backend/dataall/core/permissions/services/resource_policy_service.py @@ -217,6 +217,7 @@ def get_resource_policy_permissions(session, group_uri, resource_uri) -> List[Re raise exceptions.RequiredParameter(param_name='group_uri') if not resource_uri: raise exceptions.RequiredParameter(param_name='resource_uri') + policy = ResourcePolicyRepository.find_resource_policy( session=session, group_uri=group_uri, diff --git a/backend/dataall/modules/metadata_forms/api/queries.py b/backend/dataall/modules/metadata_forms/api/queries.py index 4458e3860..e9385e091 100644 --- a/backend/dataall/modules/metadata_forms/api/queries.py +++ b/backend/dataall/modules/metadata_forms/api/queries.py @@ -5,6 +5,7 @@ get_metadata_form, get_attached_metadata_form, list_attached_forms, + get_entity_metadata_form_permissions, ) listUserMetadataForms = gql.QueryField( @@ -47,3 +48,11 @@ resolver=get_attached_metadata_form, test_scope='MetadataForm', ) + +getEntityMetadataFormPermissions = gql.QueryField( + name='getEntityMetadataFormPermissions', + args=[gql.Argument('entityUri', gql.NonNullableType(gql.String))], + type=gql.ArrayType(gql.String), + resolver=get_entity_metadata_form_permissions, + test_scope='MetadataForm', +) diff --git a/backend/dataall/modules/metadata_forms/api/resolvers.py b/backend/dataall/modules/metadata_forms/api/resolvers.py index 390a0938f..4e03e6d6c 100644 --- a/backend/dataall/modules/metadata_forms/api/resolvers.py +++ b/backend/dataall/modules/metadata_forms/api/resolvers.py @@ -94,3 +94,7 @@ def has_tenant_permissions_for_metadata_forms(context: Context, source: Metadata def resolve_metadata_form_field(context: Context, source: AttachedMetadataFormField): return MetadataFormService.get_metadata_form_field_by_uri(uri=source.fieldUri) + + +def get_entity_metadata_form_permissions(context: Context, source, entityUri): + return MetadataFormService.get_mf_permissions(entityUri=entityUri) diff --git a/backend/dataall/modules/metadata_forms/db/metadata_form_repository.py b/backend/dataall/modules/metadata_forms/db/metadata_form_repository.py index cd404e396..8dcf55f1b 100644 --- a/backend/dataall/modules/metadata_forms/db/metadata_form_repository.py +++ b/backend/dataall/modules/metadata_forms/db/metadata_form_repository.py @@ -70,6 +70,9 @@ def query_user_metadata_forms(session, is_da_admin, groups, env_uris, org_uris, :param filter: """ + env_uris = env_uris or [] + org_uris = org_uris or [] + query = session.query(MetadataForm) if not is_da_admin: @@ -141,16 +144,22 @@ def query_entity_metadata_forms( entity_orgs_uris = entity_orgs_uris or [] entity_envs_uris = entity_envs_uris or [] - orgs = list(set(user_org_uris).intersection(set(entity_orgs_uris))) - envs = list(set(user_env_uris).intersection(set(entity_envs_uris))) - - query = MetadataFormRepository.query_user_metadata_forms(session, is_da_admin, groups, envs, orgs, filter) - - if not orgs: - query = query.filter(MetadataForm.visibility != MetadataFormVisibility.Organization.value) + query = MetadataFormRepository.query_user_metadata_forms( + session, is_da_admin, groups, user_env_uris, user_org_uris, filter + ) - if not envs: - query = query.filter(MetadataForm.visibility != MetadataFormVisibility.Environment.value) + query = query.filter( + and_( + or_( + MetadataForm.visibility != MetadataFormVisibility.Organization.value, + MetadataForm.homeEntity.in_(entity_orgs_uris), + ), + or_( + MetadataForm.visibility != MetadataFormVisibility.Environment.value, + MetadataForm.homeEntity.in_(entity_envs_uris), + ), + ) + ) query = MetadataFormRepository.exclude_attached(session, query, filter) return query.order_by(MetadataForm.name) @@ -247,3 +256,9 @@ def query_attached_metadata_forms(session, is_da_admin, groups, user_envs_uris, if filter and filter.get('metadataFormUri'): query = query.filter(AttachedMetadataForm.metadataFormUri == filter.get('metadataFormUri')) return query + + @staticmethod + def query_all_attached_metadata_forms_for_entity(session, entityUri, entityType): + return session.query(AttachedMetadataForm).filter( + and_(AttachedMetadataForm.entityType == entityType, AttachedMetadataForm.entityUri == entityUri) + ) diff --git a/backend/dataall/modules/metadata_forms/services/attached_metadata_form_service.py b/backend/dataall/modules/metadata_forms/services/attached_metadata_form_service.py index 41f6067b4..005e9a45b 100644 --- a/backend/dataall/modules/metadata_forms/services/attached_metadata_form_service.py +++ b/backend/dataall/modules/metadata_forms/services/attached_metadata_form_service.py @@ -1,10 +1,9 @@ from dataall.base.context import get_context from dataall.base.db import exceptions, paginate -from dataall.core.environment.db.environment_repositories import EnvironmentRepository -from dataall.core.organizations.db.organization_repositories import OrganizationRepository -from dataall.core.permissions.services.tenant_policy_service import TenantPolicyValidationService +from dataall.core.permissions.services.resource_policy_service import ResourcePolicyService from dataall.modules.metadata_forms.db.metadata_form_repository import MetadataFormRepository from dataall.modules.metadata_forms.services.metadata_form_access_service import MetadataFormAccessService +from dataall.modules.metadata_forms.services.metadata_form_permissions import ATTACH_METADATA_FORM class AttachedMetadataFormValidationService: @@ -33,15 +32,22 @@ def validate_enrich_fields_params(mf_fields, data): class AttachedMetadataFormService: @staticmethod + def _get_entity_uri(data): + return data.get('entityUri') + + @staticmethod + @ResourcePolicyService.has_resource_permission( + ATTACH_METADATA_FORM, parent_resource=_get_entity_uri, param_name='data' + ) def create_attached_metadata_form(uri, data): AttachedMetadataFormValidationService.validate_filled_form_params(uri, data) - with get_context().db_engine.scoped_session() as session: + context = get_context() + with context.db_engine.scoped_session() as session: mf = MetadataFormRepository.get_metadata_form(session, uri) if not mf: raise exceptions.ObjectNotFound('MetadataForm', uri) mf_fields = MetadataFormRepository.get_metadata_form_fields(session, uri) AttachedMetadataFormValidationService.validate_enrich_fields_params(mf_fields, data) - amf = MetadataFormRepository.create_attached_metadata_form(session, uri, data) for f in data.get('fields'): MetadataFormRepository.create_attached_metadata_form_field( @@ -74,7 +80,11 @@ def list_attached_forms(filter=None): ).to_dict() @staticmethod + @ResourcePolicyService.has_resource_permission( + ATTACH_METADATA_FORM, parent_resource=_get_entity_uri, param_name='data' + ) def delete_attached_metadata_form(uri): mf = AttachedMetadataFormService.get_attached_metadata_form(uri) - with get_context().db_engine.scoped_session() as session: + context = get_context() + with context.db_engine.scoped_session() as session: return session.delete(mf) diff --git a/backend/dataall/modules/metadata_forms/services/metadata_form_permissions.py b/backend/dataall/modules/metadata_forms/services/metadata_form_permissions.py index f5801f6e3..883977a16 100644 --- a/backend/dataall/modules/metadata_forms/services/metadata_form_permissions.py +++ b/backend/dataall/modules/metadata_forms/services/metadata_form_permissions.py @@ -1,6 +1,55 @@ +from dataall.core.permissions.services.environment_permissions import ENVIRONMENT_INVITED, ENVIRONMENT_ALL +from dataall.core.permissions.services.organization_permissions import ( + ORGANIZATION_ALL, + ORGANIZATION_INVITED_DESCRIPTIONS, +) from dataall.core.permissions.services.tenant_permissions import TENANT_ALL, TENANT_ALL_WITH_DESC +from dataall.core.permissions.services.resources_permissions import RESOURCES_ALL, RESOURCES_ALL_WITH_DESC +from dataall.modules.s3_datasets.services.dataset_permissions import DATASET_WRITE, DATASET_ALL - +# ------------------------TENANT----------------------------------- MANAGE_METADATA_FORMS = 'MANAGE_METADATA_FORMS' TENANT_ALL.append(MANAGE_METADATA_FORMS) TENANT_ALL_WITH_DESC[MANAGE_METADATA_FORMS] = 'Manage metadata forms' + +# ------------------------RESOURCE--------------------------------- +# permissions to attach MF to the entity, ot make the entity the visibility base for MF +# these permissions are attached to Organizations, Environments, Datasets etc. +ATTACH_METADATA_FORM = 'ATTACH_METADATA_FORM' +CREATE_METADATA_FORM = 'CREATE_METADATA_FORM' +ALL_METADATA_FORMS_ENTITY_PERMISSIONS = [ATTACH_METADATA_FORM, CREATE_METADATA_FORM] +RESOURCES_ALL.extend(ALL_METADATA_FORMS_ENTITY_PERMISSIONS) +RESOURCES_ALL_WITH_DESC[CREATE_METADATA_FORM] = 'Create metadata form within this visibility scope' +RESOURCES_ALL_WITH_DESC[ATTACH_METADATA_FORM] = 'Attach metadata form' + +ORGANIZATION_ALL.extend(ALL_METADATA_FORMS_ENTITY_PERMISSIONS) +ORGANIZATION_INVITED_DESCRIPTIONS[CREATE_METADATA_FORM] = 'Create metadata form within this visibility scope' +ORGANIZATION_INVITED_DESCRIPTIONS[ATTACH_METADATA_FORM] = 'Attach metadata form' + +ENVIRONMENT_INVITED.extend(ALL_METADATA_FORMS_ENTITY_PERMISSIONS) +ENVIRONMENT_ALL.extend(ALL_METADATA_FORMS_ENTITY_PERMISSIONS) + +DATASET_WRITE.extend(ALL_METADATA_FORMS_ENTITY_PERMISSIONS) +DATASET_ALL.extend(ALL_METADATA_FORMS_ENTITY_PERMISSIONS) +# ------------------------METADATA FORM---------------------------- +# permissions to change and delete metadata forms +# these permissions are attached to MFs +UPDATE_METADATA_FORM_FIELD = 'UPDATE_METADATA_FORM_FIELD' +DELETE_METADATA_FORM_FIELD = 'DELETE_METADATA_FORM_FIELD' +DELETE_METADATA_FORM = 'DELETE_METADATA_FORM' +EDIT_METADATA_FORM = 'EDIT_METADATA_FORM' + +METADATA_FORM_PERMISSIONS_ALL = [ + UPDATE_METADATA_FORM_FIELD, + DELETE_METADATA_FORM_FIELD, + DELETE_METADATA_FORM, + EDIT_METADATA_FORM, +] + +METADATA_FORM_EDIT_PERMISSIONS = [ + EDIT_METADATA_FORM, + UPDATE_METADATA_FORM_FIELD, + DELETE_METADATA_FORM_FIELD, +] + +RESOURCES_ALL.extend(METADATA_FORM_PERMISSIONS_ALL) diff --git a/backend/dataall/modules/metadata_forms/services/metadata_form_service.py b/backend/dataall/modules/metadata_forms/services/metadata_form_service.py index ac4ddbb91..5ac4af784 100644 --- a/backend/dataall/modules/metadata_forms/services/metadata_form_service.py +++ b/backend/dataall/modules/metadata_forms/services/metadata_form_service.py @@ -2,7 +2,9 @@ from dataall.base.db import exceptions, paginate from dataall.core.organizations.db.organization_repositories import OrganizationRepository from dataall.core.environment.db.environment_repositories import EnvironmentRepository -from dataall.core.permissions.services.tenant_policy_service import TenantPolicyValidationService, TenantPolicyService +from dataall.core.permissions.db.resource_policy.resource_policy_repositories import ResourcePolicyRepository +from dataall.core.permissions.services.resource_policy_service import ResourcePolicyService +from dataall.core.permissions.services.tenant_policy_service import TenantPolicyService from dataall.modules.metadata_forms.db.enums import ( MetadataFormVisibility, MetadataFormFieldType, @@ -10,7 +12,14 @@ from dataall.modules.catalog.db.glossary_repositories import GlossaryRepository from dataall.modules.metadata_forms.db.metadata_form_repository import MetadataFormRepository from dataall.modules.metadata_forms.services.metadata_form_access_service import MetadataFormAccessService -from dataall.modules.metadata_forms.services.metadata_form_permissions import MANAGE_METADATA_FORMS +from dataall.modules.metadata_forms.services.metadata_form_permissions import ( + MANAGE_METADATA_FORMS, + DELETE_METADATA_FORM, + DELETE_METADATA_FORM_FIELD, + UPDATE_METADATA_FORM_FIELD, + CREATE_METADATA_FORM, + ALL_METADATA_FORMS_ENTITY_PERMISSIONS, +) class MetadataFormParamValidationService: @@ -91,7 +100,20 @@ class MetadataFormService: @TenantPolicyService.has_tenant_permission(MANAGE_METADATA_FORMS) def create_metadata_form(data): MetadataFormParamValidationService.validate_create_form_params(data) - with get_context().db_engine.scoped_session() as session: + context = get_context() + with context.db_engine.scoped_session() as session: + if data.get('visibility') in [ + MetadataFormVisibility.Organization.value, + MetadataFormVisibility.Environment.value, + ]: + ResourcePolicyService.check_user_resource_permission( + session=session, + username=context.username, + groups=context.groups, + resource_uri=data.get('homeEntity'), + permission_name=CREATE_METADATA_FORM, + ) + form = MetadataFormRepository.create_metadata_form(session, data) return form @@ -104,7 +126,7 @@ def get_metadata_form_by_uri(uri): # toDo: deletion logic @staticmethod @TenantPolicyService.has_tenant_permission(MANAGE_METADATA_FORMS) - @MetadataFormAccessService.can_perform('DELETE') + @MetadataFormAccessService.can_perform(DELETE_METADATA_FORM) def delete_metadata_form_by_uri(uri): if mf := MetadataFormService.get_metadata_form_by_uri(uri): with get_context().db_engine.scoped_session() as session: @@ -181,7 +203,7 @@ def get_metadata_form_field_by_uri(uri): @staticmethod @TenantPolicyService.has_tenant_permission(MANAGE_METADATA_FORMS) - @MetadataFormAccessService.can_perform('ADD FIELD') + @MetadataFormAccessService.can_perform(UPDATE_METADATA_FORM_FIELD) def create_metadata_form_field(uri, data): MetadataFormParamValidationService.validate_create_field_params(data) with get_context().db_engine.scoped_session() as session: @@ -189,7 +211,7 @@ def create_metadata_form_field(uri, data): @staticmethod @TenantPolicyService.has_tenant_permission(MANAGE_METADATA_FORMS) - @MetadataFormAccessService.can_perform('ADD FIELDS') + @MetadataFormAccessService.can_perform(UPDATE_METADATA_FORM_FIELD) def create_metadata_form_fields(uri, data_arr): fields = [] for data in data_arr: @@ -198,7 +220,7 @@ def create_metadata_form_fields(uri, data_arr): @staticmethod @TenantPolicyService.has_tenant_permission(MANAGE_METADATA_FORMS) - @MetadataFormAccessService.can_perform('DELETE FIELD') + @MetadataFormAccessService.can_perform(DELETE_METADATA_FORM_FIELD) def delete_metadata_form_field(uri, fieldUri): mf = MetadataFormService.get_metadata_form_field_by_uri(fieldUri) with get_context().db_engine.scoped_session() as session: @@ -206,7 +228,7 @@ def delete_metadata_form_field(uri, fieldUri): @staticmethod @TenantPolicyService.has_tenant_permission(MANAGE_METADATA_FORMS) - @MetadataFormAccessService.can_perform('UPDATE FIELDS') + @MetadataFormAccessService.can_perform('UPDATE_METADATA_FORM_FIELD') def batch_metadata_form_field_update(uri, data): to_delete = [] to_update = [] @@ -238,8 +260,23 @@ def batch_metadata_form_field_update(uri, data): @staticmethod @TenantPolicyService.has_tenant_permission(MANAGE_METADATA_FORMS) - @MetadataFormAccessService.can_perform('UPDATE FIELD') + @MetadataFormAccessService.can_perform(UPDATE_METADATA_FORM_FIELD) def update_metadata_form_field(uri, fieldUri, data): with get_context().db_engine.scoped_session() as session: MetadataFormParamValidationService.validate_update_field_params(uri, data) return MetadataFormRepository.update_metadata_form_field(session, fieldUri, data) + + @staticmethod + def get_mf_permissions(entityUri): + context = get_context() + result_permissions = [] + with context.db_engine.scoped_session() as session: + for permissions in ALL_METADATA_FORMS_ENTITY_PERMISSIONS: + if ResourcePolicyRepository.has_user_resource_permission( + session=session, + groups=context.groups, + permission_name=permissions, + resource_uri=entityUri, + ): + result_permissions.append(permissions) + return result_permissions diff --git a/backend/dataall/modules/redshift_datasets/services/redshift_dataset_service.py b/backend/dataall/modules/redshift_datasets/services/redshift_dataset_service.py index 2edf3724c..f578894b0 100644 --- a/backend/dataall/modules/redshift_datasets/services/redshift_dataset_service.py +++ b/backend/dataall/modules/redshift_datasets/services/redshift_dataset_service.py @@ -193,6 +193,7 @@ def delete_redshift_dataset(uri): RedshiftDatasetService._delete_dataset_term_links(session, uri) VoteRepository.delete_votes(session, dataset.datasetUri, VOTE_REDSHIFT_DATASET_NAME) session.delete(dataset) + session.commit() return True diff --git a/backend/dataall/modules/s3_datasets/services/dataset_service.py b/backend/dataall/modules/s3_datasets/services/dataset_service.py index 14cfdc2fd..2e68eb951 100644 --- a/backend/dataall/modules/s3_datasets/services/dataset_service.py +++ b/backend/dataall/modules/s3_datasets/services/dataset_service.py @@ -22,7 +22,6 @@ from dataall.modules.catalog.db.glossary_repositories import GlossaryRepository from dataall.modules.s3_datasets.db.dataset_bucket_repositories import DatasetBucketRepository from dataall.modules.shares_base.db.share_object_repositories import ShareObjectRepository -from dataall.modules.shares_base.services.share_object_service import ShareObjectService from dataall.modules.vote.db.vote_repositories import VoteRepository from dataall.modules.s3_datasets.aws.glue_dataset_client import DatasetCrawler from dataall.modules.s3_datasets.aws.s3_dataset_client import S3DatasetClient diff --git a/backend/migrations/versions/075d344ae2cc_mf_triggers.py b/backend/migrations/versions/075d344ae2cc_mf_triggers.py new file mode 100644 index 000000000..35b1a9b5e --- /dev/null +++ b/backend/migrations/versions/075d344ae2cc_mf_triggers.py @@ -0,0 +1,153 @@ +"""mf_triggers + +Revision ID: 075d344ae2cc +Revises: 427db8f31999 +Create Date: 2024-09-13 13:12:16.951311 + +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '075d344ae2cc' +down_revision = '427db8f31999' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute(""" + CREATE OR REPLACE FUNCTION org_delete_trigger_function() + RETURNS TRIGGER AS $$ + BEGIN + -- Delete from attached_metadata_form + DELETE FROM attached_metadata_form + WHERE "entityUri" = OLD."organizationUri" + AND "entityType" = 'Organization'; + + -- Delete from metadata_form + DELETE FROM metadata_form + WHERE "homeEntity" = OLD."organizationUri" + AND visibility = 'Organization-Wide'; + + RETURN OLD; + END; + $$ LANGUAGE plpgsql; + + -- Create the trigger for organization table + CREATE TRIGGER org_delete_trigger + BEFORE DELETE ON organization + FOR EACH ROW + EXECUTE FUNCTION org_delete_trigger_function(); + """) + + op.execute(""" + CREATE OR REPLACE FUNCTION env_delete_trigger_function() + RETURNS TRIGGER AS $$ + BEGIN + -- Delete from attached_metadata_form + DELETE FROM attached_metadata_form + WHERE "entityUri" = OLD."environmentUri" + AND "entityType" = 'Environment'; + + -- Delete from metadata_form + DELETE FROM metadata_form + WHERE "homeEntity" = OLD."environmentUri" + AND visibility = 'Environment-Wide'; + + RETURN OLD; + END; + $$ LANGUAGE plpgsql; + + -- Create the trigger for environment table + CREATE TRIGGER env_delete_trigger + BEFORE DELETE ON environment + FOR EACH ROW + EXECUTE FUNCTION env_delete_trigger_function(); + """) + + op.execute(""" + CREATE OR REPLACE FUNCTION dataset_delete_trigger_function() + RETURNS TRIGGER AS $$ + BEGIN + -- Delete from attached_metadata_form + DELETE FROM attached_metadata_form + WHERE "entityUri" = OLD."datasetUri" + AND "entityType" = 'Dataset'; + + RETURN OLD; + END; + $$ LANGUAGE plpgsql; + + -- Create the trigger for dataset table + CREATE TRIGGER dataset_delete_trigger + BEFORE DELETE ON dataset + FOR EACH ROW + EXECUTE FUNCTION dataset_delete_trigger_function(); + """) + + op.execute(""" + CREATE OR REPLACE FUNCTION metadata_form_delete_trigger_function() + RETURNS TRIGGER AS $$ + BEGIN + -- Delete from resource_permission_policy + DELETE FROM resource_policy_permission + WHERE "sid" in (SELECT sid from resource_policy where "resourceUri"=OLD.uri and "resourceType"='MetadataForm'); + DELETE FROM resource_policy where "resourceUri"=OLD.uri; + RETURN OLD; + END; + $$ LANGUAGE plpgsql; + + -- Create the trigger for dataset table + CREATE TRIGGER metadata_form_delete_trigger + BEFORE DELETE ON metadata_form + FOR EACH ROW + EXECUTE FUNCTION metadata_form_delete_trigger_function(); + """) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute( + """ + -- Drop the org_delete_trigger + DROP TRIGGER IF EXISTS org_delete_trigger ON organization; + + -- Drop the org_delete_trigger_function + DROP FUNCTION IF EXISTS org_delete_trigger_function; + """ + ) + + op.execute( + """ + -- Drop the env_delete_trigger + DROP TRIGGER IF EXISTS env_delete_trigger ON environment; + + -- Drop the env_delete_trigger_function + DROP FUNCTION IF EXISTS env_delete_trigger_function; + """ + ) + + op.execute( + """ + -- Drop the dataset_delete_trigger + DROP TRIGGER IF EXISTS dataset_delete_trigger ON dataset; + + -- Drop the dataset_delete_trigger_function + DROP FUNCTION IF EXISTS dataset_delete_trigger_function; + """ + ) + + op.execute( + """ + -- Drop the dataset_delete_trigger + DROP TRIGGER IF EXISTS metadata_form_delete_trigger ON metadata_form; + + -- Drop the dataset_delete_trigger_function + DROP FUNCTION IF EXISTS metadata_form_delete_trigger_function; + """ + ) + # ### end Alembic commands ### diff --git a/backend/migrations/versions/427db8f31999_backfill_MF_resource_permissions.py b/backend/migrations/versions/427db8f31999_backfill_MF_resource_permissions.py new file mode 100644 index 000000000..5209963e8 --- /dev/null +++ b/backend/migrations/versions/427db8f31999_backfill_MF_resource_permissions.py @@ -0,0 +1,127 @@ +"""backfill_MF_resource_permissions + +Revision ID: 427db8f31999 +Revises: f87aecc36d39 +Create Date: 2024-09-11 15:55:51.444403 + +""" + +from alembic import op +from sqlalchemy import orm + +from dataall.core.environment.db.environment_models import Environment +from dataall.core.organizations.db.organization_models import Organization +from dataall.core.permissions.api.enums import PermissionType +from dataall.core.permissions.services.permission_service import PermissionService +from dataall.core.permissions.services.resource_policy_service import ResourcePolicyService +from dataall.core.permissions.services.resources_permissions import RESOURCES_ALL_WITH_DESC +from dataall.modules.datasets_base.db.dataset_models import DatasetBase +from dataall.modules.metadata_forms.services.metadata_form_permissions import ( + ATTACH_METADATA_FORM, + CREATE_METADATA_FORM, + METADATA_FORM_PERMISSIONS_ALL, +) + +# revision identifiers, used by Alembic. +revision = '427db8f31999' +down_revision = 'f87aecc36d39' +branch_labels = None +depends_on = None + + +def get_session(): + bind = op.get_bind() + session = orm.Session(bind=bind) + return session + + +def upgrade(): + session = get_session() + + for perm in [ATTACH_METADATA_FORM, CREATE_METADATA_FORM] + METADATA_FORM_PERMISSIONS_ALL: + PermissionService.save_permission( + session, + name=perm, + description=RESOURCES_ALL_WITH_DESC.get(perm, perm), + permission_type=PermissionType.RESOURCE.name, + ) + print('Adding organization resource permissions...') + orgs = session.query(Organization).all() + for org in orgs: + ResourcePolicyService.attach_resource_policy( + session=session, + group=org.SamlGroupName, + resource_uri=org.organizationUri, + permissions=[ATTACH_METADATA_FORM, CREATE_METADATA_FORM], + resource_type=Organization.__name__, + ) + print('Adding environment resource permissions...') + envs = session.query(Environment).all() + for env in envs: + ResourcePolicyService.attach_resource_policy( + session=session, + group=env.SamlGroupName, + resource_uri=env.environmentUri, + permissions=[ATTACH_METADATA_FORM, CREATE_METADATA_FORM], + resource_type=Environment.__name__, + ) + print('Adding dataset resource permissions...') + datasets = session.query(DatasetBase).all() + for dataset in datasets: + ResourcePolicyService.attach_resource_policy( + session=session, + group=dataset.SamlAdminGroupName, + resource_uri=dataset.datasetUri, + permissions=[ATTACH_METADATA_FORM], + resource_type=DatasetBase.__name__, + ) + + +def downgrade(): + bind = op.get_bind() + session = orm.Session(bind=bind) + all_environments = session.query(Environment).all() + for env in all_environments: + policies = ResourcePolicyService.find_resource_policies( + session=session, + group=env.SamlGroupName, + resource_uri=env.environmentUri, + resource_type=Environment.__name__, + permissions=[ATTACH_METADATA_FORM, CREATE_METADATA_FORM], + ) + for policy in policies: + for resource_pol_permission in policy.permissions: + if resource_pol_permission.permission.name in [ATTACH_METADATA_FORM, CREATE_METADATA_FORM]: + session.delete(resource_pol_permission) + session.commit() + + all_organizations = session.query(Organization).all() + for org in all_organizations: + policies = ResourcePolicyService.find_resource_policies( + session=session, + group=org.SamlGroupName, + resource_uri=org.organizationUri, + permissions=[ATTACH_METADATA_FORM, CREATE_METADATA_FORM], + resource_type=Organization.__name__, + ) + for policy in policies: + for resource_pol_permission in policy.permissions: + if resource_pol_permission.permission.name in [ATTACH_METADATA_FORM, CREATE_METADATA_FORM]: + session.delete(resource_pol_permission) + session.commit() + + datasets = session.query(DatasetBase).all() + for dataset in datasets: + policies = ResourcePolicyService.find_resource_policies( + session=session, + group=dataset.SamlAdminGroupName, + resource_uri=dataset.datasetUri, + permissions=[ATTACH_METADATA_FORM], + resource_type=DatasetBase.__name__, + ) + + for policy in policies: + for resource_pol_permission in policy.permissions: + if resource_pol_permission.permission.name in [ATTACH_METADATA_FORM, CREATE_METADATA_FORM]: + session.delete(resource_pol_permission) + session.commit() diff --git a/backend/migrations/versions/852cdf6cf1e0_add_redshift_datasets.py b/backend/migrations/versions/852cdf6cf1e0_add_redshift_datasets.py index 3e7a38c35..422d1ffbb 100644 --- a/backend/migrations/versions/852cdf6cf1e0_add_redshift_datasets.py +++ b/backend/migrations/versions/852cdf6cf1e0_add_redshift_datasets.py @@ -146,6 +146,7 @@ def downgrade(): permissions=ENVIRONMENT_REDSHIFT_ALL, ) for policy in policies: - for permission in policy.permissions: - session.delete(permission) - session.commit() + for resource_pol_permission in policy.permissions: + if resource_pol_permission.permission.name in ENVIRONMENT_REDSHIFT_ALL: + session.delete(resource_pol_permission) + session.commit() diff --git a/backend/migrations/versions/f87aecc36d39_attached_field_type_enum.py b/backend/migrations/versions/f87aecc36d39_attached_field_type_enum.py index 391b52f21..68ab75285 100644 --- a/backend/migrations/versions/f87aecc36d39_attached_field_type_enum.py +++ b/backend/migrations/versions/f87aecc36d39_attached_field_type_enum.py @@ -118,8 +118,8 @@ def upgrade(): def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.execute('DROP TYPE metadataformfieldtype') op.alter_column('attached_metadata_form_field', 'type', type_=sa.VARCHAR(), existing_nullable=True) + op.execute('DROP TYPE metadataformfieldtype CASCADE') # ### end Alembic commands ### # ### commands auto generated by Alembic - please adjust! ### diff --git a/frontend/src/modules/Environments/views/EnvironmentView.js b/frontend/src/modules/Environments/views/EnvironmentView.js index 790d97f57..de5d91ee1 100644 --- a/frontend/src/modules/Environments/views/EnvironmentView.js +++ b/frontend/src/modules/Environments/views/EnvironmentView.js @@ -275,7 +275,6 @@ const EnvironmentView = () => { )} {currentTab === 'teams' && } diff --git a/frontend/src/modules/Metadata_Forms/components/metadataAttachment.js b/frontend/src/modules/Metadata_Forms/components/metadataAttachment.js index e29f78675..1ac206290 100644 --- a/frontend/src/modules/Metadata_Forms/components/metadataAttachment.js +++ b/frontend/src/modules/Metadata_Forms/components/metadataAttachment.js @@ -16,6 +16,7 @@ import { import { deleteAttachedMetadataForm, getAttachedMetadataForm, + getEntityMetadataFormPermissions, getMetadataForm, listAttachedMetadataForms, listEntityMetadataForms @@ -30,7 +31,7 @@ import DoNotDisturbAltOutlinedIcon from '@mui/icons-material/DoNotDisturbAltOutl import DeleteIcon from '@mui/icons-material/DeleteOutlined'; export const MetadataAttachment = (props) => { - const { entityType, entityUri, canEdit } = props; + const { entityType, entityUri } = props; const client = useClient(); const dispatch = useDispatch(); const [selectedForm, setSelectedForm] = useState(null); @@ -38,6 +39,7 @@ export const MetadataAttachment = (props) => { const [loadingFields, setLoadingFields] = useState(false); const [formsList, setFormsList] = useState([]); const [fields, setFields] = useState([]); + const [canEdit, setCanEdit] = useState(false); const [filter] = useState({ ...Defaults.filter, entityType: entityType, @@ -139,9 +141,25 @@ export const MetadataAttachment = (props) => { } }; + const getPermissions = async () => { + const response = await client.query( + getEntityMetadataFormPermissions(entityUri) + ); + if (!response.errors) { + setCanEdit( + response.data.getEntityMetadataFormPermissions.includes( + 'ATTACH_METADATA_FORM' + ) + ); + } + }; + useEffect(() => { if (client) { fetchList().catch((e) => dispatch({ type: SET_ERROR, error: e.message })); + getPermissions().catch((e) => + dispatch({ type: SET_ERROR, error: e.message }) + ); fetchAvailableForms().catch((e) => dispatch({ type: SET_ERROR, error: e.message }) ); diff --git a/frontend/src/modules/Metadata_Forms/services/getMetadataFormEntityPermissions.js b/frontend/src/modules/Metadata_Forms/services/getMetadataFormEntityPermissions.js new file mode 100644 index 000000000..ca268874b --- /dev/null +++ b/frontend/src/modules/Metadata_Forms/services/getMetadataFormEntityPermissions.js @@ -0,0 +1,12 @@ +import { gql } from 'apollo-boost'; + +export const getEntityMetadataFormPermissions = (entityUri) => ({ + variables: { + entityUri + }, + query: gql` + query getEntityMetadataFormPermissions($entityUri: String!) { + getEntityMetadataFormPermissions(entityUri: $entityUri) + } + ` +}); diff --git a/frontend/src/modules/Metadata_Forms/services/index.js b/frontend/src/modules/Metadata_Forms/services/index.js index 99e3b2312..74c383379 100644 --- a/frontend/src/modules/Metadata_Forms/services/index.js +++ b/frontend/src/modules/Metadata_Forms/services/index.js @@ -8,3 +8,4 @@ export * from './attachMetadataForm'; export * from './getAttachedMetadataForm'; export * from './listAttachedMetadataForms'; export * from './deleteAttachedMetadataForm'; +export * from './getMetadataFormEntityPermissions'; diff --git a/frontend/src/modules/Organizations/views/OrganizationView.js b/frontend/src/modules/Organizations/views/OrganizationView.js index ccc868a39..758409c46 100644 --- a/frontend/src/modules/Organizations/views/OrganizationView.js +++ b/frontend/src/modules/Organizations/views/OrganizationView.js @@ -237,7 +237,6 @@ const OrganizationView = () => { )} diff --git a/frontend/src/modules/S3_Datasets/views/DatasetView.js b/frontend/src/modules/S3_Datasets/views/DatasetView.js index 6f1800a64..f47b376c1 100644 --- a/frontend/src/modules/S3_Datasets/views/DatasetView.js +++ b/frontend/src/modules/S3_Datasets/views/DatasetView.js @@ -362,11 +362,7 @@ const DatasetView = () => { )} {currentTab === 'metadata' && ( - + )} {currentTab === 'overview' && (