This is an automated email from the ASF dual-hosted git repository. machristie pushed a commit to branch custos-integration in repository https://gitbox.apache.org/repos/asf/airavata-data-catalog.git
commit a0c86b28e7f92cf47cf892482d9594a478a704b7 Author: Marcus Christie <[email protected]> AuthorDate: Tue Apr 25 09:57:10 2023 -0400 Initial simple sharing implementation with user sharing implemented --- .../api/DataCatalogApiServiceApplication.java | 16 ++ .../model/{UserEntity.java => GroupEntity.java} | 41 ++-- .../airavata/datacatalog/api/model/UserEntity.java | 1 + .../model/sharing/simple/SimpleGroupEntity.java | 103 ++++++++ .../sharing/simple/SimpleGroupSharingEntity.java | 109 +++++++++ .../simple/SimpleTenantEntity.java} | 43 ++-- .../api/model/sharing/simple/SimpleUserEntity.java | 108 +++++++++ .../sharing/simple/SimpleUserSharingEntity.java | 109 +++++++++ .../api/repository/GroupRepository.java | 13 ++ .../api/repository/TenantRepository.java | 3 + .../datacatalog/api/repository/UserRepository.java | 14 ++ .../sharing/simple/SimpleGroupRepository.java | 12 + .../simple/SimpleGroupSharingRepository.java | 13 ++ .../sharing/simple/SimpleTenantRepository.java | 11 + .../sharing/simple/SimpleUserRepository.java | 12 + .../simple/SimpleUserSharingRepository.java | 13 ++ .../api/sharing/SimpleSharingManagerImpl.java | 259 +++++++++++++++++++++ .../src/main/resources/application.properties | 5 + .../server/src/main/resources/schema.sql | 36 +++ .../api/sharing/SimpleSharingManagerImplTest.java | 138 +++++++++++ 20 files changed, 1014 insertions(+), 45 deletions(-) diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/DataCatalogApiServiceApplication.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/DataCatalogApiServiceApplication.java index 7b6bd4e..fb35723 100644 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/DataCatalogApiServiceApplication.java +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/DataCatalogApiServiceApplication.java @@ -1,9 +1,15 @@ package org.apache.airavata.datacatalog.api; +import org.apache.airavata.datacatalog.api.sharing.SharingManager; +import org.apache.airavata.datacatalog.api.sharing.SharingManagerImpl; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Primary; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @ComponentScan(basePackages = { "org.apache.airavata.datacatalog.api", "org.apache.custos.sharing.core" }) @@ -14,8 +20,18 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; "org.apache.custos.sharing.core.persistance.model" }) public class DataCatalogApiServiceApplication { + @Autowired + private ApplicationContext applicationContext; + public static void main(String[] args) { SpringApplication.run(DataCatalogApiServiceApplication.class, args); } + @Bean + @Primary + public SharingManager getSharingManager() { + // TODO: externalize bean name to a property + // return (SharingManager) applicationContext.getBean("simpleSharingManager"); + return applicationContext.getBean(SharingManagerImpl.class); + } } diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/GroupEntity.java similarity index 68% copy from data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java copy to data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/GroupEntity.java index 20a4a3c..4c6caf7 100644 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/GroupEntity.java @@ -11,26 +11,23 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; +// TODO: not needed? +// TODO: need a unique constraint on (tenant, externalId) @Entity -// 'user' is a reserved word, so naming this table 'user_table' -@Table(name = "user_table") -public class UserEntity { +@Table(name = "user_group") +public class GroupEntity { @Id - @SequenceGenerator(name = "user_user_id_seq", sequenceName = "user_user_id_seq", allocationSize = 1) - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_user_id_seq") - @Column(name = "user_id") - private Long userId; - - /** - * The identifier for the user. This external identifier comes from the user - * management service that data catalog is configured to use. - */ + @SequenceGenerator(name = "user_group_group_id", sequenceName = "user_group_group_id", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_group_group_id") + @Column(name = "group_id") + private Long groupId; + @Basic @Column(name = "external_id", nullable = false) private String externalId; - @Basic + @Column(name = "name", nullable = false) private String name; @@ -38,12 +35,12 @@ public class UserEntity { @JoinColumn(name = "tenant_id", referencedColumnName = "tenant_id", nullable = false, updatable = false) private TenantEntity tenant; - public Long getUserId() { - return userId; + public Long getGroupId() { + return groupId; } - public void setUserId(Long userId) { - this.userId = userId; + public void setGroupId(Long groupId) { + this.groupId = groupId; } public String getExternalId() { @@ -74,7 +71,7 @@ public class UserEntity { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((userId == null) ? 0 : userId.hashCode()); + result = prime * result + ((groupId == null) ? 0 : groupId.hashCode()); return result; } @@ -86,11 +83,11 @@ public class UserEntity { return false; if (getClass() != obj.getClass()) return false; - UserEntity other = (UserEntity) obj; - if (userId == null) { - if (other.userId != null) + GroupEntity other = (GroupEntity) obj; + if (groupId == null) { + if (other.groupId != null) return false; - } else if (!userId.equals(other.userId)) + } else if (!groupId.equals(other.groupId)) return false; return true; } diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java index 20a4a3c..3cff66a 100644 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java @@ -11,6 +11,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; +// TODO: need a unique constraint on (tenant, externalId) @Entity // 'user' is a reserved word, so naming this table 'user_table' @Table(name = "user_table") diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupEntity.java new file mode 100644 index 0000000..26416a3 --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupEntity.java @@ -0,0 +1,103 @@ +package org.apache.airavata.datacatalog.api.model.sharing.simple; + +import java.util.HashSet; +import java.util.Set; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; + +// TODO: need a unique constraint on (tenant, externalId) +@Entity +@Table(name = "simple_group") +public class SimpleGroupEntity { + + @Id + @SequenceGenerator(name = "simple_group_simple_group_id", sequenceName = "simple_group_simple_group_id", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "simple_group_simple_group_id") + @Column(name = "simple_group_id") + private Long simpleGroupId; + + @Basic + @Column(name = "external_id", nullable = false) + private String externalId; + + @Basic + @Column(name = "name", nullable = false) + private String name; + + @ManyToOne(optional = false) + @JoinColumn(name = "simple_tenant_id", referencedColumnName = "simple_tenant_id", nullable = false, updatable = false) + private SimpleTenantEntity simpleTenant; + + @ManyToMany + @JoinTable(name = "simple_group_membership", joinColumns = @JoinColumn(name = "simple_group_id"), inverseJoinColumns = @JoinColumn(name = "simple_user_id")) + private Set<SimpleUserEntity> memberUsers = new HashSet<>(); + + public Long getSimpleGroupId() { + return simpleGroupId; + } + + public void setSimpleGroupId(Long simpleGroupId) { + this.simpleGroupId = simpleGroupId; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SimpleTenantEntity getSimpleTenant() { + return simpleTenant; + } + + public void setSimpleTenant(SimpleTenantEntity simpleTenant) { + this.simpleTenant = simpleTenant; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((simpleGroupId == null) ? 0 : simpleGroupId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SimpleGroupEntity other = (SimpleGroupEntity) obj; + if (simpleGroupId == null) { + if (other.simpleGroupId != null) + return false; + } else if (!simpleGroupId.equals(other.simpleGroupId)) + return false; + return true; + } + +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupSharingEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupSharingEntity.java new file mode 100644 index 0000000..bf5d0fd --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupSharingEntity.java @@ -0,0 +1,109 @@ +package org.apache.airavata.datacatalog.api.model.sharing.simple; + +import org.apache.airavata.datacatalog.api.Permission; +import org.apache.airavata.datacatalog.api.model.DataProductEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; + +@Entity +@Table(name = "simple_group_sharing") +public class SimpleGroupSharingEntity { + + @Id + @SequenceGenerator(name = "simple_group_sharing_sharing_id", sequenceName = "simple_group_sharing_sharing_id", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "simple_group_sharing_sharing_id") + @Column(name = "sharing_id") + private Long sharingId; + + @ManyToOne(optional = false) + @JoinColumn(name = "simple_group_id", referencedColumnName = "simple_group_id", nullable = false, updatable = false) + private SimpleGroupEntity simpleGroup; + + @ManyToOne(optional = false) + @JoinColumn(name = "data_product_id", referencedColumnName = "data_product_id", nullable = false, updatable = false) + private DataProductEntity dataProduct; + + @Column(name = "permission_id") + @Enumerated(EnumType.STRING) + private Permission permission; + + @ManyToOne + @JoinColumn(name = "shared_by_user_id", referencedColumnName = "user_id") + private SimpleUserEntity sharedByUser; + + public Long getSharingId() { + return sharingId; + } + + public void setSharingId(Long sharingId) { + this.sharingId = sharingId; + } + + public SimpleGroupEntity getSimpleGroup() { + return simpleGroup; + } + + public void setSimpleGroup(SimpleGroupEntity simpleGroup) { + this.simpleGroup = simpleGroup; + } + + public DataProductEntity getDataProduct() { + return dataProduct; + } + + public void setDataProduct(DataProductEntity dataProduct) { + this.dataProduct = dataProduct; + } + + public Permission getPermission() { + return permission; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } + + public SimpleUserEntity getSharedByUser() { + return sharedByUser; + } + + public void setSharedByUser(SimpleUserEntity sharedByUser) { + this.sharedByUser = sharedByUser; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((sharingId == null) ? 0 : sharingId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SimpleGroupSharingEntity other = (SimpleGroupSharingEntity) obj; + if (sharingId == null) { + if (other.sharingId != null) + return false; + } else if (!sharingId.equals(other.sharingId)) + return false; + return true; + } + +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleTenantEntity.java similarity index 61% copy from data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java copy to data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleTenantEntity.java index 20a4a3c..eabadcb 100644 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/UserEntity.java +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleTenantEntity.java @@ -1,4 +1,6 @@ -package org.apache.airavata.datacatalog.api.model; +package org.apache.airavata.datacatalog.api.model.sharing.simple; + +import org.apache.airavata.datacatalog.api.model.TenantEntity; import jakarta.persistence.Basic; import jakarta.persistence.Column; @@ -12,20 +14,15 @@ import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; @Entity -// 'user' is a reserved word, so naming this table 'user_table' -@Table(name = "user_table") -public class UserEntity { +@Table(name = "simple_tenant") +public class SimpleTenantEntity { @Id - @SequenceGenerator(name = "user_user_id_seq", sequenceName = "user_user_id_seq", allocationSize = 1) - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_user_id_seq") - @Column(name = "user_id") - private Long userId; - - /** - * The identifier for the user. This external identifier comes from the user - * management service that data catalog is configured to use. - */ + @SequenceGenerator(name = "simple_tenant_simple_tenant_id_seq", sequenceName = "simple_tenant_simple_tenant_id_seq", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "simple_tenant_simple_tenant_id_seq") + @Column(name = "simple_tenant_id") + private Long simpleTenantId; + @Basic @Column(name = "external_id", nullable = false) private String externalId; @@ -35,15 +32,15 @@ public class UserEntity { private String name; @ManyToOne(optional = false) - @JoinColumn(name = "tenant_id", referencedColumnName = "tenant_id", nullable = false, updatable = false) + @JoinColumn(name = "tenant_id", nullable = false, updatable = false) private TenantEntity tenant; - public Long getUserId() { - return userId; + public Long getSimpleTenantId() { + return simpleTenantId; } - public void setUserId(Long userId) { - this.userId = userId; + public void setSimpleTenantId(Long simpleTenantId) { + this.simpleTenantId = simpleTenantId; } public String getExternalId() { @@ -74,7 +71,7 @@ public class UserEntity { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((userId == null) ? 0 : userId.hashCode()); + result = prime * result + ((simpleTenantId == null) ? 0 : simpleTenantId.hashCode()); return result; } @@ -86,11 +83,11 @@ public class UserEntity { return false; if (getClass() != obj.getClass()) return false; - UserEntity other = (UserEntity) obj; - if (userId == null) { - if (other.userId != null) + SimpleTenantEntity other = (SimpleTenantEntity) obj; + if (simpleTenantId == null) { + if (other.simpleTenantId != null) return false; - } else if (!userId.equals(other.userId)) + } else if (!simpleTenantId.equals(other.simpleTenantId)) return false; return true; } diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleUserEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleUserEntity.java new file mode 100644 index 0000000..83114f7 --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleUserEntity.java @@ -0,0 +1,108 @@ +package org.apache.airavata.datacatalog.api.model.sharing.simple; + +import org.apache.airavata.datacatalog.api.model.UserEntity; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; + +// TODO: need a unique constraint on (tenant, externalId) +@Entity +@Table(name = "simple_user") +public class SimpleUserEntity { + + @Id + @SequenceGenerator(name = "simple_user_simple_user_id_seq", sequenceName = "simple_user_simple_user_id_seq", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "simple_user_simple_user_id_seq") + @Column(name = "simple_user_id") + private Long simpleUserId; + + @Basic + @Column(name = "external_id", nullable = false) + private String externalId; + + @Basic + @Column(name = "name", nullable = false) + private String name; + + @ManyToOne(optional = false) + @JoinColumn(name = "simple_tenant_id", referencedColumnName = "simple_tenant_id", nullable = false, updatable = false) + private SimpleTenantEntity simpleTenant; + + @ManyToOne(optional = false) + @JoinColumn(name = "user_id", nullable = false, updatable = false) + private UserEntity user; + + public Long getSimpleUserId() { + return simpleUserId; + } + + public void setSimpleUserId(Long simpleUserId) { + this.simpleUserId = simpleUserId; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SimpleTenantEntity getSimpleTenant() { + return simpleTenant; + } + + public void setSimpleTenant(SimpleTenantEntity tenant) { + this.simpleTenant = tenant; + } + + public UserEntity getUser() { + return user; + } + + public void setUser(UserEntity user) { + this.user = user; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((simpleUserId == null) ? 0 : simpleUserId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SimpleUserEntity other = (SimpleUserEntity) obj; + if (simpleUserId == null) { + if (other.simpleUserId != null) + return false; + } else if (!simpleUserId.equals(other.simpleUserId)) + return false; + return true; + } + +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleUserSharingEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleUserSharingEntity.java new file mode 100644 index 0000000..428537e --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleUserSharingEntity.java @@ -0,0 +1,109 @@ +package org.apache.airavata.datacatalog.api.model.sharing.simple; + +import org.apache.airavata.datacatalog.api.Permission; +import org.apache.airavata.datacatalog.api.model.DataProductEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; + +@Entity +@Table(name = "simple_user_sharing") +public class SimpleUserSharingEntity { + + @Id + @SequenceGenerator(name = "simple_user_sharing_sharing_id", sequenceName = "simple_user_sharing_sharing_id", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "simple_user_sharing_sharing_id") + @Column(name = "sharing_id") + private Long sharingId; + + @ManyToOne(optional = false) + @JoinColumn(name = "simple_user_id", nullable = false, updatable = false) + private SimpleUserEntity simpleUser; + + @ManyToOne(optional = false) + @JoinColumn(name = "data_product_id", nullable = false, updatable = false) + private DataProductEntity dataProduct; + + @Column(name = "permission_id") + @Enumerated(EnumType.STRING) + private Permission permission; + + @ManyToOne + @JoinColumn(name = "shared_by_user_id") + private SimpleUserEntity sharedByUser; + + public Long getSharingId() { + return sharingId; + } + + public void setSharingId(Long sharingId) { + this.sharingId = sharingId; + } + + public SimpleUserEntity getSimpleUser() { + return simpleUser; + } + + public void setSimpleUser(SimpleUserEntity simpleUser) { + this.simpleUser = simpleUser; + } + + public DataProductEntity getDataProduct() { + return dataProduct; + } + + public void setDataProduct(DataProductEntity dataProduct) { + this.dataProduct = dataProduct; + } + + public Permission getPermission() { + return permission; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } + + public SimpleUserEntity getSharedByUser() { + return sharedByUser; + } + + public void setSharedByUser(SimpleUserEntity sharedByUser) { + this.sharedByUser = sharedByUser; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((sharingId == null) ? 0 : sharingId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SimpleUserSharingEntity other = (SimpleUserSharingEntity) obj; + if (sharingId == null) { + if (other.sharingId != null) + return false; + } else if (!sharingId.equals(other.sharingId)) + return false; + return true; + } + +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/GroupRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/GroupRepository.java new file mode 100644 index 0000000..f821fd9 --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/GroupRepository.java @@ -0,0 +1,13 @@ +package org.apache.airavata.datacatalog.api.repository; + +import java.util.Optional; + +import org.apache.airavata.datacatalog.api.model.GroupEntity; +import org.apache.airavata.datacatalog.api.model.TenantEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +// TODO: not needed? +public interface GroupRepository extends JpaRepository<GroupEntity, Long> { + + Optional<GroupEntity> findByExternalIdAndTenant(String externalId, TenantEntity tenantEntity); +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/TenantRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/TenantRepository.java index a90d0db..0964017 100644 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/TenantRepository.java +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/TenantRepository.java @@ -1,5 +1,7 @@ package org.apache.airavata.datacatalog.api.repository; +import java.util.Optional; + import org.apache.airavata.datacatalog.api.model.TenantEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.transaction.annotation.Transactional; @@ -7,4 +9,5 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public interface TenantRepository extends JpaRepository<TenantEntity, Long> { + Optional<TenantEntity> findByExternalId(String externalId); } diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/UserRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/UserRepository.java new file mode 100644 index 0000000..301f2ee --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/UserRepository.java @@ -0,0 +1,14 @@ +package org.apache.airavata.datacatalog.api.repository; + +import java.util.Optional; + +import org.apache.airavata.datacatalog.api.model.TenantEntity; +import org.apache.airavata.datacatalog.api.model.UserEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository<UserEntity, Long> { + + Optional<UserEntity> findByExternalIdAndTenant(String externalId, TenantEntity tenantEntity); + + Optional<UserEntity> findByExternalIdAndTenant_ExternalId(String externalId, String tenantExternalId); +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleGroupRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleGroupRepository.java new file mode 100644 index 0000000..855736f --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleGroupRepository.java @@ -0,0 +1,12 @@ +package org.apache.airavata.datacatalog.api.repository.sharing.simple; + +import java.util.Optional; + +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleGroupEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleTenantEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SimpleGroupRepository extends JpaRepository<SimpleGroupEntity, Long> { + + Optional<SimpleGroupEntity> findByExternalIdAndSimpleTenant(String externalId, SimpleTenantEntity simpleTenant); +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleGroupSharingRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleGroupSharingRepository.java new file mode 100644 index 0000000..1fea593 --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleGroupSharingRepository.java @@ -0,0 +1,13 @@ +package org.apache.airavata.datacatalog.api.repository.sharing.simple; + +import java.util.Optional; + +import org.apache.airavata.datacatalog.api.Permission; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleGroupSharingEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SimpleGroupSharingRepository extends JpaRepository<SimpleGroupSharingEntity, Long> { + + Optional<SimpleGroupSharingEntity> findBySimpleGroup_SimpleGroupIdAndDataProduct_DataProductIdAndPermission( + long groupId, long dataProductId, Permission permission); +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleTenantRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleTenantRepository.java new file mode 100644 index 0000000..d45dd2a --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleTenantRepository.java @@ -0,0 +1,11 @@ +package org.apache.airavata.datacatalog.api.repository.sharing.simple; + +import java.util.Optional; + +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleTenantEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SimpleTenantRepository extends JpaRepository<SimpleTenantEntity, Long> { + + Optional<SimpleTenantEntity> findByExternalId(String externalId); +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserRepository.java new file mode 100644 index 0000000..515da5a --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserRepository.java @@ -0,0 +1,12 @@ +package org.apache.airavata.datacatalog.api.repository.sharing.simple; + +import java.util.Optional; + +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleTenantEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleUserEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SimpleUserRepository extends JpaRepository<SimpleUserEntity, Long> { + + Optional<SimpleUserEntity> findByExternalIdAndSimpleTenant(String externalId, SimpleTenantEntity simpleTenant); +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserSharingRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserSharingRepository.java new file mode 100644 index 0000000..a94f809 --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserSharingRepository.java @@ -0,0 +1,13 @@ +package org.apache.airavata.datacatalog.api.repository.sharing.simple; + +import java.util.Optional; + +import org.apache.airavata.datacatalog.api.Permission; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleUserSharingEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SimpleUserSharingRepository extends JpaRepository<SimpleUserSharingEntity, Long> { + + Optional<SimpleUserSharingEntity> findBySimpleUser_SimpleUserIdAndDataProduct_DataProductIdAndPermission( + long userId, long dataProductId, Permission permission); +} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImpl.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImpl.java new file mode 100644 index 0000000..f5d42d3 --- /dev/null +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImpl.java @@ -0,0 +1,259 @@ +package org.apache.airavata.datacatalog.api.sharing; + +import java.util.Optional; + +import org.apache.airavata.datacatalog.api.DataProduct; +import org.apache.airavata.datacatalog.api.GroupInfo; +import org.apache.airavata.datacatalog.api.Permission; +import org.apache.airavata.datacatalog.api.UserInfo; +import org.apache.airavata.datacatalog.api.exception.SharingException; +import org.apache.airavata.datacatalog.api.model.DataProductEntity; +import org.apache.airavata.datacatalog.api.model.TenantEntity; +import org.apache.airavata.datacatalog.api.model.UserEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleGroupEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleGroupSharingEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleTenantEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleUserEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleUserSharingEntity; +import org.apache.airavata.datacatalog.api.repository.DataProductRepository; +import org.apache.airavata.datacatalog.api.repository.TenantRepository; +import org.apache.airavata.datacatalog.api.repository.UserRepository; +import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleGroupRepository; +import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleGroupSharingRepository; +import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleTenantRepository; +import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleUserRepository; +import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleUserSharingRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; + +@Component("simpleSharingManager") +public class SimpleSharingManagerImpl implements SharingManager { + + @Autowired + private TenantRepository tenantRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private DataProductRepository dataProductRepository; + + @Autowired + private SimpleUserSharingRepository simpleUserSharingRepository; + + @Autowired + private SimpleGroupSharingRepository simpleGroupSharingRepository; + + @Autowired + private SimpleTenantRepository simpleTenantRepository; + + @Autowired + private SimpleUserRepository simpleUserRepository; + + @Autowired + private SimpleGroupRepository simpleGroupRepository; + + @PersistenceContext + private EntityManager entityManager; + + @Override + public void initialize(String tenantId) throws SharingException { + // TODO: create a public group for the tenantId + } + + @Override + public UserEntity resolveUser(UserInfo userInfo) throws SharingException { + SimpleUserEntity simpleUser = resolveSimpleUser(userInfo); + return simpleUser.getUser(); + } + + @Override + public boolean userHasAccess(UserInfo userInfo, DataProduct dataProduct, Permission permission) + throws SharingException { + UserEntity user = resolveUser(userInfo); + DataProductEntity dataProductEntity = resolveDataProduct(dataProduct); + Query query = entityManager.createNativeQuery("select 1 from " + getDataProductSharingView() + + " where user_id = :user_id and data_product_id = :data_product_id and permission_id = :permission_id"); + query.setParameter("user_id", user.getUserId()); + query.setParameter("data_product_id", dataProductEntity.getDataProductId()); + query.setParameter("permission_id", permission.getNumber()); + + return query.getResultList().size() > 0; + } + + @Override + public String getDataProductSharingView() { + return "simple_data_product_sharing_view"; + } + + @Override + public void grantPermissionToUser(UserInfo userInfo, DataProduct dataProduct, Permission permission, + UserInfo sharedByUser) throws SharingException { + SimpleUserEntity simpleUser = resolveSimpleUser(userInfo); + DataProductEntity dataProductEntity = resolveDataProduct(dataProduct); + SimpleUserEntity sharedByUserEntity = sharedByUser != null ? resolveSimpleUser(sharedByUser) : null; + + Optional<SimpleUserSharingEntity> maybeSimpleUserSharingEntity = simpleUserSharingRepository + .findBySimpleUser_SimpleUserIdAndDataProduct_DataProductIdAndPermission(simpleUser.getSimpleUserId(), + dataProductEntity.getDataProductId(), permission); + + if (maybeSimpleUserSharingEntity.isEmpty()) { + SimpleUserSharingEntity simpleUserSharingEntity = new SimpleUserSharingEntity(); + simpleUserSharingEntity.setDataProduct(dataProductEntity); + simpleUserSharingEntity.setPermission(permission); + simpleUserSharingEntity.setSimpleUser(simpleUser); + simpleUserSharingEntity.setSharedByUser(sharedByUserEntity); + simpleUserSharingRepository.save(simpleUserSharingEntity); + } + } + + @Override + public void revokePermissionFromUser(UserInfo userInfo, DataProduct dataProduct, Permission permission) + throws SharingException { + + SimpleUserEntity simpleUser = resolveSimpleUser(userInfo); + DataProductEntity dataProductEntity = resolveDataProduct(dataProduct); + + Optional<SimpleUserSharingEntity> maybeSimpleUserSharingEntity = simpleUserSharingRepository + .findBySimpleUser_SimpleUserIdAndDataProduct_DataProductIdAndPermission(simpleUser.getSimpleUserId(), + dataProductEntity.getDataProductId(), permission); + maybeSimpleUserSharingEntity.ifPresent(simpleUserSharingEntity -> { + simpleUserSharingRepository.delete(simpleUserSharingEntity); + }); + } + + @Override + public void grantPermissionToGroup(GroupInfo groupInfo, DataProduct dataProduct, Permission permission, + UserInfo sharedByUser) throws SharingException { + + SimpleGroupEntity groupEntity = resolveGroup(groupInfo); + DataProductEntity dataProductEntity = resolveDataProduct(dataProduct); + SimpleUserEntity sharedByUserEntity = sharedByUser != null + ? resolveSimpleUser(sharedByUser, groupEntity.getSimpleTenant()) + : null; + + Optional<SimpleGroupSharingEntity> maybeSimpleGroupSharingEntity = simpleGroupSharingRepository + .findBySimpleGroup_SimpleGroupIdAndDataProduct_DataProductIdAndPermission( + groupEntity.getSimpleGroupId(), + dataProductEntity.getDataProductId(), permission); + + if (maybeSimpleGroupSharingEntity.isEmpty()) { + SimpleGroupSharingEntity simpleGroupSharingEntity = new SimpleGroupSharingEntity(); + simpleGroupSharingEntity.setDataProduct(dataProductEntity); + simpleGroupSharingEntity.setPermission(permission); + simpleGroupSharingEntity.setSimpleGroup(groupEntity); + simpleGroupSharingEntity.setSharedByUser(sharedByUserEntity); + simpleGroupSharingRepository.save(simpleGroupSharingEntity); + } + } + + @Override + public void revokePermissionFromGroup(GroupInfo groupInfo, DataProduct dataProduct, Permission permission) + throws SharingException { + SimpleGroupEntity groupEntity = resolveGroup(groupInfo); + DataProductEntity dataProductEntity = resolveDataProduct(dataProduct); + + Optional<SimpleGroupSharingEntity> maybeSimpleGroupSharingEntity = simpleGroupSharingRepository + .findBySimpleGroup_SimpleGroupIdAndDataProduct_DataProductIdAndPermission( + groupEntity.getSimpleGroupId(), dataProductEntity.getDataProductId(), permission); + maybeSimpleGroupSharingEntity.ifPresent(simpleUserSharingEntity -> { + simpleGroupSharingRepository.delete(simpleUserSharingEntity); + }); + } + + @Override + public boolean hasPublicAccess(DataProduct dataProduct, Permission permission) throws SharingException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'hasPublicAccess'"); + } + + @Override + public void grantPublicAccess(DataProduct dataProduct, Permission permission) throws SharingException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'grantPublicAccess'"); + } + + @Override + public void revokePublicAccess(DataProduct dataProduct, Permission permission) throws SharingException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'revokePublicAccess'"); + } + + private SimpleGroupEntity resolveGroup(GroupInfo groupInfo) { + + final String tenantId = groupInfo.hasTenantId() ? groupInfo.getTenantId() : "default"; + SimpleTenantEntity tenant = resolveTenant(tenantId); + + // Create the group if missing + Optional<SimpleGroupEntity> maybeSimpleGroup = simpleGroupRepository + .findByExternalIdAndSimpleTenant(groupInfo.getGroupId(), tenant); + SimpleGroupEntity simpleGroup = maybeSimpleGroup.orElseGet(() -> { + SimpleGroupEntity newGroup = new SimpleGroupEntity(); + newGroup.setExternalId(groupInfo.getGroupId()); + newGroup.setName(groupInfo.getGroupId()); + newGroup.setSimpleTenant(tenant); + return simpleGroupRepository.save(newGroup); + }); + + return simpleGroup; + } + + private SimpleTenantEntity resolveTenant(String tenantId) { + + Optional<SimpleTenantEntity> maybeSimpleTenant = simpleTenantRepository.findByExternalId(tenantId); + return maybeSimpleTenant.orElseGet(() -> { + TenantEntity newTenant = new TenantEntity(); + newTenant.setExternalId(tenantId); + newTenant.setName(tenantId); + newTenant = tenantRepository.save(newTenant); + + SimpleTenantEntity newSimpleTenant = new SimpleTenantEntity(); + newSimpleTenant.setExternalId(tenantId); + newSimpleTenant.setName(tenantId); + newSimpleTenant.setTenant(newTenant); + return simpleTenantRepository.save(newSimpleTenant); + }); + } + + private SimpleUserEntity resolveSimpleUser(UserInfo userInfo) { + + final String tenantId = userInfo.hasTenantId() ? userInfo.getTenantId() : "default"; + SimpleTenantEntity tenant = resolveTenant(tenantId); + + return resolveSimpleUser(userInfo, tenant); + } + + private SimpleUserEntity resolveSimpleUser(UserInfo userInfo, SimpleTenantEntity tenant) { + Optional<SimpleUserEntity> maybeSimpleUser = simpleUserRepository + .findByExternalIdAndSimpleTenant(userInfo.getUserId(), tenant); + + SimpleUserEntity simpleUser = maybeSimpleUser.orElseGet(() -> { + UserEntity newUser = new UserEntity(); + newUser.setExternalId(userInfo.getUserId()); + newUser.setName(userInfo.getUserId()); + newUser.setTenant(tenant.getTenant()); + newUser = userRepository.save(newUser); + + SimpleUserEntity newSimpleUser = new SimpleUserEntity(); + newSimpleUser.setExternalId(userInfo.getUserId()); + newSimpleUser.setName(userInfo.getUserId()); + newSimpleUser.setSimpleTenant(tenant); + newSimpleUser.setUser(newUser); + return simpleUserRepository.save(newSimpleUser); + }); + return simpleUser; + } + + private DataProductEntity resolveDataProduct(DataProduct dataProduct) throws SharingException { + Optional<DataProductEntity> maybeDataProduct = dataProductRepository + .findByExternalId(dataProduct.getDataProductId()); + DataProductEntity dataProductEntity = maybeDataProduct.orElseThrow(() -> { + return new SharingException("No data product exists with id " + dataProduct.getDataProductId()); + }); + return dataProductEntity; + } +} diff --git a/data-catalog-api/server/src/main/resources/application.properties b/data-catalog-api/server/src/main/resources/application.properties index 2064c00..914f6da 100644 --- a/data-catalog-api/server/src/main/resources/application.properties +++ b/data-catalog-api/server/src/main/resources/application.properties @@ -3,3 +3,8 @@ spring.datasource.username=postgres spring.datasource.password=example spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true + +# Run schema.sql after schema creation performed by Hibernate +# https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-initialization.using-basic-sql-scripts +spring.jpa.defer-datasource-initialization=true +spring.sql.init.mode=always diff --git a/data-catalog-api/server/src/main/resources/schema.sql b/data-catalog-api/server/src/main/resources/schema.sql new file mode 100644 index 0000000..e890d2e --- /dev/null +++ b/data-catalog-api/server/src/main/resources/schema.sql @@ -0,0 +1,36 @@ +-- TODO: move this to Liquibase or some other schema migration management tool +CREATE +OR REPLACE VIEW simple_data_product_sharing_view AS +SELECT + s.data_product_id AS data_product_id, + u.user_id AS user_id, + CASE + WHEN s.permission_id = 'OWNER' THEN 0 + WHEN s.permission_id = 'READ' THEN 1 + WHEN s.permission_id = 'READ_METADATA' THEN 2 + WHEN s.permission_id = 'WRITE' THEN 3 + WHEN s.permission_id = 'WRITE_METADATA' THEN 4 + WHEN s.permission_id = 'MANAGE_SHARING' THEN 5 + ELSE NULL + END AS permission_id +FROM + simple_user_sharing s + INNER JOIN simple_user su ON su.simple_user_id = s.simple_user_id + INNER JOIN user_table u ON u.user_id = su.user_id -- UNION + -- SELECT + -- dp.data_product_id AS data_product_id, + -- u.user_id AS user_id, + -- CASE + -- WHEN s.permission_id = 'OWNER' THEN 0 + -- WHEN s.permission_id = 'READ' THEN 1 + -- WHEN s.permission_id = 'READ_METADATA' THEN 2 + -- WHEN s.permission_id = 'WRITE' THEN 3 + -- WHEN s.permission_id = 'WRITE_METADATA' THEN 4 + -- WHEN s.permission_id = 'MANAGE_SHARING' THEN 5 + -- ELSE NULL + -- END AS permission_id + -- FROM + -- simple_group_sharing s + -- INNER JOIN simple_user su ON su.simple_user_id = s.simple_user_id + -- INNER JOIN user_table u ON u.user_id = su.user_id +; diff --git a/data-catalog-api/server/src/test/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImplTest.java b/data-catalog-api/server/src/test/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImplTest.java new file mode 100644 index 0000000..91f485b --- /dev/null +++ b/data-catalog-api/server/src/test/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImplTest.java @@ -0,0 +1,138 @@ +package org.apache.airavata.datacatalog.api.sharing; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Optional; +import java.util.UUID; + +import org.apache.airavata.datacatalog.api.DataProduct; +import org.apache.airavata.datacatalog.api.Permission; +import org.apache.airavata.datacatalog.api.UserInfo; +import org.apache.airavata.datacatalog.api.exception.SharingException; +import org.apache.airavata.datacatalog.api.model.DataProductEntity; +import org.apache.airavata.datacatalog.api.model.TenantEntity; +import org.apache.airavata.datacatalog.api.model.UserEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleTenantEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleUserEntity; +import org.apache.airavata.datacatalog.api.repository.DataProductRepository; +import org.apache.airavata.datacatalog.api.repository.TenantRepository; +import org.apache.airavata.datacatalog.api.repository.UserRepository; +import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleTenantRepository; +import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleUserRepository; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +@AutoConfigureTestDatabase(replace = Replace.NONE) +public class SimpleSharingManagerImplTest { + @Autowired + SimpleSharingManagerImpl simpleSharingManagerImpl; + + @Autowired + UserRepository userRepository; + @Autowired + TenantRepository tenantRepository; + @Autowired + SimpleUserRepository simpleUserRepository; + @Autowired + SimpleTenantRepository simpleTenantRepository; + @Autowired + DataProductRepository dataProductRepository; + + @Test + void testResolveUserCreatesUserAndTenantIfMissing() throws SharingException { + + Optional<UserEntity> maybeUserEntity = userRepository.findByExternalIdAndTenant_ExternalId("userId", + "tenantId"); + assertFalse(maybeUserEntity.isPresent()); + Optional<TenantEntity> maybeTenantEntity = tenantRepository.findByExternalId("tenantId"); + assertFalse(maybeTenantEntity.isPresent()); + + UserInfo userInfo = UserInfo.newBuilder().setUserId("userId").setTenantId("tenantId").build(); + UserEntity userEntity = this.simpleSharingManagerImpl.resolveUser(userInfo); + + assertEquals(userEntity.getExternalId(), "userId"); + assertEquals(userEntity.getName(), "userId"); + assertEquals(userEntity.getTenant().getExternalId(), "tenantId"); + + maybeUserEntity = userRepository.findByExternalIdAndTenant_ExternalId("userId", "tenantId"); + assertTrue(maybeUserEntity.isPresent()); + + maybeTenantEntity = tenantRepository.findByExternalId("tenantId"); + assertTrue(maybeTenantEntity.isPresent()); + } + + @Test + void testResolveUserFindsExistingUserAndTenant() throws SharingException { + + String userId = "userId"; + String tenantId = "tenantId"; + + TenantEntity tenantEntity = new TenantEntity(); + tenantEntity.setExternalId(tenantId); + tenantEntity.setName("tenant name"); + tenantRepository.save(tenantEntity); + SimpleTenantEntity simpleTenantEntity = new SimpleTenantEntity(); + simpleTenantEntity.setExternalId(tenantId); + simpleTenantEntity.setName(tenantId); + simpleTenantEntity.setTenant(tenantEntity); + simpleTenantRepository.save(simpleTenantEntity); + + UserEntity testUserEntity = new UserEntity(); + testUserEntity.setExternalId(userId); + testUserEntity.setName("user name"); + testUserEntity.setTenant(tenantEntity); + UserEntity savedUserEntity = userRepository.save(testUserEntity); + SimpleUserEntity simpleUserEntity = new SimpleUserEntity(); + simpleUserEntity.setExternalId(userId); + simpleUserEntity.setName(userId); + simpleUserEntity.setUser(testUserEntity); + simpleUserEntity.setSimpleTenant(simpleTenantEntity); + simpleUserRepository.save(simpleUserEntity); + + UserInfo userInfo = UserInfo.newBuilder().setUserId(userId).setTenantId(tenantId).build(); + UserEntity userEntity = this.simpleSharingManagerImpl.resolveUser(userInfo); + + assertEquals(userEntity.getExternalId(), userId); + assertEquals(userEntity.getName(), "user name"); + assertEquals(userEntity.getTenant().getExternalId(), tenantId); + // Double check same database record + assertEquals(userEntity.getUserId(), savedUserEntity.getUserId()); + } + + @Test + public void testUserHasAccess() throws SharingException { + + UserInfo userA = UserInfo.newBuilder().setTenantId("tenantId").setUserId("userA").build(); + UserEntity testUserA = simpleSharingManagerImpl.resolveUser(userA); + UserInfo userB = UserInfo.newBuilder().setTenantId("tenantId").setUserId("userB").build(); + // UserEntity testUserB = simpleSharingManagerImpl + // .resolveUser(userB); + + DataProductEntity dataProductEntity = new DataProductEntity(); + dataProductEntity.setExternalId(UUID.randomUUID().toString()); + dataProductEntity.setOwner(testUserA); + dataProductEntity.setName("test data product"); + dataProductRepository.save(dataProductEntity); + + // Check that userB doesn't have READ access to the data product + DataProduct dataProduct = DataProduct.newBuilder() + .setDataProductId(dataProductEntity.getExternalId()) // only need the data product id + .build(); + boolean hasAccess = simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ); + assertFalse(hasAccess); + + // Grant READ access to userB for the data product + simpleSharingManagerImpl.grantPermissionToUser(userB, dataProduct, Permission.READ, userA); + + // Check that userB does now have READ access to the data product + hasAccess = simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ); + assertTrue(hasAccess); + } + +}
