From b0b464890c4da02210387496c4af163cd1dc49c8 Mon Sep 17 00:00:00 2001 From: Daniil Palagin Date: Tue, 3 Sep 2024 19:36:08 +0200 Subject: [PATCH 1/4] [kbss-cvut/record-manager-ui#202] Implement roles --- .../study/security/SecurityConstants.java | 15 +++++- .../cvut/kbss/study/security/model/Role.java | 13 ++++- src/main/resources/model.ttl | 51 +++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/study/security/SecurityConstants.java b/src/main/java/cz/cvut/kbss/study/security/SecurityConstants.java index a60c8ba3..7c1456dc 100644 --- a/src/main/java/cz/cvut/kbss/study/security/SecurityConstants.java +++ b/src/main/java/cz/cvut/kbss/study/security/SecurityConstants.java @@ -28,6 +28,19 @@ private SecurityConstants() { public static final int SESSION_TIMEOUT = 12 * 60 * 60; public static final String ROLE_USER = "ROLE_USER"; - public static final String ROLE_ADMIN = "ROLE_ADMIN"; + + public static final String ROLE_COMPLETE_RECORDS = "rm_complete_records"; + public static final String ROLE_DELETE_ALL_RECORDS = "rm_delete_all_records"; + public static final String ROLE_DELETE_ORGANIZATION_RECORDS = "rm_delete_organization_records"; + public static final String ROLE_EDIT_ALL_RECORDS = "rm_edit_all_records"; + public static final String ROLE_EDIT_ORGANIZATION_RECORDS = "rm_edit_organization_records"; + public static final String ROLE_EDIT_USERS = "rm_edit_users"; + public static final String ROLE_IMPORT_CODELISTS = "rm_import_codelists"; + public static final String ROLE_PUBLISH_RECORDS = "rm_publish_records"; + public static final String ROLE_REJECT_RECORDS = "rm_reject_records"; + public static final String ROLE_VIEW_ALL_RECORDS = "rm_view_all_records"; + public static final String ROLE_VIEW_ORGANIZATION_RECORDS = "rm_view_organization_records"; + + } diff --git a/src/main/java/cz/cvut/kbss/study/security/model/Role.java b/src/main/java/cz/cvut/kbss/study/security/model/Role.java index 4b794953..36c4b970 100644 --- a/src/main/java/cz/cvut/kbss/study/security/model/Role.java +++ b/src/main/java/cz/cvut/kbss/study/security/model/Role.java @@ -8,7 +8,18 @@ public enum Role { USER(SecurityConstants.ROLE_USER, Vocabulary.s_c_doctor), - ADMIN(SecurityConstants.ROLE_ADMIN, Vocabulary.s_c_administrator); + ADMIN(SecurityConstants.ROLE_ADMIN, Vocabulary.s_c_administrator), + COMPLETE_RECORDS(SecurityConstants.ROLE_COMPLETE_RECORDS, Vocabulary.s_c_complete_records), + DELETE_ALL_RECORDS(SecurityConstants.ROLE_DELETE_ALL_RECORDS, Vocabulary.s_c_delete_all_records), + DELETE_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_DELETE_ORGANIZATION_RECORDS, Vocabulary.s_c_delete_organization_records), + EDIT_ALL_RECORDS(SecurityConstants.ROLE_EDIT_ALL_RECORDS, Vocabulary.s_c_edit_all_records), + EDIT_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_EDIT_ORGANIZATION_RECORDS, Vocabulary.s_c_edit_organization_records), + EDIT_USERS(SecurityConstants.ROLE_EDIT_USERS, Vocabulary.s_c_edit_users), + IMPORT_CODELISTS(SecurityConstants.ROLE_IMPORT_CODELISTS, Vocabulary.s_c_import_codelists), + PUBLISH_RECORDS(SecurityConstants.ROLE_PUBLISH_RECORDS, Vocabulary.s_c_publish_records), + REJECT_RECORDS(SecurityConstants.ROLE_REJECT_RECORDS, Vocabulary.s_c_reject_records), + VIEW_ALL_RECORDS(SecurityConstants.ROLE_VIEW_ALL_RECORDS, Vocabulary.s_c_view_all_records), + VIEW_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_VIEW_ORGANIZATION_RECORDS, Vocabulary.s_c_view_organization_records); private final String name; private final String type; diff --git a/src/main/resources/model.ttl b/src/main/resources/model.ttl index 863b9d68..87a04aaa 100644 --- a/src/main/resources/model.ttl +++ b/src/main/resources/model.ttl @@ -200,3 +200,54 @@ rm:rejected-record-phase rdf:type owl:Class ; rdfs:label "rejected record phase"@en . ### Generated by the OWL API (version 4.2.8.20170104-2310) https://github.com/owlcs/owlapi + +################################################################# +# New Roles +################################################################# + + +### http://onto.fel.cvut.cz/ontologies/record-manager/complete-records +rm:complete-records rdf:type owl:Class ; + rdfs:label "Complete Records"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/delete-all-records +rm:delete-all-records rdf:type owl:Class ; + rdfs:label "Delete All Records"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/edit-all-records +rm:edit-all-records rdf:type owl:Class ; + rdfs:label "Edit All Records"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/view-all-records +rm:view-all-records rdf:type owl:Class ; + rdfs:label "View All Records"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/delete-organization-records +rm:delete-organization-records rdf:type owl:Class ; + rdfs:label "Delete Organization Records"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/edit-organization-records +rm:edit-organization-records rdf:type owl:Class ; + rdfs:label "Edit Organization Records"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/view-organization-records +rm:view-organization-records rdf:type owl:Class ; + rdfs:label "View Organization Records"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/edit-users +rm:edit-users rdf:type owl:Class ; + rdfs:label "Edit Users"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/import-codelists +rm:import-codelists rdf:type owl:Class ; + rdfs:label "Import Codelists"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/publish-records +rm:publish-records rdf:type owl:Class ; + rdfs:label "Publish Records"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/reject-records +rm:reject-records rdf:type owl:Class ; + rdfs:label "Reject Records"@en . + + From 0a8cfee64ca2f973e48081718ff7a58d4124753e Mon Sep 17 00:00:00 2001 From: Daniil Palagin Date: Fri, 6 Sep 2024 16:31:05 +0200 Subject: [PATCH 2/4] [kbss-cvut/record-manager-ui#202] Implement Role group assignment --- .../java/cz/cvut/kbss/study/model/User.java | 16 +++- .../kbss/study/service/SystemInitializer.java | 2 + .../cz/cvut/kbss/study/util/Constants.java | 6 ++ .../kbss/study/util/RoleAssignmentUtil.java | 78 +++++++++++++++++++ src/main/resources/model.ttl | 4 + .../service/security/SecurityUtilsTest.java | 2 + 6 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/main/java/cz/cvut/kbss/study/util/RoleAssignmentUtil.java diff --git a/src/main/java/cz/cvut/kbss/study/model/User.java b/src/main/java/cz/cvut/kbss/study/model/User.java index 0685c80c..27c3537f 100644 --- a/src/main/java/cz/cvut/kbss/study/model/User.java +++ b/src/main/java/cz/cvut/kbss/study/model/User.java @@ -11,6 +11,7 @@ import cz.cvut.kbss.study.model.util.HasDerivableUri; import cz.cvut.kbss.study.util.Constants; import cz.cvut.kbss.study.util.IdentificationUtils; +import cz.cvut.kbss.study.util.RoleAssignmentUtil; import org.springframework.security.crypto.password.PasswordEncoder; import java.io.Serializable; @@ -61,9 +62,22 @@ public class User implements HasDerivableUri, Serializable { @OWLObjectProperty(iri = Vocabulary.s_p_is_member_of, fetch = FetchType.EAGER) private Institution institution; + @OWLDataProperty(iri = Vocabulary.s_p_role_group) + private String roleGroup; + @Types private Set types; + public String getRoleGroup() { + return roleGroup; + } + + public void setRoleGroup(String roleGroup) { + this.roleGroup = roleGroup; + this.types.clear(); + this.types = RoleAssignmentUtil.assignRolesForGroup(this.roleGroup); + } + public User() { this.types = new HashSet<>(); types.add(Vocabulary.s_c_doctor); @@ -216,7 +230,7 @@ public User copy() { copy.setInstitution(institution); copy.setIsInvited(isInvited); copy.setToken(token); - types.forEach(copy::addType); + copy.setRoleGroup(roleGroup); return copy; } diff --git a/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java b/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java index dc6795ff..223fd834 100644 --- a/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java +++ b/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java @@ -3,6 +3,7 @@ import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; +import cz.cvut.kbss.study.util.Constants; import jakarta.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,6 +53,7 @@ private void addDefaultAdministrator() { admin.setPassword("5y5t3mAdm1n."); admin.setInstitution(institutionService.findByName(INSTITUTION_NAME)); admin.setIsInvited(true); + admin.setRoleGroup(Constants.OPERATOR_ADMIN); admin.getTypes().add(Vocabulary.s_c_administrator); LOG.debug("Persisting default administrator {}", admin); userService.persist(admin); diff --git a/src/main/java/cz/cvut/kbss/study/util/Constants.java b/src/main/java/cz/cvut/kbss/study/util/Constants.java index 58289c76..19cdbb3b 100644 --- a/src/main/java/cz/cvut/kbss/study/util/Constants.java +++ b/src/main/java/cz/cvut/kbss/study/util/Constants.java @@ -68,4 +68,10 @@ private Constants() { * Excel MIME type */ public static final String MEDIA_TYPE_EXCEL = "application/vnd.ms-excel"; + + public static final String OPERATOR_ADMIN = "OPERATOR_ADMIN"; + public static final String OPERATOR_USER = "OPERATOR_USER"; + public static final String SUPPLIER_ADMIN = "SUPPLIER_ADMIN"; + public static final String SUPPLIER_USER = "SUPPLIER_USER"; + public static final String EXTERNAL_USER = "EXTERNAL_USER"; } diff --git a/src/main/java/cz/cvut/kbss/study/util/RoleAssignmentUtil.java b/src/main/java/cz/cvut/kbss/study/util/RoleAssignmentUtil.java new file mode 100644 index 00000000..7da11836 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/util/RoleAssignmentUtil.java @@ -0,0 +1,78 @@ +package cz.cvut.kbss.study.util; + +import cz.cvut.kbss.study.model.Vocabulary; + +import java.util.*; + +public class RoleAssignmentUtil { + + public static final Set OPERATOR_ADMIN_ROLES = new HashSet<>( + Set.of( + Vocabulary.s_c_administrator, + Vocabulary.s_c_doctor, + Vocabulary.s_c_edit_users, + Vocabulary.s_c_publish_records, + Vocabulary.s_c_reject_records, + Vocabulary.s_c_view_organization_records, + Vocabulary.s_c_edit_organization_records, + Vocabulary.s_c_delete_organization_records, + Vocabulary.s_c_complete_records, + Vocabulary.s_c_import_codelists + ) + ); + + public static final Set OPERATOR_USER_ROLES = new HashSet<>( + Set.of( + Vocabulary.s_c_complete_records + ) + ); + + public static final Set SUPPLIER_ADMIN_ROLES = new HashSet<>( + Set.of( + Vocabulary.s_c_administrator, + Vocabulary.s_c_doctor, + Vocabulary.s_c_edit_users, + Vocabulary.s_c_reject_records, + Vocabulary.s_c_view_organization_records, + Vocabulary.s_c_edit_organization_records, + Vocabulary.s_c_delete_organization_records, + Vocabulary.s_c_complete_records, + Vocabulary.s_c_import_codelists, + Vocabulary.s_c_edit_all_records, + Vocabulary.s_c_delete_all_records, + Vocabulary.s_c_view_all_records + ) + ); + + public static final Set SUPPLIER_USER_ROLES = new HashSet<>( + Set.of( + Vocabulary.s_c_complete_records + ) + ); + + public static final Map> roleGroups = Map.of( + Constants.OPERATOR_ADMIN, OPERATOR_ADMIN_ROLES, + Constants.OPERATOR_USER, OPERATOR_USER_ROLES, + Constants.SUPPLIER_ADMIN, SUPPLIER_ADMIN_ROLES, + Constants.SUPPLIER_USER, SUPPLIER_USER_ROLES, + Constants.EXTERNAL_USER, defaultRoles() + ); + + + public static Set assignRolesForGroup(String group) { + if(group != null) + return roleGroups.getOrDefault(group, defaultRoles()); + return defaultRoles(); + } + + /** + * Default roles to be assigned if the group is not recognized. + * + * @return A set of default roles + */ + private static Set defaultRoles() { + Set defaultRoles = new HashSet<>(); + defaultRoles.add(Vocabulary.s_c_doctor); + return defaultRoles; + } +} diff --git a/src/main/resources/model.ttl b/src/main/resources/model.ttl index 87a04aaa..770cf23e 100644 --- a/src/main/resources/model.ttl +++ b/src/main/resources/model.ttl @@ -66,6 +66,10 @@ rm:has-question rdf:type owl:ObjectProperty ; rm:is-member-of rdf:type owl:ObjectProperty ; rdfs:subPropertyOf rm:relates-to . +### http://onto.fel.cvut.cz/ontologies/record-manager/role-group +rm:role-group rdf:type owl:ObjectProperty ; + rdfs:subPropertyOf rm:relates-to . + ### http://onto.fel.cvut.cz/ontologies/record-manager/relates-to rm:relates-to rdf:type owl:ObjectProperty . diff --git a/src/test/java/cz/cvut/kbss/study/service/security/SecurityUtilsTest.java b/src/test/java/cz/cvut/kbss/study/service/security/SecurityUtilsTest.java index 8ee0bfc4..3b3008e9 100644 --- a/src/test/java/cz/cvut/kbss/study/service/security/SecurityUtilsTest.java +++ b/src/test/java/cz/cvut/kbss/study/service/security/SecurityUtilsTest.java @@ -12,6 +12,7 @@ import cz.cvut.kbss.study.security.model.UserDetails; import cz.cvut.kbss.study.service.ConfigReader; import cz.cvut.kbss.study.util.ConfigParam; +import cz.cvut.kbss.study.util.Constants; import cz.cvut.kbss.study.util.IdentificationUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -66,6 +67,7 @@ public void setUp() { Institution institution = Generator.generateInstitution(); institution.setKey(IdentificationUtils.generateKey()); this.user = Generator.getUser(USERNAME, PASSWORD, "John", "Johnie", "Johnie@gmail.com", institution); + this.user.setRoleGroup(Constants.OPERATOR_ADMIN); user.generateUri(); } From 37970557280d900488a84e075bbebb45d8313e71 Mon Sep 17 00:00:00 2001 From: Daniil Palagin Date: Wed, 18 Sep 2024 16:58:33 +0200 Subject: [PATCH 3/4] [kbss-cvut/record-manager-ui#202] Implement RoleGroup Service and Repository. --- .../java/cz/cvut/kbss/study/model/Role.java | 109 ++++++++++++++++++ .../cz/cvut/kbss/study/model/RoleGroup.java | 59 ++++++++++ .../study/persistence/dao/RoleGroupDao.java | 31 +++++ .../kbss/study/service/RoleGroupService.java | 8 ++ .../repository/RepositoryRoleGroup.java | 21 ++++ .../cz/cvut/kbss/study/model/RoleTest.java | 71 ++++++++++++ 6 files changed, 299 insertions(+) create mode 100644 src/main/java/cz/cvut/kbss/study/model/Role.java create mode 100644 src/main/java/cz/cvut/kbss/study/model/RoleGroup.java create mode 100644 src/main/java/cz/cvut/kbss/study/persistence/dao/RoleGroupDao.java create mode 100644 src/main/java/cz/cvut/kbss/study/service/RoleGroupService.java create mode 100644 src/main/java/cz/cvut/kbss/study/service/repository/RepositoryRoleGroup.java create mode 100644 src/test/java/cz/cvut/kbss/study/model/RoleTest.java diff --git a/src/main/java/cz/cvut/kbss/study/model/Role.java b/src/main/java/cz/cvut/kbss/study/model/Role.java new file mode 100644 index 00000000..8303c4ff --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/model/Role.java @@ -0,0 +1,109 @@ +package cz.cvut.kbss.study.model; + +import cz.cvut.kbss.jopa.model.annotations.Individual; + +public enum Role { + + // TODO deprecated -- should be removed. + @Individual(iri=Vocabulary.s_i_administrator) + administrator(Vocabulary.s_i_administrator), + // TODO deprecated -- should be removed. + @Individual(iri = Vocabulary.s_i_user) + user(Vocabulary.s_i_user), + + @Individual(iri = Vocabulary.s_i_impersonate_role) + impersonate(Vocabulary.s_i_impersonate_role), + + @Individual(iri = Vocabulary.s_i_delete_all_records_role) + deleteAllRecords(Vocabulary.s_i_delete_all_records_role), + + @Individual(iri = Vocabulary.s_i_view_all_records_role) + viewAllRecords(Vocabulary.s_i_view_all_records_role), + + @Individual(iri = Vocabulary.s_i_edit_all_records_role) + editAllRecords(Vocabulary.s_i_edit_all_records_role), + + @Individual(iri = Vocabulary.s_i_delete_organization_records_role) + deleteOrganizationRecords(Vocabulary.s_i_delete_organization_records_role), + + @Individual(iri = Vocabulary.s_i_view_organization_records_role) + viewOrganizationRecords(Vocabulary.s_i_view_organization_records_role), + + @Individual(iri = Vocabulary.s_i_edit_organization_records_role) + editOrganizationRecords(Vocabulary.s_i_edit_organization_records_role), + + @Individual(iri = Vocabulary.s_i_edit_users_role) + editUsers(Vocabulary.s_i_edit_users_role), + + @Individual(iri = Vocabulary.s_i_complete_records_role) + completeRecords(Vocabulary.s_i_complete_records_role), + + @Individual(iri = Vocabulary.s_i_reject_records_role) + rejectRecords(Vocabulary.s_i_reject_records_role), + + @Individual(iri = Vocabulary.s_i_publish_records_role) + publishRecords(Vocabulary.s_i_publish_records_role), + + @Individual(iri = Vocabulary.s_i_import_codelists_role) + importCodelists(Vocabulary.s_i_import_codelists_role); + + private final String iri; + + Role(String iri) { + this.iri = iri; + } + + public String getIri() { + return iri; + } + + /** + * Returns {@link Role} with the specified IRI. + * + * @param iri role identifier + * @return matching {@code Role} + * @throws IllegalArgumentException When no matching role is found + */ + public static Role fromIri(String iri) { + for (Role r : values()) { + if (r.getIri().equals(iri)) { + return r; + } + } + throw new IllegalArgumentException("Unknown role identifier '" + iri + "'."); + } + + /** + * Returns {@link Role} with the specified constant name. + * + * @param name role name + * @return matching {@code Role} + * @throws IllegalArgumentException When no matching role is found + */ + public static Role fromName(String name) { + for (Role r : values()) { + if (r.name().equalsIgnoreCase(name)) { + return r; + } + } + throw new IllegalArgumentException("Unknown role '" + name + "'."); + } + + /** + * Returns a {@link Role} with the specified IRI or constant name. + *

+ * This function first tries to find the enum constant by IRI. If it is not found, constant name matching is + * attempted. + * + * @param identification Constant IRI or name to find match by + * @return matching {@code Role} + * @throws IllegalArgumentException When no matching role is found + */ + public static Role fromIriOrName(String identification) { + try { + return fromIri(identification); + } catch (IllegalArgumentException e) { + return fromName(identification); + } + } +} diff --git a/src/main/java/cz/cvut/kbss/study/model/RoleGroup.java b/src/main/java/cz/cvut/kbss/study/model/RoleGroup.java new file mode 100644 index 00000000..c687f78a --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/model/RoleGroup.java @@ -0,0 +1,59 @@ +package cz.cvut.kbss.study.model; +import cz.cvut.kbss.jopa.model.annotations.*; +import cz.cvut.kbss.study.model.util.HasDerivableUri; +import cz.cvut.kbss.study.model.util.HasOwlKey; +import cz.cvut.kbss.study.util.Constants; + +import java.net.URI; +import java.util.HashSet; +import java.util.Set; + +@OWLClass(iri = Vocabulary.s_c_role_group) +public class RoleGroup implements HasDerivableUri { + + @Id + private URI uri; + + @OWLAnnotationProperty(iri = Vocabulary.s_p_label) + private String name; + + @OWLObjectProperty(iri = Vocabulary.s_p_has_role) + private Set roles; + + public void addRole(Role role){ + if(roles == null){ + roles = new HashSet<>(); + } + roles.add(role); + } + + + public URI getUri() { + return uri; + } + + public void setUri(URI uri) { + this.uri = uri; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getRoles() { + return roles; + } + + public void setRoles(Set roles) { + this.roles = roles; + } + + @Override + public void generateUri() { + this.uri = URI.create(Constants.BASE_URI + name); + } +} diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/RoleGroupDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/RoleGroupDao.java new file mode 100644 index 00000000..c78dfb5b --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/RoleGroupDao.java @@ -0,0 +1,31 @@ +package cz.cvut.kbss.study.persistence.dao; + +import cz.cvut.kbss.jopa.exceptions.NoResultException; +import cz.cvut.kbss.jopa.model.EntityManager; +import cz.cvut.kbss.study.model.RoleGroup; +import cz.cvut.kbss.study.util.Constants; +import org.springframework.stereotype.Repository; +import java.net.URI; +import cz.cvut.kbss.study.model.Vocabulary; + +@Repository +public class RoleGroupDao extends DerivableUriDao { + + protected RoleGroupDao(EntityManager em) { + super(RoleGroup.class, em); + } + + public RoleGroup findByName(String name) { + if (name == null) { + return null; + } + try { + return em.createNativeQuery("SELECT ?x WHERE { ?x ?hasName ?name . }", RoleGroup.class) + .setParameter("hasName", URI.create(Vocabulary.s_p_label)) + .setParameter("name", name, Constants.PU_LANGUAGE).getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + +} diff --git a/src/main/java/cz/cvut/kbss/study/service/RoleGroupService.java b/src/main/java/cz/cvut/kbss/study/service/RoleGroupService.java new file mode 100644 index 00000000..554b21be --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/service/RoleGroupService.java @@ -0,0 +1,8 @@ +package cz.cvut.kbss.study.service; + +import cz.cvut.kbss.study.model.RoleGroup; +import org.springframework.stereotype.Service; + +public interface RoleGroupService { + RoleGroup findByName(String name); +} diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryRoleGroup.java b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryRoleGroup.java new file mode 100644 index 00000000..b6cb5d75 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryRoleGroup.java @@ -0,0 +1,21 @@ +package cz.cvut.kbss.study.service.repository; + +import cz.cvut.kbss.study.model.RoleGroup; +import cz.cvut.kbss.study.persistence.dao.RoleGroupDao; +import cz.cvut.kbss.study.service.RoleGroupService; +import org.springframework.stereotype.Service; + +@Service +public class RepositoryRoleGroup implements RoleGroupService { + + private final RoleGroupDao roleGroupDao; + + public RepositoryRoleGroup(RoleGroupDao roleGroupDao) { + this.roleGroupDao = roleGroupDao; + } + + @Override + public RoleGroup findByName(String name) { + return roleGroupDao.findByName(name); + } +} diff --git a/src/test/java/cz/cvut/kbss/study/model/RoleTest.java b/src/test/java/cz/cvut/kbss/study/model/RoleTest.java new file mode 100644 index 00000000..8f7209dc --- /dev/null +++ b/src/test/java/cz/cvut/kbss/study/model/RoleTest.java @@ -0,0 +1,71 @@ +package cz.cvut.kbss.study.model; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class RoleTest { + + @Test + void fromIriReturnsCorrectRole() { + assertEquals(Role.administrator, Role.fromIri(Vocabulary.s_i_administrator)); + assertEquals(Role.viewAllRecords, Role.fromIri(Vocabulary.s_i_view_all_records_role)); + } + + @Test + void fromIriThrowsExceptionForUnknownIri() { + String unknownIri = "unknown_iri"; + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + Role.fromIri(unknownIri); + }); + assertEquals("Unknown role identifier '" + unknownIri + "'.", exception.getMessage()); + } + + + @Test + void fromNameReturnsCorrectRole() { + assertEquals(Role.administrator, Role.fromName("administrator")); + assertEquals(Role.viewAllRecords, Role.fromName("viewAllRecords")); + } + + @Test + void fromNameIsCaseInsensitive() { + assertEquals(Role.administrator, Role.fromName("ADMINISTRATOR")); + assertEquals(Role.viewAllRecords, Role.fromName("VIEWALLRECORDS")); + } + + @Test + void fromNameThrowsExceptionForUnknownName() { + String unknownName = "unknown_role"; + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + Role.fromName(unknownName); + }); + assertEquals("Unknown role '" + unknownName + "'.", exception.getMessage()); + } + + + @Test + void fromIriOrNameReturnsRoleByIri() { + assertEquals(Role.administrator, Role.fromIriOrName(Vocabulary.s_i_administrator)); + assertEquals(Role.viewAllRecords, Role.fromIriOrName(Vocabulary.s_i_view_all_records_role)); + } + + @Test + void fromIriOrNameReturnsRoleByName() { + assertEquals(Role.administrator, Role.fromIriOrName("administrator")); + assertEquals(Role.viewAllRecords, Role.fromIriOrName("viewAllRecords")); + } + + @Test + void fromIriOrNameIsCaseInsensitiveForName() { + assertEquals(Role.administrator, Role.fromIriOrName("ADMINISTRATOR")); + } + + @Test + void fromIriOrNameThrowsExceptionForUnknownIdentifier() { + String unknownIdentifier = "unknown_identifier"; + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + Role.fromIriOrName(unknownIdentifier); + }); + assertEquals("Unknown role '" + unknownIdentifier + "'.", exception.getMessage()); + } +} From e68a4891a8e73716672e1fc73f61029f91983899 Mon Sep 17 00:00:00 2001 From: Daniil Palagin Date: Wed, 18 Sep 2024 17:09:06 +0200 Subject: [PATCH 4/4] [kbss-cvut/record-manager-ui#202] Refactor model.ttl --- .../java/cz/cvut/kbss/study/model/User.java | 13 ++- .../cvut/kbss/study/security/model/Role.java | 22 ++--- .../kbss/study/service/SystemInitializer.java | 10 +- .../kbss/study/util/RoleAssignmentUtil.java | 40 ++++---- src/main/resources/model.ttl | 98 ++++++++++++------- 5 files changed, 115 insertions(+), 68 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/study/model/User.java b/src/main/java/cz/cvut/kbss/study/model/User.java index 27c3537f..77fa0a12 100644 --- a/src/main/java/cz/cvut/kbss/study/model/User.java +++ b/src/main/java/cz/cvut/kbss/study/model/User.java @@ -62,9 +62,12 @@ public class User implements HasDerivableUri, Serializable { @OWLObjectProperty(iri = Vocabulary.s_p_is_member_of, fetch = FetchType.EAGER) private Institution institution; - @OWLDataProperty(iri = Vocabulary.s_p_role_group) + @OWLDataProperty(iri = Vocabulary.s_p_has_role_group) private String roleGroup; + @OWLObjectProperty(iri = Vocabulary.s_p_has_role_group) + private RoleGroup rg; + @Types private Set types; @@ -83,6 +86,13 @@ public User() { types.add(Vocabulary.s_c_doctor); } + public void setRg(RoleGroup rg) { + this.rg = rg; + } + public RoleGroup getRg() { + return rg; + } + @Override public URI getUri() { return uri; @@ -231,6 +241,7 @@ public User copy() { copy.setIsInvited(isInvited); copy.setToken(token); copy.setRoleGroup(roleGroup); + copy.setRg(rg); return copy; } diff --git a/src/main/java/cz/cvut/kbss/study/security/model/Role.java b/src/main/java/cz/cvut/kbss/study/security/model/Role.java index 36c4b970..e1514035 100644 --- a/src/main/java/cz/cvut/kbss/study/security/model/Role.java +++ b/src/main/java/cz/cvut/kbss/study/security/model/Role.java @@ -9,17 +9,17 @@ public enum Role { USER(SecurityConstants.ROLE_USER, Vocabulary.s_c_doctor), ADMIN(SecurityConstants.ROLE_ADMIN, Vocabulary.s_c_administrator), - COMPLETE_RECORDS(SecurityConstants.ROLE_COMPLETE_RECORDS, Vocabulary.s_c_complete_records), - DELETE_ALL_RECORDS(SecurityConstants.ROLE_DELETE_ALL_RECORDS, Vocabulary.s_c_delete_all_records), - DELETE_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_DELETE_ORGANIZATION_RECORDS, Vocabulary.s_c_delete_organization_records), - EDIT_ALL_RECORDS(SecurityConstants.ROLE_EDIT_ALL_RECORDS, Vocabulary.s_c_edit_all_records), - EDIT_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_EDIT_ORGANIZATION_RECORDS, Vocabulary.s_c_edit_organization_records), - EDIT_USERS(SecurityConstants.ROLE_EDIT_USERS, Vocabulary.s_c_edit_users), - IMPORT_CODELISTS(SecurityConstants.ROLE_IMPORT_CODELISTS, Vocabulary.s_c_import_codelists), - PUBLISH_RECORDS(SecurityConstants.ROLE_PUBLISH_RECORDS, Vocabulary.s_c_publish_records), - REJECT_RECORDS(SecurityConstants.ROLE_REJECT_RECORDS, Vocabulary.s_c_reject_records), - VIEW_ALL_RECORDS(SecurityConstants.ROLE_VIEW_ALL_RECORDS, Vocabulary.s_c_view_all_records), - VIEW_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_VIEW_ORGANIZATION_RECORDS, Vocabulary.s_c_view_organization_records); + COMPLETE_RECORDS(SecurityConstants.ROLE_COMPLETE_RECORDS, Vocabulary.s_i_complete_records_role), + DELETE_ALL_RECORDS(SecurityConstants.ROLE_DELETE_ALL_RECORDS, Vocabulary.s_i_delete_all_records_role), + DELETE_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_DELETE_ORGANIZATION_RECORDS, Vocabulary.s_i_delete_organization_records_role), + EDIT_ALL_RECORDS(SecurityConstants.ROLE_EDIT_ALL_RECORDS, Vocabulary.s_i_edit_all_records_role), + EDIT_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_EDIT_ORGANIZATION_RECORDS, Vocabulary.s_i_edit_organization_records_role), + EDIT_USERS(SecurityConstants.ROLE_EDIT_USERS, Vocabulary.s_i_edit_users_role), + IMPORT_CODELISTS(SecurityConstants.ROLE_IMPORT_CODELISTS, Vocabulary.s_i_import_codelists_role), + PUBLISH_RECORDS(SecurityConstants.ROLE_PUBLISH_RECORDS, Vocabulary.s_i_publish_records_role), + REJECT_RECORDS(SecurityConstants.ROLE_REJECT_RECORDS, Vocabulary.s_i_reject_records_role), + VIEW_ALL_RECORDS(SecurityConstants.ROLE_VIEW_ALL_RECORDS, Vocabulary.s_i_view_all_records_role), + VIEW_ORGANIZATIONS_RECORDS(SecurityConstants.ROLE_VIEW_ORGANIZATION_RECORDS, Vocabulary.s_i_view_organization_records_role); private final String name; private final String type; diff --git a/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java b/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java index 223fd834..a23dca1e 100644 --- a/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java +++ b/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java @@ -1,6 +1,7 @@ package cz.cvut.kbss.study.service; import cz.cvut.kbss.study.model.Institution; +import cz.cvut.kbss.study.model.RoleGroup; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; import cz.cvut.kbss.study.util.Constants; @@ -10,6 +11,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; +import java.net.URI; + @ConditionalOnProperty(prefix = "security", name = "provider", havingValue = "internal", matchIfMissing = true) @Service public class SystemInitializer { @@ -18,15 +21,19 @@ public class SystemInitializer { private static final String ADMIN_USERNAME = "admin"; private static final String INSTITUTION_NAME = "admin_institution"; + private static final String ROLE_GROUP_NAME = "admin-role-group"; private final UserService userService; private final InstitutionService institutionService; + private final RoleGroupService roleGroupService; + public SystemInitializer(UserService userService, - InstitutionService institutionService) { + InstitutionService institutionService, RoleGroupService roleGroupService) { this.userService = userService; this.institutionService = institutionService; + this.roleGroupService = roleGroupService; } @PostConstruct @@ -55,6 +62,7 @@ private void addDefaultAdministrator() { admin.setIsInvited(true); admin.setRoleGroup(Constants.OPERATOR_ADMIN); admin.getTypes().add(Vocabulary.s_c_administrator); + admin.setRg(roleGroupService.findByName(ROLE_GROUP_NAME)); LOG.debug("Persisting default administrator {}", admin); userService.persist(admin); } diff --git a/src/main/java/cz/cvut/kbss/study/util/RoleAssignmentUtil.java b/src/main/java/cz/cvut/kbss/study/util/RoleAssignmentUtil.java index 7da11836..c66f406b 100644 --- a/src/main/java/cz/cvut/kbss/study/util/RoleAssignmentUtil.java +++ b/src/main/java/cz/cvut/kbss/study/util/RoleAssignmentUtil.java @@ -10,20 +10,20 @@ public class RoleAssignmentUtil { Set.of( Vocabulary.s_c_administrator, Vocabulary.s_c_doctor, - Vocabulary.s_c_edit_users, - Vocabulary.s_c_publish_records, - Vocabulary.s_c_reject_records, - Vocabulary.s_c_view_organization_records, - Vocabulary.s_c_edit_organization_records, - Vocabulary.s_c_delete_organization_records, - Vocabulary.s_c_complete_records, - Vocabulary.s_c_import_codelists + Vocabulary.s_i_edit_users_role, + Vocabulary.s_i_publish_records_role, + Vocabulary.s_i_reject_records_role, + Vocabulary.s_i_view_organization_records_role, + Vocabulary.s_i_edit_organization_records_role, + Vocabulary.s_i_delete_organization_records_role, + Vocabulary.s_i_complete_records_role, + Vocabulary.s_i_import_codelists_role ) ); public static final Set OPERATOR_USER_ROLES = new HashSet<>( Set.of( - Vocabulary.s_c_complete_records + Vocabulary.s_i_complete_records_role ) ); @@ -31,22 +31,22 @@ public class RoleAssignmentUtil { Set.of( Vocabulary.s_c_administrator, Vocabulary.s_c_doctor, - Vocabulary.s_c_edit_users, - Vocabulary.s_c_reject_records, - Vocabulary.s_c_view_organization_records, - Vocabulary.s_c_edit_organization_records, - Vocabulary.s_c_delete_organization_records, - Vocabulary.s_c_complete_records, - Vocabulary.s_c_import_codelists, - Vocabulary.s_c_edit_all_records, - Vocabulary.s_c_delete_all_records, - Vocabulary.s_c_view_all_records + Vocabulary.s_i_edit_users_role, + Vocabulary.s_i_reject_records_role, + Vocabulary.s_i_view_organization_records_role, + Vocabulary.s_i_edit_organization_records_role, + Vocabulary.s_i_delete_organization_records_role, + Vocabulary.s_i_complete_records_role, + Vocabulary.s_i_import_codelists_role, + Vocabulary.s_i_edit_all_records_role, + Vocabulary.s_i_delete_all_records_role, + Vocabulary.s_i_view_all_records_role ) ); public static final Set SUPPLIER_USER_ROLES = new HashSet<>( Set.of( - Vocabulary.s_c_complete_records + Vocabulary.s_i_complete_records_role ) ); diff --git a/src/main/resources/model.ttl b/src/main/resources/model.ttl index 770cf23e..67c8dece 100644 --- a/src/main/resources/model.ttl +++ b/src/main/resources/model.ttl @@ -84,6 +84,15 @@ rm:has-phase rdf:type owl:ObjectProperty ; rdfs:subPropertyOf rdf:type ; rdfs:label "has phase"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/has-role-group +rm:has-role-group rdf:type owl:ObjectProperty ; + rdfs:subPropertyOf rm:relates-to; + rdfs:label "has role group"@en. + +### http://onto.fel.cvut.cz/ontologies/record-manager/has-role +rm:has-role rdf:type owl:ObjectProperty ; + rdfs:subPropertyOf rm:relates-to; + rdfs:label "has role"@en. ################################################################# # Data properties @@ -203,55 +212,74 @@ rm:rejected-record-phase rdf:type owl:Class ; rdfs:subClassOf rm:record-phase ; rdfs:label "rejected record phase"@en . -### Generated by the OWL API (version 4.2.8.20170104-2310) https://github.com/owlcs/owlapi +### http://onto.fel.cvut.cz/ontologies/record-manager/role +rm:role rdf:type owl:Class; + rdfs:label "user role"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/role-group +rm:role-group rdf:type owl:Class; + rdfs:label "user role group" . ################################################################# -# New Roles +# Roles ################################################################# +### http://onto.fel.cvut.cz/ontologies/record-manager/administrator +### TODO deprecated +rm:administrator rdf:type owl:NamedIndividual, rm:role ; + rdfs:label "administrator"@en . + +### http://onto.fel.cvut.cz/ontologies/record-manager/user +### TODO deprecated +rm:user rdf:type owl:NamedIndividual, rm:role ; + rdfs:label "user"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/complete-records -rm:complete-records rdf:type owl:Class ; - rdfs:label "Complete Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/complete-records-role +rm:complete-records-role rdf:type owl:NamedIndividual, rm:role ; + rdfs:label "complete records role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/delete-all-records -rm:delete-all-records rdf:type owl:Class ; - rdfs:label "Delete All Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/delete-all-records-role +rm:delete-all-records-role rdf:type owl:NamedIndividual, rm:role ; + rdfs:label "delete all records role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/edit-all-records -rm:edit-all-records rdf:type owl:Class ; - rdfs:label "Edit All Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/edit-all-records-role +rm:edit-all-records-role rdf:type owl:NamedIndividual, rm:role ; + rdfs:label "edit all records role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/view-all-records -rm:view-all-records rdf:type owl:Class ; - rdfs:label "View All Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/view-all-records-role +rm:view-all-records-role rdf:type owl:NamedIndividual, rm:role ; + rdfs:label "view all records role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/delete-organization-records -rm:delete-organization-records rdf:type owl:Class ; - rdfs:label "Delete Organization Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/delete-organization-records-role +rm:delete-organization-records-role rdf:type owl:NamedIndividual, rm:role ; + rdfs:label "delete organization records role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/edit-organization-records -rm:edit-organization-records rdf:type owl:Class ; - rdfs:label "Edit Organization Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/edit-organization-records-role +rm:edit-organization-records-role rdf:type owl:NamedIndividual, rm:role; + rdfs:label "edit organization records role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/view-organization-records -rm:view-organization-records rdf:type owl:Class ; - rdfs:label "View Organization Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/view-organization-records-role +rm:view-organization-records-role rdf:type owl:NamedIndividual, rm:role; + rdfs:label "view organization records role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/edit-users -rm:edit-users rdf:type owl:Class ; - rdfs:label "Edit Users"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/edit-users-role +rm:edit-users-role rdf:type owl:NamedIndividual, rm:role; + rdfs:label "edit users role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/import-codelists -rm:import-codelists rdf:type owl:Class ; - rdfs:label "Import Codelists"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/import-codelists-role +rm:import-codelists-role rdf:type owl:NamedIndividual, rm:role; + rdfs:label "import codelists role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/publish-records -rm:publish-records rdf:type owl:Class ; - rdfs:label "Publish Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/publish-records-role +rm:publish-records-role rdf:type owl:NamedIndividual, rm:role; + rdfs:label "publish records role"@en . -### http://onto.fel.cvut.cz/ontologies/record-manager/reject-records -rm:reject-records rdf:type owl:Class ; - rdfs:label "Reject Records"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/reject-records-role +rm:reject-records-role rdf:type owl:NamedIndividual, rm:role; + rdfs:label "reject records role"@en . +### http://onto.fel.cvut.cz/ontologies/record-manager/impersonate-role +rm:impersonate-role rdf:type owl:NamedIndividual, rm:role; + rdfs:label "impersonate role"@en . +### Generated by the OWL API (version 4.2.8.20170104-2310) https://github.com/owlcs/owlapi \ No newline at end of file