diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetProfileCriteria.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetProfileCriteria.java index cc556701d..8aa20acc2 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetProfileCriteria.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetProfileCriteria.java @@ -34,6 +34,7 @@ public class DatasetProfileCriteria extends Criteria { private UUID userId; private boolean finalized; private Integer status; + private Integer role; public boolean getAllVersions() { return allVersions; } public void setAllVersions(boolean allVersions) { this.allVersions = allVersions; } @@ -69,4 +70,12 @@ public class DatasetProfileCriteria extends Criteria { public void setStatus(Integer status) { this.status = status; } + + public Integer getRole() { + return role; + } + + public void setRole(Integer role) { + this.role = role; + } } diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDao.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDao.java index b8e480917..dad3243b4 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDao.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDao.java @@ -5,6 +5,7 @@ import eu.eudat.data.dao.criteria.DatasetProfileCriteria; import eu.eudat.data.entities.DatasetProfile; import eu.eudat.queryable.QueryableList; +import java.util.List; import java.util.UUID; public interface DatasetProfileDao extends DatabaseAccessLayer { @@ -13,4 +14,6 @@ public interface DatasetProfileDao extends DatabaseAccessLayer getAll(); + QueryableList getAuthenticated(QueryableList query, UUID principal, List roles); + } \ No newline at end of file diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java index 36fcc5433..c704f4fba 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java @@ -3,6 +3,7 @@ package eu.eudat.data.dao.entities; import eu.eudat.data.dao.DatabaseAccess; import eu.eudat.data.dao.criteria.DatasetProfileCriteria; import eu.eudat.data.dao.databaselayer.service.DatabaseService; +import eu.eudat.data.entities.DMP; import eu.eudat.data.entities.DatasetProfile; import eu.eudat.queryable.QueryableList; import eu.eudat.queryable.types.FieldSelectionType; @@ -11,8 +12,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; import java.util.Arrays; +import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -98,4 +101,18 @@ public class DatasetProfileDaoImpl extends DatabaseAccess implem public DatasetProfile find(UUID id, String hint) { throw new UnsupportedOperationException(); } + + @Override + public QueryableList getAuthenticated(QueryableList query, UUID principal, List roles) { + if (roles != null && !roles.isEmpty()) { + query.where((builder, root) -> { + Join userJoin = root.join("users", JoinType.LEFT); + return builder.and(builder.equal(userJoin.join("user", JoinType.LEFT).get("id"), principal), userJoin.get("role").in(roles)); + }); + } else { + query.where((builder, root) -> builder.equal(root.join("users", JoinType.LEFT).join("user", JoinType.LEFT).get("id"), principal)); + } + + return query; + } } diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/UserDatasetProfileDao.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/UserDatasetProfileDao.java new file mode 100644 index 000000000..dfe500ca4 --- /dev/null +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/UserDatasetProfileDao.java @@ -0,0 +1,13 @@ +package eu.eudat.data.dao.entities; + +import eu.eudat.data.dao.DatabaseAccessLayer; +import eu.eudat.data.entities.UserDMP; +import eu.eudat.data.entities.UserDatasetProfile; + +import java.util.UUID; + +/** + * Created by ikalyvas on 2/8/2018. + */ +public interface UserDatasetProfileDao extends DatabaseAccessLayer { +} diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/UserDatasetProfileDaoImpl.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/UserDatasetProfileDaoImpl.java new file mode 100644 index 000000000..73633d824 --- /dev/null +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/UserDatasetProfileDaoImpl.java @@ -0,0 +1,53 @@ +package eu.eudat.data.dao.entities; + +import eu.eudat.data.dao.DatabaseAccess; +import eu.eudat.data.dao.databaselayer.service.DatabaseService; +import eu.eudat.data.entities.UserDMP; +import eu.eudat.data.entities.UserDatasetProfile; +import eu.eudat.queryable.QueryableList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +@Component("userDatasetProfileDao") +public class UserDatasetProfileDaoImpl extends DatabaseAccess implements UserDatasetProfileDao { + + @Autowired + public UserDatasetProfileDaoImpl(DatabaseService databaseService) { + super(databaseService); + } + + @Override + public UserDatasetProfile createOrUpdate(UserDatasetProfile item) { + return this.getDatabaseService().createOrUpdate(item, UserDatasetProfile.class); + } + + @Override + public UserDatasetProfile find(UUID id) { + return this.getDatabaseService().getQueryable(UserDatasetProfile.class).where((builder, root) -> builder.equal(root.get("id"), id)).getSingleOrDefault(); + } + + @Override + public void delete(UserDatasetProfile item) { + this.getDatabaseService().delete(item); + } + + @Override + public QueryableList asQueryable() { + return this.getDatabaseService().getQueryable(UserDatasetProfile.class); + } + + @Async + @Override + public CompletableFuture createOrUpdateAsync(UserDatasetProfile item) { + return CompletableFuture.supplyAsync(() -> this.createOrUpdate(item)); + } + + @Override + public UserDatasetProfile find(UUID id, String hint) { + throw new UnsupportedOperationException(); + } +} diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/entities/DatasetProfile.java b/dmp-backend/data/src/main/java/eu/eudat/data/entities/DatasetProfile.java index 5000b461d..7b7aa11c4 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/entities/DatasetProfile.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/entities/DatasetProfile.java @@ -89,6 +89,9 @@ public class DatasetProfile implements DataEntity{ @Column(name = "\"Language\"", nullable = false) private String language; + @OneToMany(mappedBy = "datasetProfile", fetch = FetchType.LAZY) + private Set users; + public String getDescription() { return description; @@ -158,6 +161,14 @@ public class DatasetProfile implements DataEntity{ this.language = language; } + public Set getUsers() { + return users; + } + + public void setUsers(Set users) { + this.users = users; + } + @Override public String toString() { return "DatasetProfileListingModel [id=" + id + ", label=" + label + ", dataset=" + dataset + ", definition=" + definition + ", version=" + version + ", language=" + language + "]"; diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/entities/UserDatasetProfile.java b/dmp-backend/data/src/main/java/eu/eudat/data/entities/UserDatasetProfile.java new file mode 100644 index 000000000..8388cdbc3 --- /dev/null +++ b/dmp-backend/data/src/main/java/eu/eudat/data/entities/UserDatasetProfile.java @@ -0,0 +1,79 @@ +package eu.eudat.data.entities; + +import eu.eudat.data.entities.helpers.EntityBinder; +import eu.eudat.queryable.queryableentity.DataEntity; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.*; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "\"UserDatasetProfile\"") +public class UserDatasetProfile implements DataEntity { + @Id + @GeneratedValue + @GenericGenerator(name = "uuid2", strategy = "uuid2") + @Column(name = "id", updatable = false, nullable = false, columnDefinition = "BINARY(16)") + private UUID id; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "usr") + private UserInfo user; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "\"datasetProfile\"") + private DatasetProfile datasetProfile; + + @Column(name = "role") + private Integer role; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public UserInfo getUser() { + return user; + } + + public void setUser(UserInfo user) { + this.user = user; + } + + public DatasetProfile getDatasetProfile() { + return datasetProfile; + } + + public void setDatasetProfile(DatasetProfile datasetProfile) { + this.datasetProfile = datasetProfile; + } + + public Integer getRole() { + return role; + } + + public void setRole(Integer role) { + this.role = role; + } + + @Override + public void update(UserDatasetProfile entity) { + this.role = entity.getRole(); + } + + @Override + public UUID getKeys() { + return this.id; + } + + @Override + public UserDatasetProfile buildFromTuple(List tuple, List fields, String base) { + String currentBase = base.isEmpty() ? "" : base + "."; + if (fields.contains(currentBase + "id")) this.id = EntityBinder.fromTuple(tuple, currentBase + "id"); + return this; + } +} diff --git a/dmp-backend/data/src/main/java/eu/eudat/query/DatasetProfileQuery.java b/dmp-backend/data/src/main/java/eu/eudat/query/DatasetProfileQuery.java index 71a74b750..a4d477c0d 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/query/DatasetProfileQuery.java +++ b/dmp-backend/data/src/main/java/eu/eudat/query/DatasetProfileQuery.java @@ -4,4 +4,13 @@ import java.util.UUID; public class DatasetProfileQuery { + private UserQuery userQuery; + + public UserQuery getUserQuery() { + return userQuery; + } + + public void setUserQuery(UserQuery userQuery) { + this.userQuery = userQuery; + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java index b3ae23250..e7212e305 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java @@ -1,5 +1,8 @@ package eu.eudat.controllers; +import eu.eudat.data.dao.entities.UserDatasetProfileDao; +import eu.eudat.data.entities.UserDatasetProfile; +import eu.eudat.data.entities.UserInfo; import eu.eudat.data.query.items.table.datasetprofile.DatasetProfileTableRequestItem; import eu.eudat.exceptions.datasetprofile.DatasetProfileNewVersionException; import eu.eudat.exceptions.datasetprofile.DatasetProfileWithDatasetsExeption; @@ -13,6 +16,7 @@ import eu.eudat.models.data.admin.composite.DatasetProfile; import eu.eudat.models.data.datasetprofile.DatasetProfileListingModel; import eu.eudat.models.data.helpers.common.DataTableData; import eu.eudat.models.data.helpers.responses.ResponseItem; +import eu.eudat.models.data.listingmodels.UserInfoListingModel; import org.springframework.core.env.Environment; import eu.eudat.models.data.security.Principal; import eu.eudat.models.data.user.composite.PagedDatasetProfile; @@ -28,8 +32,10 @@ import javax.validation.Valid; import java.io.IOException; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import static eu.eudat.types.Authorities.ADMIN; +import static eu.eudat.types.Authorities.DATASET_PROFILE_MANAGER; @RestController @CrossOrigin @@ -50,19 +56,36 @@ public class Admin extends BaseController { @Transactional @RequestMapping(method = RequestMethod.POST, value = {"/addDmp"}, consumes = "application/json", produces = "application/json") - public ResponseEntity addDmp(@Valid @RequestBody DatasetProfile profile, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) { + public ResponseEntity addDmp(@Valid @RequestBody DatasetProfile profile, @ClaimedAuthorities(claims = {ADMIN ,DATASET_PROFILE_MANAGER}) Principal principal) { //this.getLoggerService().info(principal, "Admin Added Dataset Profile"); DatasetProfile shortenProfile = profile.toShort(); eu.eudat.data.entities.DatasetProfile modelDefinition = AdminManager.generateViewStyleDefinition(shortenProfile, getApiContext()); modelDefinition.setGroupId(UUID.randomUUID()); modelDefinition.setVersion((short) 0); - this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao().createOrUpdate(modelDefinition); + + eu.eudat.data.entities.DatasetProfile datasetProfile = this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao().createOrUpdate(modelDefinition); + UserDatasetProfile userDatasetProfile = new UserDatasetProfile(); + userDatasetProfile.setDatasetProfile(datasetProfile); + UserInfo userInfo = getApiContext().getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); + userDatasetProfile.setUser(userInfo); + userDatasetProfile.setRole(0); + getApiContext().getOperationsContext().getDatabaseRepository().getUserDatasetProfileDao().createOrUpdate(userDatasetProfile); + if (profile.getUsers() != null && !profile.getUsers().isEmpty()) { + profile.getUsers().forEach(userInfoListingModel -> { + UserDatasetProfile userDatasetProfile1 = new UserDatasetProfile(); + userDatasetProfile1.setDatasetProfile(datasetProfile); + UserInfo userInfo1 = getApiContext().getOperationsContext().getDatabaseRepository().getUserInfoDao().find(userInfoListingModel.getId()); + userDatasetProfile1.setUser(userInfo1); + userDatasetProfile1.setRole(1); + getApiContext().getOperationsContext().getDatabaseRepository().getUserDatasetProfileDao().createOrUpdate(userDatasetProfile1); + }); + } return ResponseEntity.status(HttpStatus.OK).body(modelDefinition.getId()); } @Transactional @RequestMapping(method = RequestMethod.POST, value = {"/addDmp/{id}"}, consumes = "application/json", produces = "application/json") - public ResponseEntity> updateDmp(@PathVariable String id, @RequestBody DatasetProfile profile, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) { + public ResponseEntity> updateDmp(@PathVariable String id, @RequestBody DatasetProfile profile, @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) { DatasetProfile shortenProfile = profile.toShort(); eu.eudat.data.entities.DatasetProfile modelDefinition = AdminManager.generateViewStyleDefinition(shortenProfile, getApiContext()); eu.eudat.data.entities.DatasetProfile datasetprofile = this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao().find(UUID.fromString(id)); @@ -71,13 +94,23 @@ public class Admin extends BaseController { datasetprofile.setLabel(modelDefinition.getLabel()); datasetprofile.setDescription(modelDefinition.getDescription()); datasetprofile.setLanguage(modelDefinition.getLanguage()); - this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao().createOrUpdate(datasetprofile); + eu.eudat.data.entities.DatasetProfile datasetProfile = this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao().createOrUpdate(datasetprofile); + if (profile.getUsers() != null && !profile.getUsers().isEmpty()) { + profile.getUsers().forEach(userInfoListingModel -> { + UserDatasetProfile userDatasetProfile1 = new UserDatasetProfile(); + userDatasetProfile1.setDatasetProfile(datasetProfile); + UserInfo userInfo1 = getApiContext().getOperationsContext().getDatabaseRepository().getUserInfoDao().find(userInfoListingModel.getId()); + userDatasetProfile1.setUser(userInfo1); + userDatasetProfile1.setRole(1); + getApiContext().getOperationsContext().getDatabaseRepository().getUserDatasetProfileDao().createOrUpdate(userDatasetProfile1); + }); + } return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); } @Transactional @RequestMapping(method = RequestMethod.POST, value = {"/newVersion/{id}"}, produces = "application/json") - public ResponseEntity newVersionDatasetProfile(@PathVariable String id, @RequestBody DatasetProfile profile, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws Exception { + public ResponseEntity newVersionDatasetProfile(@PathVariable String id, @RequestBody DatasetProfile profile, @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) throws Exception { try { eu.eudat.data.entities.DatasetProfile modelDefinition = this.datasetProfileManager.createNewVersionDatasetProfile(id, profile); return ResponseEntity.status(HttpStatus.OK).body(modelDefinition.getId()); @@ -87,20 +120,20 @@ public class Admin extends BaseController { } @RequestMapping(method = RequestMethod.GET, value = {"/get/{id}"}, produces = "application/json") - public ResponseEntity> get(@PathVariable String id, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) { + public ResponseEntity> get(@PathVariable String id, @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) { eu.eudat.models.data.admin.composite.DatasetProfile datasetprofile = this.datasetProfileManager.getDatasetProfile(id); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(datasetprofile)); } @RequestMapping(method = RequestMethod.POST, value = {"/datasetprofiles/getPaged"}, produces = "application/json") public @ResponseBody - ResponseEntity>> getPaged(@RequestBody DatasetProfileTableRequestItem datasetProfileTableRequestItem, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws Exception { - DataTableData datasetProfileTableData = this.datasetProfileManager.getPaged(datasetProfileTableRequestItem); + ResponseEntity>> getPaged(@RequestBody DatasetProfileTableRequestItem datasetProfileTableRequestItem, @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) throws Exception { + DataTableData datasetProfileTableData = this.datasetProfileManager.getPaged(datasetProfileTableRequestItem, principal); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().status(ApiMessageCode.NO_MESSAGE).payload(datasetProfileTableData)); } @RequestMapping(method = RequestMethod.POST, value = {"/preview"}, consumes = "application/json", produces = "application/json") - public ResponseEntity> getPreview(@RequestBody DatasetProfile profile, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) { + public ResponseEntity> getPreview(@RequestBody DatasetProfile profile, @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) { eu.eudat.data.entities.DatasetProfile modelDefinition = AdminManager.generateViewStyleDefinition(profile, getApiContext()); eu.eudat.models.data.user.composite.DatasetProfile datasetProfile = userManager.generateDatasetProfileModel(modelDefinition); PagedDatasetProfile pagedDatasetProfile = new PagedDatasetProfile(); @@ -110,18 +143,28 @@ public class Admin extends BaseController { @Transactional @RequestMapping(method = RequestMethod.POST, value = {"/datasetprofile/clone/{id}"}, consumes = "application/json", produces = "application/json") - public ResponseEntity> clone(@PathVariable String id, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) { + public ResponseEntity> clone(@PathVariable String id, @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) { eu.eudat.data.entities.DatasetProfile profile = this.datasetProfileManager.clone(id); eu.eudat.models.data.admin.composite.DatasetProfile datasetprofile = AdminManager.generateDatasetProfileModel(profile); datasetprofile.setLabel(profile.getLabel() + " new "); datasetprofile.setLanguage(profile.getLanguage()); + if (profile.getUsers() != null && !profile.getUsers().isEmpty()) { + datasetprofile.setUsers(profile.getUsers().stream().map(userDatasetProfile -> { + UserInfoListingModel userInfoListingModel = new UserInfoListingModel(); + userInfoListingModel.setId(userDatasetProfile.getUser().getId()); + userInfoListingModel.setName(userDatasetProfile.getUser().getName()); + userInfoListingModel.setEmail(userDatasetProfile.getUser().getEmail()); + userInfoListingModel.setRole(userDatasetProfile.getRole()); + return userInfoListingModel; + }).collect(Collectors.toList())); + } return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(datasetprofile)); } @Transactional @RequestMapping(method = RequestMethod.DELETE, value = {"{id}"}, consumes = "application/json", produces = "application/json") public @ResponseBody - ResponseEntity> inactivate(@PathVariable String id, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) { + ResponseEntity> inactivate(@PathVariable String id, @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) { try { eu.eudat.data.entities.DatasetProfile ret = AdminManager.inactivate(this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao(), this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetDao(), id); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); @@ -132,11 +175,13 @@ public class Admin extends BaseController { @Transactional @RequestMapping(method = RequestMethod.GET, value = {"/getXml/{id}"}, produces = "application/json") - public ResponseEntity getDatasetProfileXml(@PathVariable String id, @RequestHeader("Content-Type") String contentType, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws IllegalAccessException, IOException, InstantiationException { + public ResponseEntity getDatasetProfileXml(@PathVariable String id, @RequestHeader("Content-Type") String contentType, @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) throws IllegalAccessException, IOException, InstantiationException { if (contentType.equals("application/xml")) { eu.eudat.data.entities.DatasetProfile profile = this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao().find(UUID.fromString(id)); eu.eudat.models.data.user.composite.DatasetProfile datasetProfile = userManager.generateDatasetProfileModel(profile); datasetProfile.setStatus(profile.getStatus()); + datasetProfile.setDescription(profile.getDescription()); + datasetProfile.setLanguage(profile.getLanguage()); return this.datasetProfileManager.getDocument(datasetProfile, profile.getLabel()); } else { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE).message("NOT AUTHORIZE")); @@ -145,17 +190,23 @@ public class Admin extends BaseController { @RequestMapping(method = RequestMethod.POST, value = {"/upload"}) public ResponseEntity setDatasetProfileXml(@RequestParam("file") MultipartFile file, - @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws IllegalAccessException, IOException { + @ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) throws IllegalAccessException, IOException { eu.eudat.logic.utilities.documents.xml.datasetProfileXml.datasetProfileModel.DatasetProfile datasetProfileModel = this.datasetProfileManager.createDatasetProfileFromXml(file); eu.eudat.models.data.admin.composite.DatasetProfile datasetProfileEntity = datasetProfileModel.toAdminCompositeModel(file.getOriginalFilename()); eu.eudat.data.entities.DatasetProfile modelDefinition = AdminManager.generateViewStyleDefinition(datasetProfileEntity, getApiContext()); - this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao().createOrUpdate(modelDefinition); + eu.eudat.data.entities.DatasetProfile datasetProfile = this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetProfileDao().createOrUpdate(modelDefinition); + UserDatasetProfile userDatasetProfile = new UserDatasetProfile(); + userDatasetProfile.setDatasetProfile(datasetProfile); + UserInfo userInfo = getApiContext().getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); + userDatasetProfile.setUser(userInfo); + userDatasetProfile.setRole(0); + getApiContext().getOperationsContext().getDatabaseRepository().getUserDatasetProfileDao().createOrUpdate(userDatasetProfile); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>() .status(ApiMessageCode.SUCCESS_MESSAGE).message("")); } @RequestMapping(method = RequestMethod.GET, value = {"/getRDACommonStandards"}, produces = "application/json") - public ResponseEntity getRDACommonStandards(@ClaimedAuthorities(claims = {ADMIN}) Principal principal) { + public ResponseEntity getRDACommonStandards(@ClaimedAuthorities(claims = {ADMIN, DATASET_PROFILE_MANAGER}) Principal principal) { return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().status(ApiMessageCode.SUCCESS_MESSAGE).payload(configLoader.getRdaProperties())); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java index 362acb233..a1e8fc5a2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java @@ -20,7 +20,10 @@ import eu.eudat.models.data.datasetprofile.DatasetProfileListingModel; import eu.eudat.models.data.entities.xmlmodels.datasetprofiledefinition.Field; import eu.eudat.models.data.externaldataset.ExternalAutocompleteFieldModel; import eu.eudat.models.data.helpers.common.DataTableData; +import eu.eudat.models.data.listingmodels.UserInfoListingModel; +import eu.eudat.models.data.security.Principal; import eu.eudat.queryable.QueryableList; +import eu.eudat.types.Authorities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -68,7 +71,17 @@ public class DatasetProfileManager { datasetprofile.setStatus(profile.getStatus()); datasetprofile.setDescription(profile.getDescription()); datasetprofile.setLanguage(profile.getLanguage()); - + datasetprofile.setUsers(new ArrayList<>()); + if (profile.getUsers() != null && !profile.getUsers().isEmpty()) { + datasetprofile.getUsers().addAll(profile.getUsers().stream().map(userDatasetProfile -> { + UserInfoListingModel userInfoListingModel = new UserInfoListingModel(); + userInfoListingModel.setId(userDatasetProfile.getUser().getId()); + userInfoListingModel.setName(userDatasetProfile.getUser().getName()); + userInfoListingModel.setEmail(userInfoListingModel.getEmail()); + userInfoListingModel.setRole(userInfoListingModel.getRole()); + return userInfoListingModel; + }).collect(Collectors.toList())); + } return datasetprofile; } @@ -86,9 +99,15 @@ public class DatasetProfileManager { return profile; } - public DataTableData getPaged(DatasetProfileTableRequestItem datasetProfileTableRequestItem) throws Exception { + public DataTableData getPaged(DatasetProfileTableRequestItem datasetProfileTableRequestItem, Principal principal) throws Exception { QueryableList items = apiContext.getOperationsContext().getDatabaseRepository().getDatasetProfileDao().getWithCriteria(datasetProfileTableRequestItem.getCriteria()); - QueryableList pagedItems = PaginationManager.applyPaging(items, datasetProfileTableRequestItem); + QueryableList authItems = null; + if (principal.getAuthz().contains(Authorities.ADMIN)) { + authItems = items; + } else if (principal.getAuthz().contains(Authorities.DATASET_PROFILE_MANAGER)) { + authItems = apiContext.getOperationsContext().getDatabaseRepository().getDatasetProfileDao().getAuthenticated(items, principal.getId(), null); + } + QueryableList pagedItems = PaginationManager.applyPaging(authItems, datasetProfileTableRequestItem); List datasetProfiles = pagedItems.select(item -> new DatasetProfileListingModel().fromDataModel(item)); return apiContext.getOperationsContext().getBuilderFactory().getBuilder(DataTableDataBuilder.class).data(datasetProfiles).totalCount(items.count()).build(); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepository.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepository.java index d77af5779..3866291ad 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepository.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepository.java @@ -36,6 +36,8 @@ public interface DatabaseRepository { ExternalDatasetDao getExternalDatasetDao(); + UserDatasetProfileDao getUserDatasetProfileDao(); + UserDmpDao getUserDmpDao(); ContentDao getContentDao(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepositoryImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepositoryImpl.java index cad146eaf..addeabe7c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepositoryImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepositoryImpl.java @@ -27,6 +27,7 @@ public class DatabaseRepositoryImpl implements DatabaseRepository { private UserTokenDao userTokenDao; private ExternalDatasetDao externalDatasetDao; private UserRoleDao userRoleDao; + private UserDatasetProfileDao userDatasetProfileDao; private UserDmpDao userDmpDao; private ContentDao contentDao; private DMPProfileDao dmpProfileDao; @@ -306,6 +307,16 @@ public class DatabaseRepositoryImpl implements DatabaseRepository { this.notificationDao = notificationDao; } + @Override + public UserDatasetProfileDao getUserDatasetProfileDao() { + return userDatasetProfileDao; + } + + @Autowired + public void setUserDatasetProfileDao(UserDatasetProfileDao userDatasetProfileDao) { + this.userDatasetProfileDao = userDatasetProfileDao; + } + public void detachEntity(T entity) { this.entityManager.detach(entity); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/admin/composite/DatasetProfile.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/admin/composite/DatasetProfile.java index 4f8ada7e4..cbc23c2f4 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/admin/composite/DatasetProfile.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/admin/composite/DatasetProfile.java @@ -3,7 +3,9 @@ package eu.eudat.models.data.admin.composite; import eu.eudat.models.data.admin.components.datasetprofile.Page; import eu.eudat.models.data.admin.components.datasetprofile.Section; import eu.eudat.logic.utilities.builders.ModelBuilder; +import eu.eudat.models.data.listingmodels.UserInfoListingModel; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -16,6 +18,7 @@ public class DatasetProfile { private Short status; private Short version; private String language; + private List users; public String getLabel() { @@ -61,6 +64,13 @@ public class DatasetProfile { this.language = language; } + public List getUsers() { + return users; + } + public void setUsers(List users) { + this.users = users; + } + public void buildProfile(eu.eudat.models.data.entities.xmlmodels.datasetprofiledefinition.ViewStyleModel viewStyle) { this.sections = new ModelBuilder().fromViewStyleDefinition(viewStyle.getSections(), Section.class); this.pages = new ModelBuilder().fromViewStyleDefinition(viewStyle.getPages(), Page.class); @@ -80,6 +90,7 @@ public class DatasetProfile { shortProfile.setStatus(this.status); shortProfile.setVersion(this.version); shortProfile.setLanguage(this.language); + shortProfile.setUsers(new ArrayList<>()); return shortProfile; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/types/Authorities.java b/dmp-backend/web/src/main/java/eu/eudat/types/Authorities.java index 129db641a..55515354f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/types/Authorities.java +++ b/dmp-backend/web/src/main/java/eu/eudat/types/Authorities.java @@ -5,7 +5,7 @@ import java.util.List; public enum Authorities { - USER(0), MANAGER(1), ADMIN(2), ANONYMOUS(99); + USER(0), MANAGER(1), ADMIN(2), DATASET_PROFILE_MANAGER(3), ANONYMOUS(99); private Integer value; @@ -25,6 +25,8 @@ public enum Authorities { return MANAGER; case 2: return ADMIN; + case 3: + return DATASET_PROFILE_MANAGER; case 99: return ANONYMOUS; default: @@ -33,6 +35,6 @@ public enum Authorities { } public static List all() { - return Arrays.asList(USER, ADMIN, MANAGER); + return Arrays.asList(USER, ADMIN, MANAGER, DATASET_PROFILE_MANAGER); } } diff --git a/dmp-db-scema/main/dmp-dump.sql b/dmp-db-scema/main/dmp-dump.sql index 7c0ef0309..a9134c56a 100644 --- a/dmp-db-scema/main/dmp-dump.sql +++ b/dmp-db-scema/main/dmp-dump.sql @@ -802,6 +802,19 @@ CREATE TABLE public."Service" ( ALTER TABLE public."Service" OWNER TO :POSTGRES_USER; +-- +-- Name: UserDatasetProfile; Type: TABLE; Schema: public; Owner: :POSTGRES_USER +-- + +CREATE TABLE public."UserDatasetProfile" ( + id uuid NOT NULL, + "usr" uuid NOT NULL, + "datasetProfile" uuid NOT NULL, + role integer +); + +ALTER TABLE public."UserDatasetProfile" OWNER TO :POSTGRES_USER; + -- -- Name: UserDMP; Type: TABLE; Schema: public; Owner: :POSTGRES_USER -- @@ -1122,6 +1135,12 @@ ALTER TABLE ONLY public."Project" ALTER TABLE ONLY public."Researcher" ADD CONSTRAINT "Researcher_pkey" PRIMARY KEY ("ID"); +-- +-- Name: UserDatasetProfile UserDatasetProfile_pkey; Type: CONSTRAINT; Schema: public; Owner: :POSTGRES_USER +-- + +ALTER TABLE ONLY public."UserDatasetProfile" + ADD CONSTRAINT "UserDatasetProfile_pkey" PRIMARY KEY (id); -- -- Name: UserDMP UserDMP_pkey; Type: CONSTRAINT; Schema: public; Owner: :POSTGRES_USER @@ -1328,6 +1347,20 @@ ALTER TABLE ONLY public."Lock" ALTER TABLE ONLY public."Notification" ADD CONSTRAINT "NotificationUserReference" FOREIGN KEY ("UserId") REFERENCES public."UserInfo"(id); +-- +-- Name: UserDatasetProfile UserDatasetProfile_datasetProfile_key; Type: FK CONSTRAINT; Schema: public; Owner: :POSTGRES_USER +-- + +ALTER TABLE ONLY public."UserDatasetProfile" + ADD CONSTRAINT "UserDatasetProfile_datasetProfile_fkey" FOREIGN KEY (datasetProfile) REFERENCES public."DatasetProfile" ("ID"); + +-- +-- Name: UserDatasetProfile UserDatasetProfile_user_key; Type: FK CONSTRAINT; Schema: public; Owner: :POSTGRES_USER +-- + + +ALTER TABLE ONLY public."UserDatasetProfile" + ADD CONSTRAINT "UserDatasetProfile_usr_fkey" FOREIGN KEY (usr) REFERENCES public."UserInfo" (id); -- -- Name: UserDMP UserDMP_dmp_fkey; Type: FK CONSTRAINT; Schema: public; Owner: :POSTGRES_USER diff --git a/dmp-db-scema/updates/00.00.008_Add_UserDatasetProfile_table.sql b/dmp-db-scema/updates/00.00.008_Add_UserDatasetProfile_table.sql new file mode 100644 index 000000000..70c421eb2 --- /dev/null +++ b/dmp-db-scema/updates/00.00.008_Add_UserDatasetProfile_table.sql @@ -0,0 +1,20 @@ +CREATE TABLE public."UserDatasetProfile" +( + id uuid NOT NULL, + "usr" uuid NOT NULL, + "datasetProfile" uuid NOT NULL, + role integer, + CONSTRAINT "UserDatasetProfile_pkey" PRIMARY KEY (id), + CONSTRAINT "UserDatasetProfile_datasetProfile_fkey" FOREIGN KEY (datasetProfile) + REFERENCES public."DatasetProfile" ("ID") MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION + NOT VALID, + CONSTRAINT "UserDatasetProfile_usr_fkey" FOREIGN KEY (usr) + REFERENCES public."UserInfo" (id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION + NOT VALID +) + +INSERT INTO public."DBVersion" VALUES ('DMPDB', '00.00.008', '2021-04-05 17:48:00.000000+03', now(), 'Add Dataset Profile User Table'); \ No newline at end of file diff --git a/dmp-frontend/src/app/core/common/enum/app-role.ts b/dmp-frontend/src/app/core/common/enum/app-role.ts index 944067e78..4cd4c9c08 100644 --- a/dmp-frontend/src/app/core/common/enum/app-role.ts +++ b/dmp-frontend/src/app/core/common/enum/app-role.ts @@ -2,4 +2,5 @@ export enum AppRole { Admin = 2, Manager = 1, User = 0, -} \ No newline at end of file + DatasetTemplateEditor = 3 +} diff --git a/dmp-frontend/src/app/core/core-service.module.ts b/dmp-frontend/src/app/core/core-service.module.ts index 854728f85..0f8656770 100644 --- a/dmp-frontend/src/app/core/core-service.module.ts +++ b/dmp-frontend/src/app/core/core-service.module.ts @@ -44,6 +44,7 @@ import { UserGuideService } from './services/user-guide/user-guide.service'; import { UserService } from './services/user/user.service'; import { CollectionUtils } from './services/utilities/collection-utils.service'; import { TypeUtils } from './services/utilities/type-utils.service'; +import { SpecialAuthGuard } from './special-auth-guard.service'; // // // This is shared module that provides all the services. Its imported only once on the AppModule. @@ -71,6 +72,7 @@ export class CoreServiceModule { CookieService, BaseHttpService, AdminAuthGuard, + SpecialAuthGuard, AuthGuard, CultureService, TimezoneService, diff --git a/dmp-frontend/src/app/core/special-auth-guard.service.ts b/dmp-frontend/src/app/core/special-auth-guard.service.ts new file mode 100644 index 000000000..6c311f418 --- /dev/null +++ b/dmp-frontend/src/app/core/special-auth-guard.service.ts @@ -0,0 +1,61 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, CanLoad, Route, Router, RouterStateSnapshot } from '@angular/router'; +import { AuthService } from './services/auth/auth.service'; +import { AppRole } from './common/enum/app-role'; + +@Injectable() +export class SpecialAuthGuard implements CanActivate, CanLoad { + constructor(private auth: AuthService, private router: Router) { + } + + hasPermission(permission: AppRole): boolean { + if (!this.auth.current()) { return false; } + const principalRoles = this.auth.current().authorities; + for (let i = 0; i < principalRoles.length; i++) { + if (principalRoles[i] === permission) { + return true; + } + } + return false; + } + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + const url: string = state.url; + const permissions = route.data['authContext']['permissions']; + let count = permissions.length; + if (count < 0 || count === undefined) { + return false; + } + for (let i = 0; i < permissions.length; i++) { + if (!this.hasPermission(permissions[i])) { + count--; + } + } + if (count === 0) { + this.router.navigate(['/unauthorized'], { queryParams: { returnUrl: url } }); + return false; + } else { + return true; + } + } + + canLoad(route: Route): boolean { + const url = `/${route.path}`; + const permissions = route.data['authContext']['permissions']; + let count = permissions.length; + if (count < 0 || count === undefined) { + return false; + } + for (let i = 0; i < permissions.length; i++) { + if (!this.hasPermission(permissions[i])) { + count--; + } + } + if (count === 0) { + this.router.navigate(['/unauthorized'], { queryParams: { returnUrl: url } }); + return false; + } else { + return true; + } + } +} diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts index 880788a59..c417425b2 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts @@ -21,6 +21,7 @@ declare interface GroupMenuItem { title: string; routes: RouteInfo[]; requiresAuthentication: boolean; + requiresSpecialPermission?: AppRole; requiresAdmin: boolean; isGeneral: boolean; } @@ -57,6 +58,10 @@ export const ADMIN_ROUTES: RouteInfo[] = [ { path: '/user-guide-editor', title: 'SIDE-BAR.GUIDE-EDITOR', icon: 'import_contacts' } ]; +export const DATASET_TEMPLATE_ROUTES: RouteInfo[] = [ + { path: '/dataset-profiles', title: 'SIDE-BAR.DATASET-TEMPLATES', icon: 'library_books' } +]; + export const INFO_ROUTES: RouteInfo[] = [ { path: '/co-branding', title: 'SIDE-BAR.CO-BRANDING', icon: 'toll' }, { path: '/contact-support', title: 'SIDE-BAR.SUPPORT', icon: 'help' }, @@ -77,6 +82,7 @@ export class SidebarComponent implements OnInit { generalItems: GroupMenuItem; dmpItems: GroupMenuItem; adminItems: GroupMenuItem; + datasetTemplateItems: GroupMenuItem; // historyItems: GroupMenuItem; datasetItems: GroupMenuItem; grantItems: GroupMenuItem; @@ -146,6 +152,16 @@ export class SidebarComponent implements OnInit { } this.groupMenuItems.push(this.adminItems); + this.datasetTemplateItems = { + title: 'SIDE-BAR.ADMIN', + routes: DATASET_TEMPLATE_ROUTES, + requiresAuthentication: true, + requiresSpecialPermission: AppRole.DatasetTemplateEditor, + requiresAdmin: false, + isGeneral: false + } + this.groupMenuItems.push(this.datasetTemplateItems); + this.publicItems = { title: 'SIDE-BAR.PUBLIC', routes: PUBLIC_ROUTES, @@ -208,6 +224,20 @@ export class SidebarComponent implements OnInit { } } + public hasPermission(permission: AppRole): boolean { + const principal: Principal = this.authentication.current(); + if (principal) { + if (principal.authorities.find(role => role === permission)) { + return true; + } + else { + return false; + } + } else { + return false; + } + } + isLoginRouteActivated(): boolean { return this.location.path().indexOf('/login') > -1; } @@ -221,6 +251,9 @@ export class SidebarComponent implements OnInit { if (value.requiresAdmin) { return this.isAdmin(); } + else if (value.requiresSpecialPermission !== undefined) { + return this.hasPermission(value.requiresSpecialPermission); + } else { return value.isGeneral || value.requiresAuthentication; }