From 4ff053eb5028fb8b71aecfdad7ca3465c542c0b2 Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Thu, 21 May 2020 14:55:23 +0200 Subject: [PATCH 01/68] Deleted default values --- src/main/java/com/patternpedia/api/PatternPediaAPI.java | 9 --------- .../patternpedia/api/rest/controller/UserController.java | 9 --------- 2 files changed, 18 deletions(-) diff --git a/src/main/java/com/patternpedia/api/PatternPediaAPI.java b/src/main/java/com/patternpedia/api/PatternPediaAPI.java index d00720d..b160515 100644 --- a/src/main/java/com/patternpedia/api/PatternPediaAPI.java +++ b/src/main/java/com/patternpedia/api/PatternPediaAPI.java @@ -35,15 +35,6 @@ public static void main(String[] args) { @Override public void run(String... args) { - log.info("PatternPediaAPI is up"); - // Used this for testing purposes, will be deleted in the final build -// userController.defaultUsers(); -// Issue issue = new Issue(); -// issue.setUri("uri"); -// issue.setName("name"); -// issue.setDescription("description"); -// Issue p = issueService.createIssue(issue); -// log.info(p.toString()); } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/UserController.java b/src/main/java/com/patternpedia/api/rest/controller/UserController.java index 1529965..8624532 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/UserController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/UserController.java @@ -63,15 +63,6 @@ public UserEntity newUser(@RequestBody UserEntity user) { } - public void defaultUsers() { - List role = new ArrayList<>(Arrays.asList(UserRole.MEMBER)); - UserEntity userMember = new UserEntity("Member User", "member@mail", passwordEncoder.encode("pass"), role); - this.userService.createUser(userMember); - role.add(UserRole.ADMIN); - UserEntity userAdmin = new UserEntity("Admin User", "admin@mail", passwordEncoder.encode("pass"), role); - this.userService.createUser(userAdmin); - } - /** * UPDATE Methods */ From 5257be988960657957499f3b23695d774566548c Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Thu, 11 Jun 2020 22:55:30 +0200 Subject: [PATCH 02/68] CHANGED & ADDED files --- .../api/config/SetupDataLoader.java | 153 +++++++++++++ .../api/entities/candidate/Candidate.java | 58 ++--- .../{rating => }/CandidateRating.java | 18 +- .../candidate/author/CandidateAuthor.java | 47 ++++ .../{ => comment}/CandidateComment.java | 13 +- .../CandidateCommentRating.java | 16 +- .../rating/CandidateCommentRatingKey.java | 21 -- .../candidate/rating/CandidateRatingKey.java | 21 -- .../api/entities/issue/Issue.java | 45 ++-- .../issue/{rating => }/IssueRating.java | 24 +- .../entities/issue/author/IssueAuthor.java | 46 ++++ .../issue/{ => comment}/IssueComment.java | 21 +- .../IssueCommentRating.java | 15 +- .../issue/rating/IssueCommentRatingKey.java | 21 -- .../api/entities/shared/AuthorConstant.java | 7 + .../api/entities/shared/Comment.java | 5 +- .../CompositeKey.java} | 6 +- .../api/entities/user/UserEntity.java | 48 ++-- .../api/entities/user/UserRole.java | 9 - .../api/entities/user/role/Privilege.java | 46 ++++ .../entities/user/role/PrivilegeConstant.java | 24 ++ .../api/entities/user/role/Role.java | 34 +++ .../api/entities/user/role/RoleConstant.java | 10 + .../exception/CandidateNotFoundException.java | 21 -- .../exception/CommentNotFoundException.java | 21 -- .../api/exception/NullIssueException.java | 13 -- .../api/exception/NullRoleException.java | 12 + ...eption.java => RoleNotFoundException.java} | 8 +- .../exception/UserAlreadyVotedException.java | 25 -- .../CandidateAuthorRepository.java | 11 + .../CandidateCommentRatingRepository.java | 13 +- .../CandidateCommentRepository.java | 2 +- .../CandidateRatingRepository.java | 18 +- .../api/repositories/CandidateRepository.java | 2 +- .../repositories/IssueAuthorRepository.java | 11 + .../IssueCommentRatingRepository.java | 10 +- .../repositories/IssueCommentRepository.java | 2 +- .../repositories/IssueRatingRepository.java | 16 +- .../api/repositories/IssueRepository.java | 4 +- .../api/repositories/PrivilegeRepository.java | 11 + .../api/repositories/RoleRepository.java | 12 + .../api/repositories/UserRepository.java | 3 +- .../api/rest/controller/AuthorController.java | 98 ++++++++ .../rest/controller/CandidateController.java | 61 +++-- .../api/rest/controller/IssueController.java | 58 +++-- .../api/rest/controller/RatingController.java | 52 +++++ .../api/rest/controller/UserController.java | 60 +++-- .../api/rest/model/CandidateModel.java | 64 ------ .../api/rest/model/IssueModel.java | 31 --- .../rest/model/candidate/CandidateModel.java | 65 ++++++ .../candidate/CandidateModelRequest.java | 19 ++ .../api/rest/model/issue/IssueModel.java | 50 ++++ .../rest/model/issue/IssueModelRequest.java | 17 ++ .../api/rest/model/shared/AuthorModel.java | 42 ++++ .../rest/model/shared/AuthorModelRequest.java | 15 ++ .../api/rest/model/shared/CommentModel.java | 57 +++++ .../api/rest/model/shared/RatingModel.java | 41 ++++ .../rest/model/shared/RatingModelRequest.java | 13 ++ .../api/rest/model/user/PrivilegeModel.java | 23 ++ .../api/rest/model/user/RoleModel.java | 29 +++ .../api/rest/model/user/RoleModelRequest.java | 13 ++ .../api/rest/model/user/UserModel.java | 39 ++++ .../api/rest/model/user/UserModelRequest.java | 14 ++ .../api/service/AuthorService.java | 24 ++ .../api/service/AuthorServiceImpl.java | 88 +++++++ .../api/service/CandidateService.java | 26 +-- .../api/service/CandidateServiceImpl.java | 151 +++++++----- .../api/service/IssueService.java | 23 +- .../api/service/IssueServiceImpl.java | 215 +++++++----------- .../api/service/RatingService.java | 21 ++ .../api/service/RatingServiceImpl.java | 109 +++++++++ .../patternpedia/api/service/UserService.java | 19 +- .../api/service/UserServiceImpl.java | 112 ++++++--- src/main/resources/applicationYML.yml | 35 --- src/main/resources/db/migration/data.sql | 6 + 75 files changed, 1843 insertions(+), 770 deletions(-) create mode 100644 src/main/java/com/patternpedia/api/config/SetupDataLoader.java rename src/main/java/com/patternpedia/api/entities/candidate/{rating => }/CandidateRating.java (76%) create mode 100644 src/main/java/com/patternpedia/api/entities/candidate/author/CandidateAuthor.java rename src/main/java/com/patternpedia/api/entities/candidate/{ => comment}/CandidateComment.java (70%) rename src/main/java/com/patternpedia/api/entities/candidate/{rating => comment}/CandidateCommentRating.java (78%) delete mode 100644 src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateCommentRatingKey.java delete mode 100644 src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateRatingKey.java rename src/main/java/com/patternpedia/api/entities/issue/{rating => }/IssueRating.java (63%) create mode 100644 src/main/java/com/patternpedia/api/entities/issue/author/IssueAuthor.java rename src/main/java/com/patternpedia/api/entities/issue/{ => comment}/IssueComment.java (65%) rename src/main/java/com/patternpedia/api/entities/issue/{rating => comment}/IssueCommentRating.java (78%) delete mode 100644 src/main/java/com/patternpedia/api/entities/issue/rating/IssueCommentRatingKey.java create mode 100644 src/main/java/com/patternpedia/api/entities/shared/AuthorConstant.java rename src/main/java/com/patternpedia/api/entities/{issue/rating/IssueRatingKey.java => shared/CompositeKey.java} (71%) delete mode 100644 src/main/java/com/patternpedia/api/entities/user/UserRole.java create mode 100644 src/main/java/com/patternpedia/api/entities/user/role/Privilege.java create mode 100644 src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java create mode 100644 src/main/java/com/patternpedia/api/entities/user/role/Role.java create mode 100644 src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java delete mode 100644 src/main/java/com/patternpedia/api/exception/CandidateNotFoundException.java delete mode 100644 src/main/java/com/patternpedia/api/exception/CommentNotFoundException.java delete mode 100644 src/main/java/com/patternpedia/api/exception/NullIssueException.java create mode 100644 src/main/java/com/patternpedia/api/exception/NullRoleException.java rename src/main/java/com/patternpedia/api/exception/{IssueNotFoundException.java => RoleNotFoundException.java} (60%) delete mode 100644 src/main/java/com/patternpedia/api/exception/UserAlreadyVotedException.java create mode 100644 src/main/java/com/patternpedia/api/repositories/CandidateAuthorRepository.java create mode 100644 src/main/java/com/patternpedia/api/repositories/IssueAuthorRepository.java create mode 100644 src/main/java/com/patternpedia/api/repositories/PrivilegeRepository.java create mode 100644 src/main/java/com/patternpedia/api/repositories/RoleRepository.java create mode 100644 src/main/java/com/patternpedia/api/rest/controller/AuthorController.java create mode 100644 src/main/java/com/patternpedia/api/rest/controller/RatingController.java delete mode 100644 src/main/java/com/patternpedia/api/rest/model/CandidateModel.java delete mode 100644 src/main/java/com/patternpedia/api/rest/model/IssueModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/issue/IssueModelRequest.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/AuthorModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/RatingModelRequest.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/user/PrivilegeModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/user/RoleModelRequest.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/user/UserModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/user/UserModelRequest.java create mode 100644 src/main/java/com/patternpedia/api/service/AuthorService.java create mode 100644 src/main/java/com/patternpedia/api/service/AuthorServiceImpl.java create mode 100644 src/main/java/com/patternpedia/api/service/RatingService.java create mode 100644 src/main/java/com/patternpedia/api/service/RatingServiceImpl.java delete mode 100644 src/main/resources/applicationYML.yml create mode 100644 src/main/resources/db/migration/data.sql diff --git a/src/main/java/com/patternpedia/api/config/SetupDataLoader.java b/src/main/java/com/patternpedia/api/config/SetupDataLoader.java new file mode 100644 index 0000000..7697b9c --- /dev/null +++ b/src/main/java/com/patternpedia/api/config/SetupDataLoader.java @@ -0,0 +1,153 @@ +package com.patternpedia.api.config; + +import com.patternpedia.api.entities.user.role.PrivilegeConstant; +import com.patternpedia.api.entities.user.role.RoleConstant; +import com.patternpedia.api.entities.user.role.Privilege; +import com.patternpedia.api.entities.user.role.Role; +import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.repositories.PrivilegeRepository; +import com.patternpedia.api.repositories.RoleRepository; +import com.patternpedia.api.repositories.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +import javax.transaction.Transactional; +import java.util.Arrays; +import java.util.Collection; + +@Component +public class SetupDataLoader implements ApplicationListener { + + boolean alreadySetup = false; + + @Autowired + private UserRepository userRepository; + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private PrivilegeRepository privilegeRepository; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Override + @Transactional + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { + if (alreadySetup) + return; + + /** Privileges */ + /** USER */ + Privilege readUserAllPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.READ_USER_ALL); + Privilege readUserPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.READ_USER); + Privilege createUserPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.CREATE_USER); + Privilege updateUserPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.UPDATE_USER); + Privilege deleteUserPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.DELETE_USER); + /** ISSUE */ + Privilege readIssuePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.READ_ISSUE); + Privilege createIssuePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.CREATE_ISSUE); + Privilege updateIssuePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.UPDATE_ISSUE); + Privilege deleteIssuePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.DELETE_ISSUE); + /** CANDIDATE */ + Privilege readCandidatePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.READ_CANDIDATE); + Privilege createCandidatePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.CREATE_CANDIDATE); + Privilege updateCandidatePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.UPDATE_CANDIDATE); + Privilege deleteCandidatePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.DELETE_CANDIDATE); + /** ROLE */ + String UPDATE_ROLE = "UPDATE_ROLE"; + /** DEVELOPER */ + Privilege developerPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.DEVELOPER); + + /** Roles */ + createRoleIfNotFound(RoleConstant.MEMBER, Arrays.asList( + //USER + updateUserPrivilege, readUserPrivilege, + //ISSUES + readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege + )); + createRoleIfNotFound(RoleConstant.EXPERT, Arrays.asList( + //USER + updateUserPrivilege, + //ISSUES + readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, + //CANDIDATE + createCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege + )); + createRoleIfNotFound(RoleConstant.LIBRARIAN, Arrays.asList( + //USER + readUserAllPrivilege, readUserPrivilege, createUserPrivilege, updateUserPrivilege, deleteUserPrivilege, + //ISSUES + readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, + //CANDIDATE + createCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege + )); + createRoleIfNotFound(RoleConstant.ADMIN, Arrays.asList( + //USER + readUserAllPrivilege, readUserPrivilege, createUserPrivilege, updateUserPrivilege, deleteUserPrivilege, + //ISSUES + readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, + //CANDIDATE + createCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege, + //DEVELOPER + developerPrivilege + )); + createRoleIfNotFound(RoleConstant.DEVELOPER, Arrays.asList( + //USER + readUserAllPrivilege, readUserPrivilege, createUserPrivilege, updateUserPrivilege, deleteUserPrivilege, + //ISSUES + readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, + //CANDIDATE + createCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege, + //DEVELOPER + developerPrivilege + )); + + createUser(new UserEntity("MEMBER", "member@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.MEMBER))); + createUser(new UserEntity("MEMBER_1", "member1@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.MEMBER))); + createUser(new UserEntity("EXPERT", "expert@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.EXPERT))); + createUser(new UserEntity("LIBRARIAN", "librarian@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.LIBRARIAN))); + createUser(new UserEntity("ADMIN", "admin@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.ADMIN))); + createUser(new UserEntity("DEVELOPER", "developer@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.DEVELOPER))); + + + + alreadySetup = true; + } + + @Transactional + void createUser(UserEntity userEntity) { + UserEntity user = userRepository.findByEmail(userEntity.getEmail()); + if (user == null) + userRepository.save(userEntity); + } + + @Transactional + Role createRoleIfNotFound(String name, Collection privileges) { + + Role role = roleRepository.findByName(name); + if (role == null) { + role = new Role(name); + role.setPrivileges(privileges); + roleRepository.save(role); + } + return role; + } + + @Transactional + Privilege createPrivilegeIfNotFound(String name) { + + Privilege privilege = privilegeRepository.findByName(name); + if (privilege == null) { + privilege = new Privilege(name); + privilegeRepository.save(privilege); + } + return privilege; + } + + +} diff --git a/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java b/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java index d0885ee..1a32547 100644 --- a/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java +++ b/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java @@ -4,17 +4,15 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.patternpedia.api.entities.EntityWithURI; import com.patternpedia.api.entities.PatternLanguage; -import com.patternpedia.api.entities.candidate.rating.CandidateRating; -import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.rest.model.CandidateModel; +import com.patternpedia.api.entities.candidate.author.CandidateAuthor; +import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; -import org.hibernate.annotations.Type; import javax.persistence.*; -import javax.validation.constraints.NotNull; import java.util.*; @Entity @@ -35,10 +33,12 @@ public class Candidate extends EntityWithURI { // @NotNull private String content; - private int rating = 0; - private String version = "0.1.0"; + @JsonIgnore + @OneToMany(mappedBy = "candidate", cascade = CascadeType.ALL, orphanRemoval = true) + private List authors = new ArrayList<>(); + @JsonIgnore @OneToMany(mappedBy = "candidate", cascade = CascadeType.ALL, orphanRemoval = true) private Set userRating = new HashSet<>(); @@ -47,38 +47,22 @@ public class Candidate extends EntityWithURI { @OneToMany(mappedBy = "candidate", cascade = CascadeType.ALL, orphanRemoval = true) private List comments = new ArrayList<>(); - public Candidate (CandidateModel candidateModel) { - this.setId(candidateModel.getId()); - this.setUri(candidateModel.getUri()); - this.setName(candidateModel.getName()); - this.setIconUrl(candidateModel.getIconUrl()); - //patternLanguage - this.setContent(candidateModel.getContent()); - this.setVersion(candidateModel.getVersion()); - } - - - public void addComment(CandidateComment comment, UserEntity user) { - comments.add(comment); - comment.setCandidate(this); - comment.setUser(user); - } - - public void updateComment(CandidateComment updateComment) { - ListIterator commentIterator = comments.listIterator(); - while (commentIterator.hasNext()) { - CandidateComment next = commentIterator.next(); - if (next.getId().equals(updateComment.getId())) { - commentIterator.set(updateComment); - break; - } - } + public Candidate (CandidateModelRequest candidateModelRequest) { +// this.setId(candidateModel.getId()); + this.setUri(candidateModelRequest.getUri()); + this.setName(candidateModelRequest.getName()); + this.setIconUrl(candidateModelRequest.getIconUrl()); + this.setContent(candidateModelRequest.getContent()); + this.setVersion(candidateModelRequest.getVersion()); } - public void removeComment(CandidateComment comment) { - comments.remove(comment); - comment.setCandidate(null); - comment.setUser(null); + public void updateCandidate(CandidateModelRequest candidateModelRequest) { + this.setId(candidateModelRequest.getId()); + this.setUri(candidateModelRequest.getUri()); + this.setName(candidateModelRequest.getName()); + this.setIconUrl(candidateModelRequest.getIconUrl()); + this.setContent(candidateModelRequest.getContent()); + this.setVersion(candidateModelRequest.getVersion()); } public String toString() { diff --git a/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateRating.java b/src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java similarity index 76% rename from src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateRating.java rename to src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java index 2291b28..9077be9 100644 --- a/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateRating.java +++ b/src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java @@ -1,9 +1,6 @@ -package com.patternpedia.api.entities.candidate.rating; +package com.patternpedia.api.entities.candidate; -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.issue.rating.IssueRating; -import com.patternpedia.api.entities.issue.rating.IssueRatingKey; +import com.patternpedia.api.entities.shared.CompositeKey; import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -22,10 +19,10 @@ public class CandidateRating { @EmbeddedId @EqualsAndHashCode.Include - private CandidateRatingKey id; + private CompositeKey id; @ManyToOne - @MapsId("candidateId") + @MapsId("entityId") @EqualsAndHashCode.Include private Candidate candidate; @@ -39,7 +36,12 @@ public class CandidateRating { public CandidateRating(Candidate candidate, UserEntity user) { this.candidate = candidate; this.user = user; - this.id = new CandidateRatingKey(candidate.getId(), user.getId()); + this.id = new CompositeKey(candidate.getId(), user.getId()); + } + + public CandidateRating(Candidate candidate, UserEntity user, int rating) { + this(candidate, user); + this.rating = rating; } @Override diff --git a/src/main/java/com/patternpedia/api/entities/candidate/author/CandidateAuthor.java b/src/main/java/com/patternpedia/api/entities/candidate/author/CandidateAuthor.java new file mode 100644 index 0000000..24e989b --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/candidate/author/CandidateAuthor.java @@ -0,0 +1,47 @@ +package com.patternpedia.api.entities.candidate.author; + +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.shared.CompositeKey; +import com.patternpedia.api.entities.user.UserEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; + +@Entity +@Data +@NoArgsConstructor +public class CandidateAuthor { + + @EmbeddedId + @EqualsAndHashCode.Include + private CompositeKey id; + + @ManyToOne + @MapsId("entityId") + @EqualsAndHashCode.Include + private Candidate candidate; + + @ManyToOne + @MapsId("userId") + @EqualsAndHashCode.Include + private UserEntity user; + + private String role; + + public CandidateAuthor(Candidate candidate, UserEntity user) { + this.candidate = candidate; + this.user = user; + this.id = new CompositeKey(candidate.getId(), user.getId()); + } + + public CandidateAuthor(Candidate candidate, UserEntity user, String role) { + this(candidate, user); + this.role = role; + + } +} diff --git a/src/main/java/com/patternpedia/api/entities/candidate/CandidateComment.java b/src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateComment.java similarity index 70% rename from src/main/java/com/patternpedia/api/entities/candidate/CandidateComment.java rename to src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateComment.java index 47b8de0..245ec4c 100644 --- a/src/main/java/com/patternpedia/api/entities/candidate/CandidateComment.java +++ b/src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateComment.java @@ -1,8 +1,9 @@ -package com.patternpedia.api.entities.candidate; +package com.patternpedia.api.entities.candidate.comment; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.patternpedia.api.entities.candidate.rating.CandidateCommentRating; +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; import com.patternpedia.api.entities.shared.Comment; import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; @@ -35,7 +36,13 @@ public class CandidateComment extends Comment implements Serializable { @OneToMany(mappedBy = "candidateComment", cascade = CascadeType.ALL, orphanRemoval = true) private Set userRating = new HashSet<>(); - public CandidateComment(String text) { + public CandidateComment(String text, Candidate candidate, UserEntity user) { super(text); + this.candidate = candidate; + this.user = user; + } + + public void updateComment(String text) { + this.setText(text); } } diff --git a/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateCommentRating.java b/src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateCommentRating.java similarity index 78% rename from src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateCommentRating.java rename to src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateCommentRating.java index 217c35b..da87da4 100644 --- a/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateCommentRating.java +++ b/src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateCommentRating.java @@ -1,7 +1,6 @@ -package com.patternpedia.api.entities.candidate.rating; +package com.patternpedia.api.entities.candidate.comment; -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.CandidateComment; +import com.patternpedia.api.entities.shared.CompositeKey; import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -20,10 +19,10 @@ public class CandidateCommentRating { @EmbeddedId @EqualsAndHashCode.Include - private CandidateCommentRatingKey id; + private CompositeKey id; @ManyToOne - @MapsId("candidateCommentId") + @MapsId("entityId") @EqualsAndHashCode.Include private CandidateComment candidateComment; @@ -37,7 +36,12 @@ public class CandidateCommentRating { public CandidateCommentRating(CandidateComment candidateComment, UserEntity user) { this.candidateComment = candidateComment; this.user = user; - this.id = new CandidateCommentRatingKey(candidateComment.getId(), user.getId()); + this.id = new CompositeKey(candidateComment.getId(), user.getId()); + } + + public CandidateCommentRating(CandidateComment candidateComment, UserEntity user, int rating) { + this(candidateComment, user); + this.rating = rating; } @Override diff --git a/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateCommentRatingKey.java b/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateCommentRatingKey.java deleted file mode 100644 index 1e5739f..0000000 --- a/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateCommentRatingKey.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.patternpedia.api.entities.candidate.rating; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import javax.persistence.Embeddable; -import java.io.Serializable; -import java.util.UUID; - -@Embeddable -@NoArgsConstructor -@AllArgsConstructor -@Data -@EqualsAndHashCode(callSuper = false) -public class CandidateCommentRatingKey implements Serializable { - - protected UUID candidateCommentId; - protected UUID userId; -} diff --git a/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateRatingKey.java b/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateRatingKey.java deleted file mode 100644 index 704cc5f..0000000 --- a/src/main/java/com/patternpedia/api/entities/candidate/rating/CandidateRatingKey.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.patternpedia.api.entities.candidate.rating; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import javax.persistence.Embeddable; -import java.io.Serializable; -import java.util.UUID; - -@Embeddable -@NoArgsConstructor -@AllArgsConstructor -@Data -@EqualsAndHashCode(callSuper = false) -public class CandidateRatingKey implements Serializable { - - protected UUID candidateId; - protected UUID userId; -} diff --git a/src/main/java/com/patternpedia/api/entities/issue/Issue.java b/src/main/java/com/patternpedia/api/entities/issue/Issue.java index 4dc27d1..997dd7f 100644 --- a/src/main/java/com/patternpedia/api/entities/issue/Issue.java +++ b/src/main/java/com/patternpedia/api/entities/issue/Issue.java @@ -3,8 +3,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.patternpedia.api.entities.EntityWithURI; -import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.entities.issue.rating.IssueRating; +import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.rest.model.issue.IssueModelRequest; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -20,44 +21,36 @@ public class Issue extends EntityWithURI { private String description; - private int rating = 0; - private String version = "0.1.0"; @JsonIgnore @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true) - private Set userRating = new HashSet<>(); + private List authors = new ArrayList<>(); + + @JsonIgnore + @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true) + private List userRating = new ArrayList<>(); @JsonProperty(access = JsonProperty.Access.READ_ONLY) @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true) private List comments = new ArrayList<>(); - - public void addComment(IssueComment comment, UserEntity user) { - comments.add(comment); - comment.setIssue(this); - comment.setUser(user); - } - - public void updateComment(IssueComment updateComment) { - ListIterator commentIterator = comments.listIterator(); - while (commentIterator.hasNext()) { - IssueComment next = commentIterator.next(); - if (next.getId().equals(updateComment.getId())) { - commentIterator.set(updateComment); - break; - } - } + public Issue (IssueModelRequest issueModelRequest) { + this.setUri(issueModelRequest.getUri()); + this.setName(issueModelRequest.getName()); + this.setDescription(issueModelRequest.getDescription()); + this.setVersion(issueModelRequest.getVersion()); } - public void removeComment(IssueComment comment) { - comments.remove(comment); - comment.setIssue(null); - comment.setUser(null); + public void updateIssue(IssueModelRequest issueModelRequest) { + this.setUri(issueModelRequest.getUri()); + this.setName(issueModelRequest.getName()); + this.setDescription(issueModelRequest.getDescription()); + this.setVersion(issueModelRequest.getVersion()); } public String toString() { - return this.getId().toString() + this.getDescription(); + return this.getId().toString() + this.getDescription() + this.getComments().toString(); } } diff --git a/src/main/java/com/patternpedia/api/entities/issue/rating/IssueRating.java b/src/main/java/com/patternpedia/api/entities/issue/IssueRating.java similarity index 63% rename from src/main/java/com/patternpedia/api/entities/issue/rating/IssueRating.java rename to src/main/java/com/patternpedia/api/entities/issue/IssueRating.java index ab8a136..e760547 100644 --- a/src/main/java/com/patternpedia/api/entities/issue/rating/IssueRating.java +++ b/src/main/java/com/patternpedia/api/entities/issue/IssueRating.java @@ -1,6 +1,6 @@ -package com.patternpedia.api.entities.issue.rating; +package com.patternpedia.api.entities.issue; -import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.shared.CompositeKey; import com.patternpedia.api.entities.user.UserEntity; import lombok.*; @@ -14,10 +14,10 @@ public class IssueRating { @EmbeddedId @EqualsAndHashCode.Include - private IssueRatingKey id; + private CompositeKey id; @ManyToOne - @MapsId("issueId") + @MapsId("entityId") @EqualsAndHashCode.Include private Issue issue; @@ -31,7 +31,16 @@ public class IssueRating { public IssueRating(Issue issue, UserEntity user) { this.issue = issue; this.user = user; - this.id = new IssueRatingKey(issue.getId(), user.getId()); + this.id = new CompositeKey(issue.getId(), user.getId()); + } + + public IssueRating(Issue issue, UserEntity user, int rating) { + this(issue, user); + this.rating = rating; + } + + public void update(int rating) { + this.rating = rating; } @Override @@ -44,9 +53,8 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof IssueRating)) return false; IssueRating that = (IssueRating) o; - return Objects.equals(issue.getName(), that.issue.getName()) && - Objects.equals(user.getName(), that.user.getName()) && - Objects.equals(rating, that.rating); + return Objects.equals(issue.getId(), that.issue.getId()) && + Objects.equals(user.getId(), that.user.getId()); } @Override diff --git a/src/main/java/com/patternpedia/api/entities/issue/author/IssueAuthor.java b/src/main/java/com/patternpedia/api/entities/issue/author/IssueAuthor.java new file mode 100644 index 0000000..1c7d2c2 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/issue/author/IssueAuthor.java @@ -0,0 +1,46 @@ +package com.patternpedia.api.entities.issue.author; + +import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.shared.CompositeKey; +import com.patternpedia.api.entities.user.UserEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; + +@Entity +@Data +@NoArgsConstructor +public class IssueAuthor { + + @EmbeddedId + @EqualsAndHashCode.Include + private CompositeKey id; + + @ManyToOne + @MapsId("entityId") + @EqualsAndHashCode.Include + private Issue issue; + + @ManyToOne + @MapsId("userId") + @EqualsAndHashCode.Include + private UserEntity user; + + private String role; + + public IssueAuthor(Issue issue, UserEntity user) { + this.issue = issue; + this.user = user; + this.id = new CompositeKey(issue.getId(), user.getId()); + } + + public IssueAuthor(Issue issue, UserEntity user, String role) { + this(issue, user); + this.role = role; + } +} diff --git a/src/main/java/com/patternpedia/api/entities/issue/IssueComment.java b/src/main/java/com/patternpedia/api/entities/issue/comment/IssueComment.java similarity index 65% rename from src/main/java/com/patternpedia/api/entities/issue/IssueComment.java rename to src/main/java/com/patternpedia/api/entities/issue/comment/IssueComment.java index 6e017b1..b4d17e8 100644 --- a/src/main/java/com/patternpedia/api/entities/issue/IssueComment.java +++ b/src/main/java/com/patternpedia/api/entities/issue/comment/IssueComment.java @@ -1,8 +1,8 @@ -package com.patternpedia.api.entities.issue; +package com.patternpedia.api.entities.issue.comment; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.patternpedia.api.entities.issue.rating.IssueCommentRating; +import com.patternpedia.api.entities.issue.Issue; import com.patternpedia.api.entities.shared.Comment; import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; @@ -12,15 +12,12 @@ import javax.persistence.*; import java.io.Serializable; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; +import java.util.*; @Entity @Data @NoArgsConstructor -@EqualsAndHashCode(callSuper=false) +@EqualsAndHashCode(callSuper = false) public class IssueComment extends Comment implements Serializable { @JsonIgnore @@ -35,9 +32,15 @@ public class IssueComment extends Comment implements Serializable { @JsonIgnore @OneToMany(mappedBy = "issueComment", cascade = CascadeType.ALL, orphanRemoval = true) - private Set userRating = new HashSet<>(); + private List userRating = new ArrayList<>(); - public IssueComment(String text) { + public IssueComment(String text, Issue issue, UserEntity user) { super(text); + this.issue = issue; + this.user = user; + } + + public void updateComment(String text) { + this.setText(text); } } diff --git a/src/main/java/com/patternpedia/api/entities/issue/rating/IssueCommentRating.java b/src/main/java/com/patternpedia/api/entities/issue/comment/IssueCommentRating.java similarity index 78% rename from src/main/java/com/patternpedia/api/entities/issue/rating/IssueCommentRating.java rename to src/main/java/com/patternpedia/api/entities/issue/comment/IssueCommentRating.java index 5df313a..bef52fd 100644 --- a/src/main/java/com/patternpedia/api/entities/issue/rating/IssueCommentRating.java +++ b/src/main/java/com/patternpedia/api/entities/issue/comment/IssueCommentRating.java @@ -1,6 +1,6 @@ -package com.patternpedia.api.entities.issue.rating; +package com.patternpedia.api.entities.issue.comment; -import com.patternpedia.api.entities.issue.IssueComment; +import com.patternpedia.api.entities.shared.CompositeKey; import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -19,10 +19,10 @@ public class IssueCommentRating { @EmbeddedId @EqualsAndHashCode.Include - private IssueCommentRatingKey id; + private CompositeKey id; @ManyToOne - @MapsId("issueCommentId") + @MapsId("entityId") @EqualsAndHashCode.Include private IssueComment issueComment; @@ -36,7 +36,12 @@ public class IssueCommentRating { public IssueCommentRating(IssueComment issueComment, UserEntity user) { this.issueComment = issueComment; this.user = user; - this.id = new IssueCommentRatingKey(issueComment.getId(), user.getId()); + this.id = new CompositeKey(issueComment.getId(), user.getId()); + } + + public IssueCommentRating(IssueComment issueComment, UserEntity user, int rating) { + this(issueComment, user); + this.rating = rating; } @Override diff --git a/src/main/java/com/patternpedia/api/entities/issue/rating/IssueCommentRatingKey.java b/src/main/java/com/patternpedia/api/entities/issue/rating/IssueCommentRatingKey.java deleted file mode 100644 index 611d1c8..0000000 --- a/src/main/java/com/patternpedia/api/entities/issue/rating/IssueCommentRatingKey.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.patternpedia.api.entities.issue.rating; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import javax.persistence.Embeddable; -import java.io.Serializable; -import java.util.UUID; - -@Embeddable -@NoArgsConstructor -@AllArgsConstructor -@Data -@EqualsAndHashCode(callSuper = false) -public class IssueCommentRatingKey implements Serializable { - - protected UUID issueCommentId; - protected UUID userId; -} diff --git a/src/main/java/com/patternpedia/api/entities/shared/AuthorConstant.java b/src/main/java/com/patternpedia/api/entities/shared/AuthorConstant.java new file mode 100644 index 0000000..54ccad6 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/shared/AuthorConstant.java @@ -0,0 +1,7 @@ +package com.patternpedia.api.entities.shared; + +public interface AuthorConstant { + String OWNER = "OWNER"; + String MAINTAINER = "MAINTAINER"; + String MEMBER = "MEMBER"; +} diff --git a/src/main/java/com/patternpedia/api/entities/shared/Comment.java b/src/main/java/com/patternpedia/api/entities/shared/Comment.java index fc7856d..22e5ba8 100644 --- a/src/main/java/com/patternpedia/api/entities/shared/Comment.java +++ b/src/main/java/com/patternpedia/api/entities/shared/Comment.java @@ -1,6 +1,5 @@ package com.patternpedia.api.entities.shared; -import com.patternpedia.api.entities.issue.IssueComment; import lombok.Data; import lombok.NoArgsConstructor; @@ -21,8 +20,6 @@ public abstract class Comment { private String text; - private int rating = 0; - public Comment(String text) { this.text = text; } @@ -43,6 +40,6 @@ public int hashCode() { @Override public String toString() { - return "Comment: " + this.text + this.id.toString() + this.rating; + return "Comment: " + this.text + this.id.toString(); } } diff --git a/src/main/java/com/patternpedia/api/entities/issue/rating/IssueRatingKey.java b/src/main/java/com/patternpedia/api/entities/shared/CompositeKey.java similarity index 71% rename from src/main/java/com/patternpedia/api/entities/issue/rating/IssueRatingKey.java rename to src/main/java/com/patternpedia/api/entities/shared/CompositeKey.java index 52db854..0e13b02 100644 --- a/src/main/java/com/patternpedia/api/entities/issue/rating/IssueRatingKey.java +++ b/src/main/java/com/patternpedia/api/entities/shared/CompositeKey.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.entities.issue.rating; +package com.patternpedia.api.entities.shared; import lombok.AllArgsConstructor; import lombok.Data; @@ -14,8 +14,8 @@ @AllArgsConstructor @Data @EqualsAndHashCode(callSuper = false) -public class IssueRatingKey implements Serializable { +public class CompositeKey implements Serializable { - protected UUID issueId; + protected UUID entityId; protected UUID userId; } diff --git a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java b/src/main/java/com/patternpedia/api/entities/user/UserEntity.java index 47c7845..0cd8968 100644 --- a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java +++ b/src/main/java/com/patternpedia/api/entities/user/UserEntity.java @@ -2,15 +2,19 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.patternpedia.api.entities.candidate.CandidateComment; -import com.patternpedia.api.entities.candidate.rating.CandidateRating; -import com.patternpedia.api.entities.issue.IssueComment; -import com.patternpedia.api.entities.issue.rating.IssueRating; +import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.entities.candidate.author.CandidateAuthor; +import com.patternpedia.api.entities.candidate.CandidateRating; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.user.role.Role; +import com.patternpedia.api.rest.model.user.UserModel; import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.ToString; import org.hibernate.annotations.NaturalId; -import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import javax.persistence.*; @@ -20,7 +24,7 @@ @Entity @Data @NoArgsConstructor -@TypeDef(name = "pgsql_enum", typeClass = PostgreSQLEnumType.class) +//@NamedQuery(name = "UserEntity.findAll", query="select u from UserEntity u order by u.role.name") public class UserEntity implements Serializable{ /** User fields*/ @@ -28,10 +32,10 @@ public class UserEntity implements Serializable{ @GeneratedValue(generator = "pg-uuid") private UUID id; - @Enumerated(EnumType.STRING) - @ElementCollection - @Type(type = "pgsql_enum") - private List roles = new ArrayList<>(Arrays.asList(UserRole.MEMBER)); + @JsonIgnore + @ToString.Exclude + @ManyToOne() + private Role role; @NaturalId(mutable = true) @Column(nullable = false, unique = true) @@ -43,6 +47,10 @@ public class UserEntity implements Serializable{ private String password; /** Issue fields*/ + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private Set issues = new HashSet<>(); + @JsonIgnore @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private Set issueRatings = new HashSet<>(); @@ -52,6 +60,10 @@ public class UserEntity implements Serializable{ private List issueComments = new ArrayList<>(); /** Candidate fields*/ + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private Set candidates = new HashSet<>(); + @JsonIgnore @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private Set candidateRatings = new HashSet<>(); @@ -69,17 +81,23 @@ public class UserEntity implements Serializable{ // @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) // private List candidateComments = new ArrayList<>(); - public UserEntity(String name, String email, String password) { - this.name = name; - this.email = email; + public UserEntity(UserModel userModel, String password) { + this.id = userModel.getId(); + this.name = userModel.getName(); + this.email = userModel.getEmail(); this.password = password; } - public UserEntity(String name, String email, String password, List roles) { + public UserEntity(String name, String email, String password, Role role) { this.name = name; this.email = email; this.password = password; - this.roles = roles; + this.role = role; + } + + public void updateUserEntity(UserModel userModel) { + this.setName(userModel.getName()); + this.setEmail(userModel.getEmail()); } @Override diff --git a/src/main/java/com/patternpedia/api/entities/user/UserRole.java b/src/main/java/com/patternpedia/api/entities/user/UserRole.java deleted file mode 100644 index 11498f0..0000000 --- a/src/main/java/com/patternpedia/api/entities/user/UserRole.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.patternpedia.api.entities.user; - -public enum UserRole { - MEMBER, - EXPERT, - AUTHOR, - LIBRARIAN, - ADMIN -} diff --git a/src/main/java/com/patternpedia/api/entities/user/role/Privilege.java b/src/main/java/com/patternpedia/api/entities/user/role/Privilege.java new file mode 100644 index 0000000..79607b8 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/user/role/Privilege.java @@ -0,0 +1,46 @@ +package com.patternpedia.api.entities.user.role; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.Collection; +import java.util.UUID; + +@Entity +@Data +@NoArgsConstructor +public class Privilege { + + @Id + @GeneratedValue(generator = "pg-uuid") + private UUID id; + + @Column(unique = true) + private String name; + + @ManyToMany(mappedBy = "privileges") + private Collection roles; + + public Privilege(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Privilege)) return false; + Privilege that = (Privilege) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String toString() { + return "Privileges: " + this.name; + } +} diff --git a/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java b/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java new file mode 100644 index 0000000..1d86fc0 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java @@ -0,0 +1,24 @@ +package com.patternpedia.api.entities.user.role; + +public interface PrivilegeConstant { + /** USER */ + String READ_USER_ALL = "READ_USER_ALL"; + String READ_USER = "READ_USER"; + String CREATE_USER = "CREATE_USER"; + String UPDATE_USER = "UPDATE_USER"; + String DELETE_USER = "DELETE_USER"; + /** ISSUE */ + String READ_ISSUE = "READ_ISSUE"; + String CREATE_ISSUE = "CREATE_ISSUE"; + String UPDATE_ISSUE = "UPDATE_ISSUE"; + String DELETE_ISSUE = "DELETE_ISSUE"; + /** CANDIDATE */ + String READ_CANDIDATE = "READ_CANDIDATE"; + String CREATE_CANDIDATE = "CREATE_CANDIDATE"; + String UPDATE_CANDIDATE = "UPDATE_CANDIDATE"; + String DELETE_CANDIDATE = "DELETE_CANDIDATE"; + /** ROLE */ + String UPDATE_ROLE = "UPDATE_ROLE"; + /** DEVELOPER */ + String DEVELOPER = "DEVELOPER"; +} diff --git a/src/main/java/com/patternpedia/api/entities/user/role/Role.java b/src/main/java/com/patternpedia/api/entities/user/role/Role.java new file mode 100644 index 0000000..d621aff --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/user/role/Role.java @@ -0,0 +1,34 @@ +package com.patternpedia.api.entities.user.role; + +import com.patternpedia.api.entities.user.UserEntity; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.Collection; +import java.util.UUID; + +@Entity +@Data +@NoArgsConstructor +public class Role { + + @Id + @GeneratedValue(generator = "pg-uuid") + private UUID id; + + @Column(unique = true) + private String name; + + @OneToMany(mappedBy = "role", cascade = CascadeType.ALL, orphanRemoval = true) + private Collection users; + + @ManyToMany(cascade = CascadeType.ALL) + private Collection privileges; + + public Role(String name) { + this.name = name; + } + + +} diff --git a/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java b/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java new file mode 100644 index 0000000..5b7e4d5 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java @@ -0,0 +1,10 @@ +package com.patternpedia.api.entities.user.role; + +public interface RoleConstant { + String MEMBER = "MEMBER"; +// String AUTHOR = "AUTHOR"; + String EXPERT = "EXPERT"; + String LIBRARIAN = "LIBRARIAN"; + String ADMIN = "ADMIN"; + String DEVELOPER = "DEVELOPER"; +} diff --git a/src/main/java/com/patternpedia/api/exception/CandidateNotFoundException.java b/src/main/java/com/patternpedia/api/exception/CandidateNotFoundException.java deleted file mode 100644 index 608ff7b..0000000 --- a/src/main/java/com/patternpedia/api/exception/CandidateNotFoundException.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.patternpedia.api.exception; - -import lombok.NoArgsConstructor; -import org.springframework.data.rest.webmvc.ResourceNotFoundException; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -import java.util.UUID; - -@NoArgsConstructor -@ResponseStatus(HttpStatus.NOT_FOUND) -public class CandidateNotFoundException extends ResourceNotFoundException { - - public CandidateNotFoundException(String message) { - super(message); - } - - public CandidateNotFoundException(UUID candidateId) { - super(String.format("Candidate \"%s\" not found!", candidateId)); - } -} diff --git a/src/main/java/com/patternpedia/api/exception/CommentNotFoundException.java b/src/main/java/com/patternpedia/api/exception/CommentNotFoundException.java deleted file mode 100644 index 633f555..0000000 --- a/src/main/java/com/patternpedia/api/exception/CommentNotFoundException.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.patternpedia.api.exception; - -import lombok.NoArgsConstructor; -import org.springframework.data.rest.webmvc.ResourceNotFoundException; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -import java.util.UUID; - -@NoArgsConstructor -@ResponseStatus(HttpStatus.NOT_FOUND) -public class CommentNotFoundException extends ResourceNotFoundException { - - public CommentNotFoundException(String message) { - super(message); - } - - public CommentNotFoundException(UUID commentId) { - super(String.format("Comment \"%s\" not found!", commentId)); - } -} diff --git a/src/main/java/com/patternpedia/api/exception/NullIssueException.java b/src/main/java/com/patternpedia/api/exception/NullIssueException.java deleted file mode 100644 index aae0c05..0000000 --- a/src/main/java/com/patternpedia/api/exception/NullIssueException.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.patternpedia.api.exception; - -import lombok.NoArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@NoArgsConstructor -@ResponseStatus(HttpStatus.NOT_FOUND) -public class NullIssueException extends RuntimeException { - public NullIssueException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/src/main/java/com/patternpedia/api/exception/NullRoleException.java b/src/main/java/com/patternpedia/api/exception/NullRoleException.java new file mode 100644 index 0000000..a962484 --- /dev/null +++ b/src/main/java/com/patternpedia/api/exception/NullRoleException.java @@ -0,0 +1,12 @@ +package com.patternpedia.api.exception; + +public class NullRoleException extends RuntimeException { + + public NullRoleException() { + super("Role is null"); + } + + public NullRoleException(String message) { + super(message); + } +} diff --git a/src/main/java/com/patternpedia/api/exception/IssueNotFoundException.java b/src/main/java/com/patternpedia/api/exception/RoleNotFoundException.java similarity index 60% rename from src/main/java/com/patternpedia/api/exception/IssueNotFoundException.java rename to src/main/java/com/patternpedia/api/exception/RoleNotFoundException.java index 124bff1..b2c497c 100644 --- a/src/main/java/com/patternpedia/api/exception/IssueNotFoundException.java +++ b/src/main/java/com/patternpedia/api/exception/RoleNotFoundException.java @@ -9,13 +9,13 @@ @NoArgsConstructor @ResponseStatus(HttpStatus.NOT_FOUND) -public class IssueNotFoundException extends ResourceNotFoundException { +public class RoleNotFoundException extends ResourceNotFoundException { - public IssueNotFoundException(String message) { + public RoleNotFoundException(String message) { super(message); } - public IssueNotFoundException(UUID issueId) { - super(String.format("Issue \"%s\" not found!", issueId)); + public RoleNotFoundException(UUID roleId) { + super(String.format("Role \"%s\" not found!", roleId)); } } diff --git a/src/main/java/com/patternpedia/api/exception/UserAlreadyVotedException.java b/src/main/java/com/patternpedia/api/exception/UserAlreadyVotedException.java deleted file mode 100644 index 3d9d896..0000000 --- a/src/main/java/com/patternpedia/api/exception/UserAlreadyVotedException.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.patternpedia.api.exception; - -import com.patternpedia.api.entities.PatternView; -import lombok.NoArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -import java.util.UUID; - -@NoArgsConstructor -@ResponseStatus(HttpStatus.NOT_FOUND) -public class UserAlreadyVotedException extends RuntimeException { - - public UserAlreadyVotedException(String message) { - super(message); - } - - public UserAlreadyVotedException(UUID patternViewId) { - super(String.format("PatternView \"%s\" not found!", patternViewId)); - } - - public UserAlreadyVotedException(PatternView patternView) { - super(String.format("PatternView \"%s\" not found!", patternView.getId())); - } -} diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateAuthorRepository.java b/src/main/java/com/patternpedia/api/repositories/CandidateAuthorRepository.java new file mode 100644 index 0000000..ce4b27c --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/CandidateAuthorRepository.java @@ -0,0 +1,11 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.candidate.author.CandidateAuthor; +import com.patternpedia.api.entities.shared.CompositeKey; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CandidateAuthorRepository extends JpaRepository { + + boolean existsByIdAndRole(CompositeKey compositeKey, String role); + +} \ No newline at end of file diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateCommentRatingRepository.java b/src/main/java/com/patternpedia/api/repositories/CandidateCommentRatingRepository.java index c4c3f48..f56ee74 100644 --- a/src/main/java/com/patternpedia/api/repositories/CandidateCommentRatingRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/CandidateCommentRatingRepository.java @@ -1,17 +1,12 @@ package com.patternpedia.api.repositories; -import com.patternpedia.api.entities.candidate.CandidateComment; -import com.patternpedia.api.entities.candidate.rating.CandidateCommentRating; -import com.patternpedia.api.entities.candidate.rating.CandidateCommentRatingKey; -import com.patternpedia.api.entities.issue.IssueComment; -import com.patternpedia.api.entities.issue.rating.IssueCommentRating; -import com.patternpedia.api.entities.issue.rating.IssueCommentRatingKey; -import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.shared.CompositeKey; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.rest.core.annotation.RepositoryRestResource; @RepositoryRestResource(exported = false) -public interface CandidateCommentRatingRepository extends JpaRepository { +public interface CandidateCommentRatingRepository extends JpaRepository { - CandidateCommentRating findByCandidateCommentAndUser(CandidateComment candidateComment, UserEntity user); + boolean existsByIdAndRating(CompositeKey compositeKey, int rating); } diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateCommentRepository.java b/src/main/java/com/patternpedia/api/repositories/CandidateCommentRepository.java index 3c46e9c..96e4786 100644 --- a/src/main/java/com/patternpedia/api/repositories/CandidateCommentRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/CandidateCommentRepository.java @@ -1,6 +1,6 @@ package com.patternpedia.api.repositories; -import com.patternpedia.api.entities.candidate.CandidateComment; +import com.patternpedia.api.entities.candidate.comment.CandidateComment; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java b/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java index c692818..438499b 100644 --- a/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java @@ -1,18 +1,12 @@ package com.patternpedia.api.repositories; -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.rating.CandidateRating; -import com.patternpedia.api.entities.candidate.rating.CandidateRatingKey; -import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.entities.candidate.CandidateRating; +import com.patternpedia.api.entities.shared.CompositeKey; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; -import java.util.List; +@RepositoryRestResource(exported = false) +public interface CandidateRatingRepository extends JpaRepository { -public interface CandidateRatingRepository extends JpaRepository { - - List findAllByCandidate(Candidate candidate); - - List findAllByUser(UserEntity user); - - CandidateRating findByCandidateAndUser(Candidate candidate, UserEntity user); + boolean existsByIdAndRating(CompositeKey compositeKey, int rating); } diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateRepository.java b/src/main/java/com/patternpedia/api/repositories/CandidateRepository.java index cc3f326..6a3476b 100644 --- a/src/main/java/com/patternpedia/api/repositories/CandidateRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/CandidateRepository.java @@ -9,8 +9,8 @@ public interface CandidateRepository extends JpaRepository { public Optional findByUri(String uri); - public boolean existsByUri(String uri); + public boolean existsByName(String name); } diff --git a/src/main/java/com/patternpedia/api/repositories/IssueAuthorRepository.java b/src/main/java/com/patternpedia/api/repositories/IssueAuthorRepository.java new file mode 100644 index 0000000..444668b --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/IssueAuthorRepository.java @@ -0,0 +1,11 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.shared.CompositeKey; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface IssueAuthorRepository extends JpaRepository { + + boolean existsByIdAndRole(CompositeKey compositeKey, String role); + +} diff --git a/src/main/java/com/patternpedia/api/repositories/IssueCommentRatingRepository.java b/src/main/java/com/patternpedia/api/repositories/IssueCommentRatingRepository.java index 2f3297e..252aaed 100644 --- a/src/main/java/com/patternpedia/api/repositories/IssueCommentRatingRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/IssueCommentRatingRepository.java @@ -1,15 +1,17 @@ package com.patternpedia.api.repositories; -import com.patternpedia.api.entities.issue.IssueComment; -import com.patternpedia.api.entities.issue.rating.IssueCommentRating; -import com.patternpedia.api.entities.issue.rating.IssueCommentRatingKey; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.shared.CompositeKey; import com.patternpedia.api.entities.user.UserEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.rest.core.annotation.RepositoryRestResource; @RepositoryRestResource(exported = false) -public interface IssueCommentRatingRepository extends JpaRepository { +public interface IssueCommentRatingRepository extends JpaRepository { IssueCommentRating findByIssueCommentAndUser(IssueComment issueComment, UserEntity user); + boolean existsByIdAndRating(CompositeKey compositeKey, int rating); + } diff --git a/src/main/java/com/patternpedia/api/repositories/IssueCommentRepository.java b/src/main/java/com/patternpedia/api/repositories/IssueCommentRepository.java index ce55c92..42c3711 100644 --- a/src/main/java/com/patternpedia/api/repositories/IssueCommentRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/IssueCommentRepository.java @@ -1,6 +1,6 @@ package com.patternpedia.api.repositories; -import com.patternpedia.api.entities.issue.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueComment; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; diff --git a/src/main/java/com/patternpedia/api/repositories/IssueRatingRepository.java b/src/main/java/com/patternpedia/api/repositories/IssueRatingRepository.java index 0184dbc..4c90d3f 100644 --- a/src/main/java/com/patternpedia/api/repositories/IssueRatingRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/IssueRatingRepository.java @@ -1,20 +1,16 @@ package com.patternpedia.api.repositories; import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.entities.issue.rating.IssueRatingKey; -import com.patternpedia.api.entities.issue.rating.IssueRating; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.shared.CompositeKey; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.rest.core.annotation.RepositoryRestResource; -import java.util.List; +import java.util.Collection; @RepositoryRestResource(exported = false) -public interface IssueRatingRepository extends JpaRepository { +public interface IssueRatingRepository extends JpaRepository { - List findAllByIssue(Issue issue); - - List findAllByUser(UserEntity user); - - IssueRating findByIssueAndUser(Issue issue, UserEntity user); + boolean existsByIdAndRating(CompositeKey compositeKey, int rating); + Collection findAllByIssue(Issue issue); } diff --git a/src/main/java/com/patternpedia/api/repositories/IssueRepository.java b/src/main/java/com/patternpedia/api/repositories/IssueRepository.java index b69b55f..8d13658 100644 --- a/src/main/java/com/patternpedia/api/repositories/IssueRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/IssueRepository.java @@ -9,8 +9,6 @@ public interface IssueRepository extends JpaRepository { public Optional findByUri(String uri); - public boolean existsByUri(String uri); - - + public boolean existsByName(String name); } diff --git a/src/main/java/com/patternpedia/api/repositories/PrivilegeRepository.java b/src/main/java/com/patternpedia/api/repositories/PrivilegeRepository.java new file mode 100644 index 0000000..f079f79 --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/PrivilegeRepository.java @@ -0,0 +1,11 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.user.role.Privilege; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface PrivilegeRepository extends JpaRepository { + + Privilege findByName(String name); +} diff --git a/src/main/java/com/patternpedia/api/repositories/RoleRepository.java b/src/main/java/com/patternpedia/api/repositories/RoleRepository.java new file mode 100644 index 0000000..cd656d1 --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/RoleRepository.java @@ -0,0 +1,12 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.user.role.Role; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface RoleRepository extends JpaRepository { + + boolean existsByName(String name); + Role findByName(String name); +} diff --git a/src/main/java/com/patternpedia/api/repositories/UserRepository.java b/src/main/java/com/patternpedia/api/repositories/UserRepository.java index 3627447..3a16577 100644 --- a/src/main/java/com/patternpedia/api/repositories/UserRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/UserRepository.java @@ -1,10 +1,11 @@ package com.patternpedia.api.repositories; import com.patternpedia.api.entities.user.UserEntity; +import org.apache.catalina.User; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; public interface UserRepository extends JpaRepository { - + UserEntity findByEmail(String email); } diff --git a/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java b/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java new file mode 100644 index 0000000..c3b7db3 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java @@ -0,0 +1,98 @@ +package com.patternpedia.api.rest.controller; + +import com.patternpedia.api.entities.shared.AuthorConstant; +import com.patternpedia.api.rest.model.candidate.CandidateModel; +import com.patternpedia.api.rest.model.issue.IssueModel; +import com.patternpedia.api.rest.model.shared.AuthorModel; +import com.patternpedia.api.rest.model.shared.AuthorModelRequest; +import com.patternpedia.api.rest.model.user.UserModel; +import com.patternpedia.api.service.AuthorService; +import com.patternpedia.api.service.UserService; +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@RestController +@RequestMapping(value = "/authors", produces = "application/hal+json") +public class AuthorController { + + private AuthorService authorService; + private UserService userService; + + public AuthorController( + AuthorService authorService, + UserService userService + ) { + this.authorService = authorService; + this.userService = userService; + } + + /** + * GET Methods + */ + @GetMapping(value = "") +// @PreAuthorize(value = "hasAuthority('ADMIN')") + CollectionModel> getAll() { + List> authors = this.userService.getAllUsers() + .stream() + .map(user -> new EntityModel<>(new AuthorModel(user))) + .collect(Collectors.toList()); + return new CollectionModel<>(authors); + } + + @GetMapping(value = "/roles") +// @PreAuthorize(value = "hasAuthority('ADMIN')") + String[] getAllRoles() { + return new String[]{AuthorConstant.MEMBER, AuthorConstant.MAINTAINER, AuthorConstant.OWNER}; + } + + /** + * CREATE Methods + */ + @PostMapping(value = "/{userId}/issues/{issueId}") + @ResponseStatus(HttpStatus.CREATED) + ResponseEntity> newIssueAuthor(@PathVariable UUID userId, @PathVariable UUID issueId, @RequestBody AuthorModelRequest authorModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new AuthorModel(this.authorService.saveIssueAuthor(userId, issueId, authorModelRequest)))); + } + + @PostMapping(value = "/{userId}/candidates/{candidateId}") + @ResponseStatus(HttpStatus.CREATED) + ResponseEntity> newCandidateAuthor(@PathVariable UUID userId, @PathVariable UUID candidateId, @RequestBody AuthorModelRequest authorModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new AuthorModel(this.authorService.saveCandidateAuthor(userId, candidateId, authorModelRequest)))); + } + + /** + * UPDATE Methods + */ + @PutMapping(value = "/{userId}/issues/{issueId}") + ResponseEntity> putIssueAuthor(@PathVariable UUID userId, @PathVariable UUID issueId, @RequestBody AuthorModelRequest authorModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new AuthorModel(this.authorService.saveIssueAuthor(userId, issueId, authorModelRequest)))); + } + + @PutMapping(value = "/{userId}/candidates/{candidateId}") + ResponseEntity> putCandidateAuthor(@PathVariable UUID userId, @PathVariable UUID candidateId, @RequestBody AuthorModelRequest authorModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new AuthorModel(this.authorService.saveCandidateAuthor(userId, candidateId, authorModelRequest)))); + } + + /** + * DELETE Methods + */ + @DeleteMapping(value = "/{userId}/issues/{issueId}") + ResponseEntity deleteIssueAuthor(@PathVariable UUID userId, @PathVariable UUID issueId) { + this.authorService.deleteIssueAuthor(userId, issueId); + return ResponseEntity.noContent().build(); + } + + @DeleteMapping(value = "/{userId}/candidates/{candidateId}") + ResponseEntity deleteCandidateAuthor(@PathVariable UUID userId, @PathVariable UUID candidateId) { + this.authorService.deleteCandidateAuthor(userId, candidateId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java b/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java index e0980f0..e6f0d25 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java @@ -1,18 +1,11 @@ package com.patternpedia.api.rest.controller; import com.fasterxml.jackson.databind.ObjectMapper; -import com.patternpedia.api.entities.PatternLanguage; -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.CandidateComment; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.rest.model.CandidateModel; -import com.patternpedia.api.rest.model.PatternLanguageModel; -import com.patternpedia.api.rest.model.PatternModel; +import com.patternpedia.api.rest.model.candidate.CandidateModel; +import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; +import com.patternpedia.api.rest.model.shared.CommentModel; import com.patternpedia.api.service.CandidateService; import com.patternpedia.api.service.PatternLanguageService; -import io.swagger.v3.core.util.Json; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.hateoas.CollectionModel; @@ -20,8 +13,10 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import java.security.Principal; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -51,59 +46,51 @@ public CandidateController( */ @GetMapping(value = "") CollectionModel> all() { - List> candidates = this.candidateService.getAllCandidates() .stream() - .map(candidate -> new EntityModel<>(CandidateModel.from(candidate))) -// getPatternViewLinks(patternView))) + .map(candidate -> new EntityModel<>(new CandidateModel(candidate))) .collect(Collectors.toList()); - return new CollectionModel<>(candidates); } @GetMapping(value = "/{candidateId}") @PreAuthorize(value = "#oauth2.hasScope('read')") - Candidate getCandidateById(@PathVariable UUID candidateId) { - return this.candidateService.getCandidateById(candidateId); + ResponseEntity> getCandidateById(@PathVariable UUID candidateId) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateById(candidateId)))); } @GetMapping(value = "/?uri={candidateUri}") - Candidate getCandidateByUri(@PathVariable String candidateUri) { - return this.candidateService.getCandidateByURI(candidateUri); + ResponseEntity> getCandidateByUri(@PathVariable String candidateUri) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateByURI(candidateUri)))); } /** * CREATE Methods */ @PostMapping(value = "") + @PreAuthorize(value = "#oauth2.hasScope('write')") @ResponseStatus(HttpStatus.CREATED) - Candidate newCandidate(@RequestBody CandidateModel candidate) { - return this.candidateService.createCandidate(candidate); + ResponseEntity> newCandidate(@RequestBody CandidateModelRequest candidateModelRequest, @AuthenticationPrincipal Principal principal) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createCandidate(candidateModelRequest, UUID.fromString(principal.getName()))))); } - @PostMapping(value = "/{candidateId}/comments/{userId}") + @PostMapping(value = "/{candidateId}/comments") @ResponseStatus(HttpStatus.CREATED) - Candidate newCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID userId, @RequestBody CandidateComment candidateComment) { - return this.candidateService.createComment(candidateId, userId, candidateComment); + ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.candidateService.createComment(candidateId, UUID.fromString(principal.getName()), commentModel)))); } /** * UPDATE Methods */ @PutMapping(value = "/{candidateId}") - Candidate putCandidate(@PathVariable UUID candidateId, @RequestBody Candidate candidate) { - logger.info(candidate.toString()); - return this.candidateService.updateCandidate(candidate); - } - - @PutMapping(value = "/{candidateId}/users/{userId}/rating/{rating}") - Candidate putCandidateRating(@PathVariable UUID candidateId, @PathVariable UUID userId, @PathVariable String rating) { - return this.candidateService.userRating(candidateId, userId, rating); + ResponseEntity> putCandidate(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CandidateModelRequest candidateModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidate(candidateId, UUID.fromString(principal.getName()), candidateModelRequest)))); } - @PutMapping(value = "/comments/{candidateCommentId}/users/{userId}/rating/{rating}") - Candidate putCandidateCommentRating(@PathVariable UUID candidateCommentId, @PathVariable UUID userId, @PathVariable String rating) { - return this.candidateService.commentUserRating(candidateCommentId, userId, rating); + @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}") + ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.candidateService.updateComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()), commentModel)))); } /** @@ -115,4 +102,10 @@ ResponseEntity deleteCandidate(@PathVariable UUID candidateId) { this.candidateService.deleteCandidate(candidateId); return ResponseEntity.noContent().build(); } + + @DeleteMapping(value = "/{candidateId}/comments/{candidateCommentId}") +// @PreAuthorize(value = "#oauth2.hasScope('de')") + ResponseEntity deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal) { + return this.candidateService.deleteComment(candidateId, candidateCommentId, UUID.fromString(principal.getName())); + } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java b/src/main/java/com/patternpedia/api/rest/controller/IssueController.java index 0e97f9a..984842a 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/IssueController.java @@ -1,18 +1,24 @@ package com.patternpedia.api.rest.controller; import com.fasterxml.jackson.databind.ObjectMapper; -import com.patternpedia.api.entities.issue.IssueComment; -import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.rest.model.issue.IssueModelRequest; +import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.issue.IssueModel; import com.patternpedia.api.service.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import java.security.Principal; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; @RestController @RequestMapping(value = "/issues", produces = "application/hal+json") @@ -38,19 +44,23 @@ public IssueController( * GET Methods */ @GetMapping(value = "") - List all() { - return this.issueService.getAllIssues(); + CollectionModel> getAll() { + List> issues = this.issueService.getAllIssues() + .stream() + .map(issue -> new EntityModel<>(new IssueModel(issue))) + .collect(Collectors.toList()); + return new CollectionModel<>(issues); } @GetMapping(value = "/{issueId}") @PreAuthorize(value = "#oauth2.hasScope('read')") - Issue getIssueById(@PathVariable UUID issueId) { - return this.issueService.getIssueById(issueId); + ResponseEntity> getIssueById(@PathVariable UUID issueId) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueById(issueId)))); } @GetMapping(value = "/?uri={issueUri}") - Issue getIssueByUri(@PathVariable String issueUri) { - return this.issueService.getIssueByURI(issueUri); + ResponseEntity> getIssueByUri(@PathVariable String issueUri) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueByURI(issueUri)))); } /** @@ -59,34 +69,28 @@ Issue getIssueByUri(@PathVariable String issueUri) { @PostMapping(value = "") @PreAuthorize(value = "#oauth2.hasScope('write')") @ResponseStatus(HttpStatus.CREATED) - Issue newIssue(@RequestBody Issue issue) { - return this.issueService.createIssue(issue); + ResponseEntity> newIssue(@RequestBody IssueModelRequest issueModelRequest, @AuthenticationPrincipal Principal principal) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createIssue(issueModelRequest, UUID.fromString(principal.getName()))))); } - @PostMapping(value = "/{issueId}/comments/{userId}") + @PostMapping(value = "/{issueId}/comments") // @PreAuthorize(value = "#oauth2.hasScope('write')") @ResponseStatus(HttpStatus.CREATED) - Issue newIssueComment(@PathVariable UUID issueId, @PathVariable UUID userId, @RequestBody IssueComment issueComment) { - return this.issueService.createComment(issueId, userId, issueComment); + ResponseEntity> newIssueComment(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); } /** * UPDATE Methods */ @PutMapping(value = "/{issueId}") - Issue putIssue(@PathVariable UUID issueId, @RequestBody Issue issue) { - logger.info(issue.toString()); - return this.issueService.updateIssue(issue); + ResponseEntity> putIssue(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody IssueModelRequest issueModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssue(issueId, UUID.fromString(principal.getName()), issueModelRequest)))); } - @PutMapping(value = "/{issueId}/users/{userId}/rating/{rating}") - Issue putIssueRating(@PathVariable UUID issueId, @PathVariable UUID userId, @PathVariable String rating) { - return this.issueService.userRating(issueId, userId, rating); - } - - @PutMapping(value = "/comments/{issueCommentId}/users/{userId}/rating/{rating}") - Issue putIssueCommentRating(@PathVariable UUID issueCommentId, @PathVariable UUID userId, @PathVariable String rating) { - return this.issueService.commentUserRating(issueCommentId, userId, rating); + @PutMapping(value = "/{issueId}/comments/{issueCommentId}") + ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.issueService.updateComment(issueId, issueCommentId, UUID.fromString(principal.getName()), commentModel)))); } /** @@ -98,4 +102,10 @@ ResponseEntity deleteIssue(@PathVariable UUID issueId) { this.issueService.deleteIssue(issueId); return ResponseEntity.noContent().build(); } + + @DeleteMapping(value = "/{issueId}/comments/{issueCommentId}") +// @PreAuthorize(value = "#oauth2.hasScope('de')") + ResponseEntity deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal) { + return this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName())); + } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/RatingController.java b/src/main/java/com/patternpedia/api/rest/controller/RatingController.java new file mode 100644 index 0000000..2225296 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/controller/RatingController.java @@ -0,0 +1,52 @@ +package com.patternpedia.api.rest.controller; + +import com.patternpedia.api.rest.model.candidate.CandidateModel; +import com.patternpedia.api.rest.model.issue.IssueModel; +import com.patternpedia.api.rest.model.shared.AuthorModelRequest; +import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.RatingModel; +import com.patternpedia.api.rest.model.shared.RatingModelRequest; +import com.patternpedia.api.service.RatingService; +import org.springframework.hateoas.EntityModel; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import java.security.Principal; +import java.util.UUID; + +@RestController +@RequestMapping(value = "/ratings", produces = "application/hal+json") +public class RatingController { + + private RatingService ratingService; + + public RatingController( + RatingService ratingService + ) { + this.ratingService = ratingService; + } + + /** + * UPDATE Methods + */ + @PutMapping(value = "/issues/{issueId}") + ResponseEntity> putIssueRating(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateIssueRating(issueId, UUID.fromString(principal.getName()), ratingModelRequest)))); + } + + @PutMapping(value = "/issues/{issueId}/comments/{issueCommentId}") + ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); + } + + @PutMapping(value = "/candidates/{candidateId}") + ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelRequest)))); + } + + @PutMapping(value = "/candidates/{candidateId}/comments/{candidateCommentId}") + ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateCandidateCommentRating(candidateId, candidateCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); + } +} diff --git a/src/main/java/com/patternpedia/api/rest/controller/UserController.java b/src/main/java/com/patternpedia/api/rest/controller/UserController.java index 8624532..ef8a878 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/UserController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/UserController.java @@ -1,22 +1,21 @@ package com.patternpedia.api.rest.controller; -import com.patternpedia.api.entities.user.UserRole; +import com.patternpedia.api.rest.model.user.*; +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.crypto.password.PasswordEncoder; import com.fasterxml.jackson.databind.ObjectMapper; -import com.patternpedia.api.entities.user.UserEntity; import com.patternpedia.api.service.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; @RestController @RequestMapping(value = "/users", produces = "application/hal+json") @@ -42,14 +41,36 @@ public UserController( * GET Methods */ @GetMapping(value = "") - @PreAuthorize(value = "hasAuthority('ADMIN')") - List all() { - return this.userService.getAllUsers(); +// @PreAuthorize(value = "hasAuthority('ADMIN')") + CollectionModel> getAll() { + List> users = this.userService.getAllUsers() + .stream() + .map(user -> new EntityModel<>(new UserModel(user))) + .collect(Collectors.toList()); + return new CollectionModel<>(users); } @GetMapping(value = "/{userId}") - UserEntity getUserById(@PathVariable UUID userId) { - return this.userService.getUserById(userId); + ResponseEntity> getUserById(@PathVariable UUID userId) { + return ResponseEntity.ok(new EntityModel<>(new UserModel(this.userService.getUserById(userId)))); + } + + @GetMapping(value = "/roles") + CollectionModel> getAllRoles() { + List> roles = this.userService.getAllRoles() + .stream() + .map(role -> new EntityModel<>(new RoleModel(role))) + .collect(Collectors.toList()); + return new CollectionModel<>(roles); + } + + @GetMapping(value = "/roles/privileges") + CollectionModel> getAllPrivileges() { + List> roles = this.userService.getAllPrivileges() + .stream() + .map(privilege -> new EntityModel<>(new PrivilegeModel(privilege))) + .collect(Collectors.toList()); + return new CollectionModel<>(roles); } /** @@ -57,10 +78,8 @@ UserEntity getUserById(@PathVariable UUID userId) { */ @PostMapping(value = "") @ResponseStatus(HttpStatus.CREATED) - public UserEntity newUser(@RequestBody UserEntity user) { - user.setPassword(passwordEncoder.encode(user.getPassword())); - return this.userService.createUser(user); - + ResponseEntity> newUser(@RequestBody UserModelRequest userModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new UserModel(this.userService.createUser(userModelRequest)))); } /** @@ -68,15 +87,22 @@ public UserEntity newUser(@RequestBody UserEntity user) { */ @PutMapping(value = "/{userId}") @ResponseStatus(HttpStatus.ACCEPTED) - UserEntity updateUser(@PathVariable UUID userId, @RequestBody UserEntity user) { - return this.userService.updateUser(user); + ResponseEntity> updateUser(@PathVariable UUID userId, @RequestBody UserModelRequest userModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new UserModel(this.userService.updateUser(userId, userModelRequest)))); + } + + @PutMapping(value = "/roles/{roleId}/privileges/{privilegeId}") + @ResponseStatus(HttpStatus.ACCEPTED) + ResponseEntity> updateUserRole(@PathVariable UUID roleId, @PathVariable UUID privilegeId, @RequestBody RoleModelRequest roleModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new RoleModel(this.userService.updateRole(roleId, privilegeId, roleModelRequest)))); } /** * DELETE Methods */ @DeleteMapping(value = "/{userId}") - void deleteUser(@PathVariable UUID userId) { + ResponseEntity deleteUser(@PathVariable UUID userId) { this.userService.deleteUser(userId); + return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/patternpedia/api/rest/model/CandidateModel.java b/src/main/java/com/patternpedia/api/rest/model/CandidateModel.java deleted file mode 100644 index ebfc81f..0000000 --- a/src/main/java/com/patternpedia/api/rest/model/CandidateModel.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.patternpedia.api.rest.model; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.patternpedia.api.entities.Pattern; -import com.patternpedia.api.entities.PatternLanguage; -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.CandidateComment; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -@NoArgsConstructor -@Data -@EqualsAndHashCode(callSuper = false) -public class CandidateModel { - - private UUID id; - - private String uri; - - private String name; - - private String iconUrl; - - private UUID patternLanguageId; - - private String patternLanguageName; - - private String content; - - private String version; - - private int rating; - - private List comments; - - private CandidateModel(Candidate candidate) { - PatternLanguage patternLanguage = candidate.getPatternLanguage(); - this.id = candidate.getId(); - this.uri = candidate.getUri(); - this.name = candidate.getName(); - this.iconUrl = candidate.getIconUrl(); - this.content = candidate.getContent(); - this.version = candidate.getVersion(); - this.rating = candidate.getRating(); - this.comments = candidate.getComments(); - - if (patternLanguage != null) { - this.patternLanguageId = patternLanguage.getId(); - this.patternLanguageName = patternLanguage.getName(); - } else { - this.patternLanguageId = null; - this.patternLanguageName = "NONE"; - } - } - - public static CandidateModel from(Candidate candidate) { - return new CandidateModel(candidate); - } -} diff --git a/src/main/java/com/patternpedia/api/rest/model/IssueModel.java b/src/main/java/com/patternpedia/api/rest/model/IssueModel.java deleted file mode 100644 index 9effbc7..0000000 --- a/src/main/java/com/patternpedia/api/rest/model/IssueModel.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.patternpedia.api.rest.model; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.UUID; - -@NoArgsConstructor -@Data -@EqualsAndHashCode(callSuper = false) -public class IssueModel { - - private UUID id; - - private UUID pattern_language_id; - - private UUID[] author_group; - - private UUID[] user_voted; - - private Integer votes; - - private String name; - - private String description; - - private String version; - - private Boolean active; -} diff --git a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java new file mode 100644 index 0000000..43df7ab --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java @@ -0,0 +1,65 @@ +package com.patternpedia.api.rest.model.candidate; + +import com.patternpedia.api.entities.PatternLanguage; +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.candidate.CandidateRating; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.rest.model.shared.AuthorModel; +import com.patternpedia.api.rest.model.shared.CommentModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class CandidateModel { + + private UUID id; + private String uri; + private String name; + private String iconUrl; + private UUID patternLanguageId; + private String patternLanguageName; + private String content; + private String version; + // RESPONSE + // RESPONSE + private Collection upVotes = new ArrayList<>(); + private Collection downVotes = new ArrayList<>(); + private List authors = new ArrayList<>(); + private List comments = new ArrayList<>(); + + public CandidateModel(Candidate candidate) { + PatternLanguage patternLanguage = candidate.getPatternLanguage(); + this.id = candidate.getId(); + this.uri = candidate.getUri(); + this.name = candidate.getName(); + this.iconUrl = candidate.getIconUrl(); + this.content = candidate.getContent(); + this.version = candidate.getVersion(); + // RESPONSE + for (CandidateRating candidateRating: candidate.getUserRating()) { + if (candidateRating.getRating() == 1) + this.upVotes.add(candidateRating.getUser().getId()); + if (candidateRating.getRating() == -1) + this.downVotes.add(candidateRating.getUser().getId()); + } + this.authors = candidate.getAuthors().stream().map(issueAuthor -> new AuthorModel(issueAuthor.getUser(), issueAuthor.getRole())).collect(Collectors.toList()); + this.comments = candidate.getComments().stream().map(issueComment -> CommentModel.from(issueComment)).collect(Collectors.toList()); + + if (patternLanguage != null) { + this.patternLanguageId = patternLanguage.getId(); + this.patternLanguageName = patternLanguage.getName(); + } else { + this.patternLanguageId = null; + this.patternLanguageName = "NONE"; + } + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java new file mode 100644 index 0000000..8d5f030 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java @@ -0,0 +1,19 @@ +package com.patternpedia.api.rest.model.candidate; + +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.rest.model.shared.AuthorModel; +import com.patternpedia.api.rest.model.user.UserModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class CandidateModelRequest extends CandidateModel { + + private Integer updateRating; + private List updateAuthors; +} diff --git a/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java b/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java new file mode 100644 index 0000000..82b37b2 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java @@ -0,0 +1,50 @@ +package com.patternpedia.api.rest.model.issue; + +import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.rest.model.shared.AuthorModel; +import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.RatingModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class IssueModel { + + private UUID id; + private String uri; + private String name; + private String description; + private String version; + // RESPONSE + private Collection upVotes = new ArrayList<>(); + private Collection downVotes = new ArrayList<>(); + private List authors = new ArrayList<>(); + private List comments = new ArrayList<>(); + + public IssueModel(Issue issue) { + this.id = issue.getId(); + this.uri = issue.getUri(); + this.name = issue.getName(); + this.description = issue.getDescription(); + this.version = issue.getVersion(); + //Response + for (IssueRating issueRating: issue.getUserRating()) { + if (issueRating.getRating() == 1) + this.upVotes.add(issueRating.getUser().getId()); + if (issueRating.getRating() == -1) + this.downVotes.add(issueRating.getUser().getId()); + } + this.authors = issue.getAuthors().stream().map(issueAuthor -> new AuthorModel(issueAuthor.getUser(), issueAuthor.getRole())).collect(Collectors.toList()); + this.comments = issue.getComments().stream().map(issueComment -> CommentModel.from(issueComment)).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/issue/IssueModelRequest.java b/src/main/java/com/patternpedia/api/rest/model/issue/IssueModelRequest.java new file mode 100644 index 0000000..1131d7e --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/issue/IssueModelRequest.java @@ -0,0 +1,17 @@ +package com.patternpedia.api.rest.model.issue; + +import com.patternpedia.api.rest.model.shared.AuthorModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class IssueModelRequest extends IssueModel { + + private Integer updateRating; + private List updateAuthors; +} diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModel.java new file mode 100644 index 0000000..fd102ac --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModel.java @@ -0,0 +1,42 @@ +package com.patternpedia.api.rest.model.shared; + +import com.patternpedia.api.entities.candidate.author.CandidateAuthor; +import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.user.UserEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class AuthorModel { + + private UUID userId; + private String name; + private String authorRole; + + public AuthorModel(IssueAuthor issueAuthor) { + this.userId = issueAuthor.getUser().getId(); + this.name = issueAuthor.getUser().getName(); + this.authorRole = issueAuthor.getRole(); + } + + public AuthorModel(CandidateAuthor candidateAuthor) { + this.userId = candidateAuthor.getUser().getId(); + this.name = candidateAuthor.getUser().getName(); + this.authorRole = candidateAuthor.getRole(); + } + + public AuthorModel(UserEntity user) { + this.userId = user.getId(); + this.name = user.getName(); + } + + public AuthorModel(UserEntity user, String role) { + this(user); + this.authorRole = role; + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java b/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java new file mode 100644 index 0000000..a885e01 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java @@ -0,0 +1,15 @@ +package com.patternpedia.api.rest.model.shared; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class AuthorModelRequest { + + private String authorRole; +} diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java new file mode 100644 index 0000000..96528d3 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java @@ -0,0 +1,57 @@ +package com.patternpedia.api.rest.model.shared; + +import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class CommentModel { + + private UUID id; + private UUID userId; + private String userName; + private String text; + private Collection upVotes = new ArrayList<>(); + private Collection downVotes = new ArrayList<>(); + + /** For Issue Comments*/ + public CommentModel(IssueComment issueComment) { + this.id = issueComment.getId(); + this.userId = issueComment.getUser().getId(); + this.userName = issueComment.getUser().getName(); + this.text = issueComment.getText(); + for (IssueCommentRating issueRating: issueComment.getUserRating()) { + if (issueRating.getRating() == 1) + this.upVotes.add(issueRating.getUser().getId()); + if (issueRating.getRating() == -1) + this.downVotes.add(issueRating.getUser().getId()); + } + } + public static CommentModel from(IssueComment issueComment) { return new CommentModel(issueComment); } + + /** For Candidate Comments*/ + public CommentModel(CandidateComment candidateComment) { + this.id = candidateComment.getId(); + this.userId = candidateComment.getUser().getId(); + this.userName = candidateComment.getUser().getName(); + this.text = candidateComment.getText(); + for (CandidateCommentRating candidateCommentRating: candidateComment.getUserRating()) { + if (candidateCommentRating.getRating() == 1) + this.upVotes.add(candidateCommentRating.getUser().getId()); + if (candidateCommentRating.getRating() == -1) + this.downVotes.add(candidateCommentRating.getUser().getId()); + } + } + public static CommentModel from(CandidateComment candidateComment) { return new CommentModel(candidateComment); } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java new file mode 100644 index 0000000..79233bf --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java @@ -0,0 +1,41 @@ +package com.patternpedia.api.rest.model.shared; + +import com.patternpedia.api.entities.candidate.CandidateRating; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.Collection; +import java.util.UUID; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class RatingModel { + + private int rating; + private UUID userId; + + public RatingModel(IssueRating issueRating) { + this.rating = issueRating.getRating(); + this.userId = issueRating.getUser().getId(); + } + + public RatingModel(IssueCommentRating issueCommentRating) { + this.rating = issueCommentRating.getRating(); + this.userId = issueCommentRating.getUser().getId(); + } + + public RatingModel(CandidateRating candidateRating) { + this.rating = candidateRating.getRating(); + this.userId = candidateRating.getUser().getId(); + } + + public RatingModel(CandidateCommentRating candidateCommentRating) { + this.rating = candidateCommentRating.getRating(); + this.userId = candidateCommentRating.getUser().getId(); + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModelRequest.java b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModelRequest.java new file mode 100644 index 0000000..d8aeb06 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModelRequest.java @@ -0,0 +1,13 @@ +package com.patternpedia.api.rest.model.shared; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class RatingModelRequest { + + private int rating; +} diff --git a/src/main/java/com/patternpedia/api/rest/model/user/PrivilegeModel.java b/src/main/java/com/patternpedia/api/rest/model/user/PrivilegeModel.java new file mode 100644 index 0000000..0a3e3e0 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/user/PrivilegeModel.java @@ -0,0 +1,23 @@ +package com.patternpedia.api.rest.model.user; + +import com.patternpedia.api.entities.user.role.Privilege; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class PrivilegeModel { + + private UUID id; + + private String name; + + public PrivilegeModel(Privilege privilege) { + this.id = privilege.getId(); + this.name = privilege.getName(); + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java b/src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java new file mode 100644 index 0000000..bb9e035 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java @@ -0,0 +1,29 @@ +package com.patternpedia.api.rest.model.user; + +import com.patternpedia.api.entities.user.role.Role; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.Collection; +import java.util.UUID; +import java.util.stream.Collectors; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class RoleModel { + + private UUID id; + private String name; +// private Collection privileges; + private Collection privileges; + + public RoleModel (Role role) { + this.id = role.getId(); + this.name = role.getName(); +// this.privileges = role.getPrivileges().stream().map(privilege -> new PrivilegeModel(privilege)).collect(Collectors.toList()); + this.privileges = role.getPrivileges().stream().map(privilege -> privilege.getName()).collect(Collectors.toList()); + + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/user/RoleModelRequest.java b/src/main/java/com/patternpedia/api/rest/model/user/RoleModelRequest.java new file mode 100644 index 0000000..f847d1c --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/user/RoleModelRequest.java @@ -0,0 +1,13 @@ +package com.patternpedia.api.rest.model.user; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class RoleModelRequest { + + private boolean checkboxValue; +} diff --git a/src/main/java/com/patternpedia/api/rest/model/user/UserModel.java b/src/main/java/com/patternpedia/api/rest/model/user/UserModel.java new file mode 100644 index 0000000..7d7afab --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/user/UserModel.java @@ -0,0 +1,39 @@ +package com.patternpedia.api.rest.model.user; + +import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.rest.model.issue.IssueModel; +import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.RatingModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class UserModel { + + private UUID id; + private String role; + private String email; + private String name; + private List issues; + private List issueComments; + private List issueRatings; + + public UserModel(UserEntity user) { + this.id = user.getId(); + this.role = user.getRole().getName(); + this.email = user.getEmail(); + this.name = user.getName(); + this.issues = user.getIssues().stream().map(issueAuthor -> new IssueModel(issueAuthor.getIssue())).collect(Collectors.toList()); + this.issueComments = user.getIssueComments().stream().map(issueComment -> new CommentModel(issueComment)).collect(Collectors.toList()); + this.issueRatings = user.getIssueRatings().stream().map((issueRating -> new IssueModel(issueRating.getIssue()))).collect(Collectors.toList()); + + } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/user/UserModelRequest.java b/src/main/java/com/patternpedia/api/rest/model/user/UserModelRequest.java new file mode 100644 index 0000000..5fa3f4b --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/user/UserModelRequest.java @@ -0,0 +1,14 @@ +package com.patternpedia.api.rest.model.user; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class UserModelRequest extends UserModel { + + private String oldPassword; + private String password; +} diff --git a/src/main/java/com/patternpedia/api/service/AuthorService.java b/src/main/java/com/patternpedia/api/service/AuthorService.java new file mode 100644 index 0000000..451682c --- /dev/null +++ b/src/main/java/com/patternpedia/api/service/AuthorService.java @@ -0,0 +1,24 @@ +package com.patternpedia.api.service; + +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.candidate.author.CandidateAuthor; +import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.rest.model.shared.AuthorModel; +import com.patternpedia.api.rest.model.shared.AuthorModelRequest; +import org.apache.catalina.User; + +import java.util.Collection; +import java.util.UUID; + +public interface AuthorService { + + IssueAuthor saveIssueAuthor(UUID userId, UUID issueId, AuthorModelRequest authorModelRequest); + void deleteIssueAuthor(UUID userId, UUID issueId); + + CandidateAuthor saveCandidateAuthor(UUID userId, UUID candidateId, AuthorModelRequest authorModelRequest); + void deleteCandidateAuthor(UUID userId, UUID candidateId); + +// Candidate updateCandidateAuthor(UUID candidateId, AuthorModelRequest authorModelRequest); +} diff --git a/src/main/java/com/patternpedia/api/service/AuthorServiceImpl.java b/src/main/java/com/patternpedia/api/service/AuthorServiceImpl.java new file mode 100644 index 0000000..8116fc8 --- /dev/null +++ b/src/main/java/com/patternpedia/api/service/AuthorServiceImpl.java @@ -0,0 +1,88 @@ +package com.patternpedia.api.service; + +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.candidate.author.CandidateAuthor; +import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.repositories.CandidateAuthorRepository; +import com.patternpedia.api.repositories.IssueAuthorRepository; +import com.patternpedia.api.rest.model.shared.AuthorModel; +import com.patternpedia.api.rest.model.shared.AuthorModelRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Service +@Transactional +public class AuthorServiceImpl implements AuthorService { + + Logger logger = LoggerFactory.getLogger(AuthorServiceImpl.class); + + private IssueAuthorRepository issueAuthorRepository; + private IssueService issueService; + private CandidateAuthorRepository candidateAuthorRepository; + private CandidateService candidateService; + private UserService userService; + + public AuthorServiceImpl( + IssueAuthorRepository issueAuthorRepository, + IssueService issueService, + CandidateAuthorRepository candidateAuthorRepository, + CandidateService candidateService, + UserService userService + ) { + this.issueAuthorRepository = issueAuthorRepository; + this.issueService = issueService; + this.candidateAuthorRepository = candidateAuthorRepository; + this.candidateService = candidateService; + this.userService = userService; + } + + @Override + @Transactional + public IssueAuthor saveIssueAuthor(UUID userId, UUID issueId, AuthorModelRequest authorModelRequest) { + Issue issue = issueService.getIssueById(issueId); + UserEntity user = userService.getUserById(userId); + IssueAuthor issueAuthor = new IssueAuthor(issue, user, authorModelRequest.getAuthorRole()); + return this.issueAuthorRepository.save(issueAuthor); + } + + @Override + @Transactional + public void deleteIssueAuthor(UUID userId, UUID issueId) { + Issue issue = this.issueService.getIssueById(issueId); + UserEntity user = this.userService.getUserById(userId); + IssueAuthor issueAuthor = new IssueAuthor(issue, user); + if (this.issueAuthorRepository.existsById(issueAuthor.getId())) { + this.issueAuthorRepository.deleteById(issueAuthor.getId()); + } + } + + @Override + @Transactional + public CandidateAuthor saveCandidateAuthor(UUID userId, UUID candidateId, AuthorModelRequest authorModelRequest) { + Candidate candidate = this.candidateService.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(userId); + CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user, authorModelRequest.getAuthorRole()); + return this.candidateAuthorRepository.save(candidateAuthor); + } + + @Override + @Transactional + public void deleteCandidateAuthor(UUID userId, UUID candidateId) { + Candidate candidate = this.candidateService.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(userId); + CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user); + if (this.candidateAuthorRepository.existsById(candidateAuthor.getId())) { + this.candidateAuthorRepository.deleteById(candidateAuthor.getId()); + } + } + +} + diff --git a/src/main/java/com/patternpedia/api/service/CandidateService.java b/src/main/java/com/patternpedia/api/service/CandidateService.java index f928416..58e3245 100644 --- a/src/main/java/com/patternpedia/api/service/CandidateService.java +++ b/src/main/java/com/patternpedia/api/service/CandidateService.java @@ -1,37 +1,35 @@ package com.patternpedia.api.service; import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.CandidateComment; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.issue.IssueComment; -import com.patternpedia.api.rest.model.CandidateModel; +import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; +import com.patternpedia.api.rest.model.shared.CommentModel; +import org.springframework.http.ResponseEntity; import java.util.List; import java.util.UUID; public interface CandidateService { + Candidate saveCandidate(Candidate candidate); /** CRUD */ - Candidate createCandidate(CandidateModel candidateModel); + Candidate createCandidate(CandidateModelRequest candidateModelRequest, UUID userId); - Candidate updateCandidate(Candidate candidate); - - void deleteCandidate(UUID candidateId); + List getAllCandidates(); Candidate getCandidateById(UUID candidateId); Candidate getCandidateByURI(String uri); - List getAllCandidates(); + Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRequest candidateModelRequest); - /** Voting */ - Candidate userRating(UUID candidateId, UUID userId, String rating); + void deleteCandidate(UUID candidateId); /** Comment */ - Candidate createComment(UUID candidateId, UUID userId, CandidateComment candidateComment); + CandidateComment createComment(UUID candidateId, UUID userId, CommentModel commentModel); CandidateComment getCommentById(UUID candidateCommentId); - CandidateComment updateComment(CandidateComment candidateComment); + CandidateComment updateComment(UUID candidateId, UUID commentId, UUID userId, CommentModel commentModel); - Candidate commentUserRating(UUID candidateCommentId, UUID userId, String rating); + ResponseEntity deleteComment(UUID candidateId, UUID commentId, UUID userId); } diff --git a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java index 61020e1..5470c67 100644 --- a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java @@ -1,18 +1,25 @@ package com.patternpedia.api.service; -import com.patternpedia.api.entities.PatternLanguage; import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.CandidateComment; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.exception.*; +import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.entities.candidate.author.CandidateAuthor; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.shared.AuthorConstant; +import com.patternpedia.api.entities.user.UserEntity; import com.patternpedia.api.repositories.*; -import com.patternpedia.api.rest.model.CandidateModel; +import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; +import com.patternpedia.api.rest.model.shared.CommentModel; import com.patternpedia.api.util.RatingHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.persistence.EntityExistsException; +import javax.persistence.EntityNotFoundException; import java.util.List; import java.util.UUID; @@ -23,7 +30,6 @@ public class CandidateServiceImpl implements CandidateService { private CandidateRepository candidateRepository; private CandidateRatingRepository candidateRatingRepository; private CandidateCommentRepository candidateCommentRepository; - private CandidateCommentRatingRepository candidateCommentRatingRepository; private PatternLanguageService patternLanguageService; private UserService userService; private RatingHelper ratingHelper; @@ -34,112 +40,153 @@ public CandidateServiceImpl( CandidateRepository candidateRepository, CandidateRatingRepository candidateRatingRepository, CandidateCommentRepository candidateCommentRepository, - CandidateCommentRatingRepository candidateCommentRatingRepository, PatternLanguageService patternLanguageService, UserService userService ) { this.candidateRepository = candidateRepository; this.candidateRatingRepository = candidateRatingRepository; this.candidateCommentRepository = candidateCommentRepository; - this.candidateCommentRatingRepository = candidateCommentRatingRepository; this.patternLanguageService = patternLanguageService; this.userService = userService; this.ratingHelper = new RatingHelper(); } + @Override + @Transactional + public Candidate saveCandidate(Candidate candidate) { + return this.candidateRepository.save(candidate); + } /** * CRUD Candidate */ @Override @Transactional - public Candidate createCandidate(CandidateModel candidateModel) { - Candidate candidate = new Candidate(candidateModel); + public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UUID userId) { + Candidate candidate = new Candidate(candidateModelRequest); + if (null == candidate) + throw new RuntimeException("Candidate to create is null"); + if (this.candidateRepository.existsByName(candidate.getName())) + throw new EntityExistsException(String.format("Candidate name %s already exist!", candidateModelRequest.getName())); + if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) + throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); - if (null == candidate) { - throw new NullCandidateException(); - } - if (candidateModel.getPatternLanguageId() != null) { - PatternLanguage patternLanguage = this.patternLanguageService.getPatternLanguageById(candidateModel.getPatternLanguageId()); - candidate.setPatternLanguage(patternLanguage); - } else { - candidate.setPatternLanguage(null); - } +// throw new ResourceNotFoundException(String.format("Pattern Language %s does not exist", candidateModelRequest.getPatternLanguageId())); + // ADD authors Candidate newCandidate = this.candidateRepository.save(candidate); - logger.info(String.format("Create Candidate %s: ", newCandidate.toString())); - return newCandidate; + newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(userId), AuthorConstant.OWNER)); + + // ADD pattern language + if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) + newCandidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); + + return this.candidateRepository.save(newCandidate); } @Override @Transactional - public Candidate getCandidateById(UUID candidateId) { - return this.candidateRepository.findById(candidateId) - .orElseThrow(() -> new CandidateNotFoundException(candidateId)); + public List getAllCandidates() { + return this.candidateRepository.findAll(); } @Override @Transactional - public Candidate getCandidateByURI(String uri) { - return this.candidateRepository.findByUri(uri) - .orElseThrow(() -> new CandidateNotFoundException(String.format("Pattern with URI %s not found!", uri))); + public Candidate getCandidateById(UUID candidateId) { + return this.candidateRepository.findById(candidateId) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Candidate with ID %s not found!", candidateId))); } @Override @Transactional - public List getAllCandidates() { - return this.candidateRepository.findAll(); + public Candidate getCandidateByURI(String uri) { + return this.candidateRepository.findByUri(uri) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Candidate with URI %s not found!", uri))); } @Override @Transactional - public Candidate updateCandidate(Candidate candidate) { - if (null == candidate) { - throw new NullCandidateException(); + public Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRequest candidateModelRequest) { + if (candidateModelRequest == null) { + throw new RuntimeException("Candidate to update is null!"); } - if (!this.candidateRepository.existsById(candidate.getId())) { - throw new CandidateNotFoundException(candidate.getId()); + Candidate candidate = this.getCandidateById(candidateId); + + // UPDATE issue fields + if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) { + Candidate candidateByURI = this.getCandidateByURI(candidateModelRequest.getUri()); + // NOT uri & name change + if (!candidateByURI.getId().equals(candidate.getId())) { + throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); + } } + // ADD pattern language + if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) + candidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); + + // UPDATE issue fields + candidate.updateCandidate(candidateModelRequest); - logger.info(String.format("Update Issue: %s", candidate.toString())); return this.candidateRepository.save(candidate); } @Override @Transactional public void deleteCandidate(UUID candidateId) { - Candidate candidate = this.getCandidateById(candidateId); - if (null == candidate) { - throw new NullCandidateException(); - } - + this.getCandidateById(candidateId); this.candidateRepository.deleteById(candidateId); } - /** */ + /** + * Comment + */ @Override - public Candidate userRating(UUID candidateId, UUID userId, String rating) { - return null; - } + @Transactional + public CandidateComment createComment(UUID candidateId, UUID userId, CommentModel commentModel) { + Candidate candidate = this.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(userId); - @Override - public Candidate createComment(UUID candidateId, UUID userId, CandidateComment candidateComment) { - return null; + CandidateComment comment = new CandidateComment(commentModel.getText(), candidate, user); + return this.candidateCommentRepository.save(comment); } @Override + @Transactional(readOnly = true) public CandidateComment getCommentById(UUID candidateCommentId) { - return null; + return this.candidateCommentRepository.findById(candidateCommentId) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Candidate comment with ID %s not found!", candidateCommentId))); } @Override - public CandidateComment updateComment(CandidateComment candidateComment) { - return null; + @Transactional + public CandidateComment updateComment(UUID candidateId, UUID commentId, UUID userId, CommentModel commentModel) { + if (commentModel == null) + throw new RuntimeException("Candidate comment to update is null!"); + // Used to check if candidate actually exists + CandidateComment candidateComment = this.authCandidateComment(candidateId, commentId, userId); + + // UPDATE issue comment + candidateComment.updateComment(commentModel.getText()); + return this.candidateCommentRepository.save(candidateComment); } @Override - public Candidate commentUserRating(UUID candidateCommentId, UUID userId, String rating) { - return null; + @Transactional + public ResponseEntity deleteComment(UUID issueId, UUID commentId, UUID userId) { + this.authCandidateComment(issueId, commentId, userId); + this.candidateCommentRepository.deleteById(commentId); + return ResponseEntity.noContent().build(); + } + + private CandidateComment authCandidateComment(UUID candidateId, UUID commentId, UUID userId) { + CandidateComment candidateComment = this.getCommentById(commentId); + // CORRECT Issue + if (!candidateComment.getCandidate().equals(this.getCandidateById(candidateId))) + throw new EntityNotFoundException(String.format("Candidate comment with id %s does not belong to candidate with id %s", commentId, candidateId)); + // CORRECT user + if (!candidateComment.getUser().equals(this.userService.getUserById(userId))) + throw new EntityNotFoundException(String.format("Candidate comment with id %s does not belong to user with id %s", commentId, userId)); + return candidateComment; } } diff --git a/src/main/java/com/patternpedia/api/service/IssueService.java b/src/main/java/com/patternpedia/api/service/IssueService.java index 63ac503..115b365 100644 --- a/src/main/java/com/patternpedia/api/service/IssueService.java +++ b/src/main/java/com/patternpedia/api/service/IssueService.java @@ -2,35 +2,36 @@ import java.util.List; -import com.patternpedia.api.entities.issue.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.rest.model.issue.IssueModelRequest; +import com.patternpedia.api.rest.model.shared.CommentModel; +import org.springframework.http.ResponseEntity; import java.util.UUID; public interface IssueService { + Issue saveIssue(Issue issue); /** CRUD */ - Issue createIssue(Issue issue); + Issue createIssue(IssueModelRequest issueModelRequest, UUID userId); + + List getAllIssues(); Issue getIssueById(UUID issueId); Issue getIssueByURI(String uri); - List getAllIssues(); - - Issue updateIssue(Issue issue); + Issue updateIssue(UUID issueId, UUID userId, IssueModelRequest issueModelRequest); void deleteIssue(UUID issueId); - /** Voting */ - Issue userRating(UUID issueId, UUID userId, String rating); - /** Comment */ - Issue createComment(UUID issueId, UUID userId, IssueComment issueComment); + IssueComment createComment(UUID issueId, UUID userId, CommentModel commentModel); IssueComment getCommentById(UUID issueCommentId); - IssueComment updateComment(IssueComment issueComment); + IssueComment updateComment(UUID issueId, UUID commentId, UUID userId, CommentModel commentModel); - Issue commentUserRating(UUID issueCommentId, UUID userId, String rating); + ResponseEntity deleteComment(UUID issueId, UUID commentId, UUID userId); } diff --git a/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java b/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java index a1441c1..140499b 100644 --- a/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java @@ -1,50 +1,53 @@ package com.patternpedia.api.service; -import com.patternpedia.api.entities.issue.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.issue.rating.IssueCommentRating; +import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.shared.AuthorConstant; import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.entities.issue.rating.IssueRating; -import com.patternpedia.api.exception.*; -import com.patternpedia.api.repositories.IssueCommentRatingRepository; -import com.patternpedia.api.repositories.IssueCommentRepository; -import com.patternpedia.api.repositories.IssueRepository; -import com.patternpedia.api.repositories.IssueRatingRepository; -import com.patternpedia.api.util.RatingHelper; +import com.patternpedia.api.repositories.*; +import com.patternpedia.api.rest.model.issue.IssueModelRequest; +import com.patternpedia.api.rest.model.shared.AuthorModel; +import com.patternpedia.api.rest.model.shared.CommentModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.UUID; +import javax.persistence.EntityExistsException; +import javax.persistence.EntityNotFoundException; +import java.util.*; @Service @Transactional public class IssueServiceImpl implements IssueService { private IssueRepository issueRepository; - private IssueRatingRepository issueRatingRepository; private IssueCommentRepository issueCommentRepository; private IssueCommentRatingRepository issueCommentRatingRepository; private UserService userService; - private RatingHelper ratingHelper; Logger logger = LoggerFactory.getLogger(IssueServiceImpl.class); public IssueServiceImpl( IssueRepository issueRepository, - IssueRatingRepository issueRatingRepository, IssueCommentRepository issueCommentRepository, IssueCommentRatingRepository issueCommentRatingRepository, UserService userService ) { this.issueRepository = issueRepository; - this.issueRatingRepository = issueRatingRepository; this.issueCommentRepository = issueCommentRepository; this.issueCommentRatingRepository = issueCommentRatingRepository; this.userService = userService; - this.ratingHelper = new RatingHelper(); + } + + @Override + @Transactional + public Issue saveIssue(Issue issue) { + return this.issueRepository.save(issue); } /** @@ -52,172 +55,114 @@ public IssueServiceImpl( */ @Override @Transactional - public Issue createIssue(Issue issue) { - if (null == issue) { - throw new NullIssueException(); - } + public Issue createIssue(IssueModelRequest issueModelRequest, UUID userId) { + Issue issue = new Issue(issueModelRequest); + if (null == issue) + throw new RuntimeException("Issue to create is null"); + if (this.issueRepository.existsByName(issueModelRequest.getName())) + throw new EntityExistsException(String.format("Issue name %s already exist!", issueModelRequest.getName())); + if (this.issueRepository.existsByUri(issueModelRequest.getUri())) + throw new EntityExistsException(String.format("Issue uri %s already exist!", issueModelRequest.getUri())); Issue newIssue = this.issueRepository.save(issue); - logger.info(String.format("Create Issue %s: ", newIssue.toString())); - return newIssue; + newIssue.getAuthors().add(new IssueAuthor(newIssue, this.userService.getUserById(userId), AuthorConstant.OWNER)); + return this.issueRepository.save(newIssue); } @Override @Transactional(readOnly = true) - public Issue getIssueById(UUID IssueId) { - return this.issueRepository.findById(IssueId) - .orElseThrow(() -> new IssueNotFoundException(IssueId)); + public List getAllIssues() { + return this.issueRepository.findAll(); } @Override @Transactional(readOnly = true) - public Issue getIssueByURI(String uri) { - return this.issueRepository.findByUri(uri) - .orElseThrow(() -> new IssueNotFoundException(String.format("Issue with URI %s not found!", uri))); + public Issue getIssueById(UUID issueId) { + return this.issueRepository.findById(issueId) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Issue with ID %s not found!", issueId))); } @Override @Transactional(readOnly = true) - public List getAllIssues() { - return this.issueRepository.findAll(); + public Issue getIssueByURI(String uri) { + return this.issueRepository.findByUri(uri) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Issue with URI %s not found!", uri))); } @Override @Transactional - public Issue updateIssue(Issue issue) { - if (null == issue) { - throw new NullIssueException(); - } - if (!this.issueRepository.existsById(issue.getId())) { - throw new IssueNotFoundException(String.format("Issue %s not found", issue.getId())); + public Issue updateIssue(UUID issueId, UUID userId, IssueModelRequest issueModelRequest) { + if (issueModelRequest == null) { + throw new RuntimeException("Issue to update is null!"); } + Issue issue = this.getIssueById(issueId); - logger.info(String.format("Update Issue: %s", issue.toString())); + // UPDATE issue fields + if (this.issueRepository.existsByUri(issueModelRequest.getUri())) { + Issue issueUri = this.getIssueByURI(issueModelRequest.getUri()); + // NOT uri & name change + if (!issueUri.getId().equals(issue.getId())) { + throw new EntityExistsException(String.format("Issue uri %s already exist!", issueModelRequest.getUri())); + } + } + issue.updateIssue(issueModelRequest); return this.issueRepository.save(issue); } @Override @Transactional public void deleteIssue(UUID IssueId) { - Issue issue = this.getIssueById(IssueId); - if (null == issue) { - throw new NullIssueException(); - } - + this.getIssueById(IssueId); this.issueRepository.deleteById(IssueId); } /** - * Voting Issue - * - * @param rating up, down - * @apiNote If user already up- or downvoted and does so again it neutralises vote. + * Comment */ @Override @Transactional - public Issue userRating(UUID IssueId, UUID userId, String rating) { - Issue issue = this.getIssueById(IssueId); - UserEntity user = this.userService.getUserById(userId); - - logger.info(String.format("User %s updates rating for Issue %s", user.getId(), issue.getId())); - - IssueRating issueRating = new IssueRating(issue, user); - - if (this.issueRatingRepository.existsById(issueRating.getId())) { - issueRating = this.issueRatingRepository.findByIssueAndUser(issue, user); - logger.info(String.format("Rating for user %s exists with rating %s", user.getId(), issueRating.getRating())); - } else { - logger.info(String.format("Rating for user %s does not exist", user.getId())); - } - - int newRating = this.ratingHelper.updateRating(rating, issueRating.getRating(), user); - if (newRating == -2) { - return null; - } else { - issueRating.setRating(newRating); - } - - issue.getUserRating().add(issueRating); - int updateRating = issue.getUserRating().stream().mapToInt(IssueRating::getRating).sum(); - issue.setRating(updateRating); - - return this.updateIssue(issue); - } - - /** - * Comment Issue - */ - @Override - @Transactional - public Issue createComment(UUID issueId, UUID userId, IssueComment issueComment) { + public IssueComment createComment(UUID issueId, UUID userId, CommentModel commentModel) { Issue issue = this.getIssueById(issueId); UserEntity user = this.userService.getUserById(userId); - IssueComment comment = new IssueComment(issueComment.getText()); - issue.addComment(comment, user); - - return this.updateIssue(issue); - } - - @Override - @Transactional - public IssueComment updateComment(IssueComment issueComment) { - if (null == issueComment) { - throw new NullCommentException(); - } - if (!this.issueCommentRepository.existsById(issueComment.getId())) { - throw new CommentNotFoundException(String.format("Comment %s for issue %s not found", issueComment.getId(), issueComment.getIssue().getId())); - } - - logger.info(String.format("Update issue comment: %s", issueComment.toString())); - return this.issueCommentRepository.save(issueComment); + IssueComment comment = new IssueComment(commentModel.getText(), issue, user); + return this.issueCommentRepository.save(comment); } @Override @Transactional(readOnly = true) public IssueComment getCommentById(UUID commentId) { return this.issueCommentRepository.findById(commentId) - .orElseThrow(() -> new CommentNotFoundException(commentId)); + .orElseThrow(() -> new ResourceNotFoundException(String.format("Issue comment with ID %s not found!", commentId))); } - /** - * Voting IssueComment - * - * @param rating up, down - * @apiNote If user already up- or downvoted and does so again it neutralises vote. - */ @Override @Transactional - public Issue commentUserRating(UUID issueCommentId, UUID userId, String rating) { - IssueComment issueComment = this.getCommentById(issueCommentId); - UserEntity user = this.userService.getUserById(userId); - - logger.info(String.format("User %s updates rating for Comment %s", user.getId(), issueComment.getId())); - - IssueCommentRating issueCommentRating = new IssueCommentRating(issueComment, user); - - if (this.issueCommentRatingRepository.existsById(issueCommentRating.getId())) { - issueCommentRating = this.issueCommentRatingRepository.findByIssueCommentAndUser(issueComment, user); - logger.info(String.format("Rating for user %s exists with rating %s", user.getId(), issueCommentRating.getRating())); - } else { - logger.info(String.format("Rating for user %s does not exist", user.getId())); - } - - int newRating = this.ratingHelper.updateRating(rating, issueCommentRating.getRating(), user); - if (newRating == -2) { - return null; - } else { - issueCommentRating.setRating(newRating); - } - - issueComment.getUserRating().add(issueCommentRating); - int updateRating = issueComment.getUserRating().stream().mapToInt(IssueCommentRating::getRating).sum(); - issueComment.setRating((updateRating)); - logger.info(String.format("New rating for comment is: %d", updateRating)); - this.updateComment(issueComment); - - return this.getIssueById(issueComment.getIssue().getId()); + public IssueComment updateComment(UUID issueId, UUID commentId, UUID userId, CommentModel commentModel) { + if (commentModel == null) + throw new RuntimeException("Issue comment to update is null!"); + IssueComment issueComment = this.authIssueComment(issueId, commentId, userId); + // UPDATE issue comment + issueComment.updateComment(commentModel.getText()); + return this.issueCommentRepository.save(issueComment); } + @Override + @Transactional + public ResponseEntity deleteComment(UUID issueId, UUID commentId, UUID userId) { + this.authIssueComment(issueId, commentId, userId); + this.issueCommentRepository.deleteById(commentId); + return ResponseEntity.noContent().build(); + } + private IssueComment authIssueComment(UUID issueId, UUID commentId, UUID userId) { + IssueComment issueComment = this.getCommentById(commentId); + // CORRECT Issue + if (!issueComment.getIssue().equals(this.getIssueById(issueId))) + throw new EntityNotFoundException(String.format("Issue comment with id %s does not belong to issue with id %s", commentId, issueId)); + // CORRECT user + if (!issueComment.getUser().equals(this.userService.getUserById(userId))) + throw new EntityNotFoundException(String.format("Issue comment with id %s does not belong to user with id %s", commentId, userId)); + return issueComment; + } } diff --git a/src/main/java/com/patternpedia/api/service/RatingService.java b/src/main/java/com/patternpedia/api/service/RatingService.java new file mode 100644 index 0000000..c4569d4 --- /dev/null +++ b/src/main/java/com/patternpedia/api/service/RatingService.java @@ -0,0 +1,21 @@ +package com.patternpedia.api.service; + +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.candidate.CandidateRating; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.rest.model.shared.RatingModelRequest; + +import java.util.Collection; +import java.util.UUID; + +public interface RatingService { + + IssueRating updateIssueRating(UUID issueId, UUID userId, RatingModelRequest ratingModelRequest); + IssueCommentRating updateIssueCommentRating(UUID issueId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); + + CandidateRating updateCandidateRating(UUID candidateId, UUID userId, RatingModelRequest ratingModelRequest); + CandidateCommentRating updateCandidateCommentRating(UUID candidateId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); +} diff --git a/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java b/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java new file mode 100644 index 0000000..3571734 --- /dev/null +++ b/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java @@ -0,0 +1,109 @@ +package com.patternpedia.api.service; + +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.candidate.CandidateRating; +import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.repositories.*; +import com.patternpedia.api.rest.model.shared.RatingModelRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +@Service +@Transactional +public class RatingServiceImpl implements RatingService { + + Logger logger = LoggerFactory.getLogger(RatingServiceImpl.class); + + private IssueRatingRepository issueRatingRepository; + private IssueCommentRatingRepository issueCommentRatingRepository; + private IssueService issueService; + private CandidateRatingRepository candidateRatingRepository; + private CandidateCommentRatingRepository candidateCommentRatingRepository; + private CandidateService candidateService; + private UserService userService; + + public RatingServiceImpl( + IssueRatingRepository issueRatingRepository, + IssueCommentRatingRepository issueCommentRatingRepository, + IssueService issueService, + CandidateRatingRepository candidateRatingRepository, + CandidateCommentRatingRepository candidateCommentRatingRepository, + CandidateService candidateService, + UserService userService + ) { + this.issueRatingRepository = issueRatingRepository; + this.issueCommentRatingRepository = issueCommentRatingRepository; + this.issueService = issueService; + this.candidateRatingRepository = candidateRatingRepository; + this.candidateCommentRatingRepository = candidateCommentRatingRepository; + this.candidateService = candidateService; + this.userService = userService; + } + + @Override + @Transactional + public IssueRating updateIssueRating(UUID issueId, UUID userId, RatingModelRequest ratingModelRequest) { + Issue issue = this.issueService.getIssueById(issueId); + UserEntity user = this.userService.getUserById(userId); + IssueRating issueRating = new IssueRating(issue, user, ratingModelRequest.getRating()); + + if (this.issueRatingRepository.existsByIdAndRating(issueRating.getId(), issueRating.getRating())) { + this.issueRatingRepository.delete(issueRating); + issueRating.setRating(0); + return issueRating; + } + return this.issueRatingRepository.save(issueRating); + } + + @Override + @Transactional + public IssueCommentRating updateIssueCommentRating(UUID issueId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest) { + Issue issue = this.issueService.getIssueById(issueId); + IssueComment issueComment = this.issueService.getCommentById(commentId); + UserEntity user = this.userService.getUserById(userId); + IssueCommentRating issueCommentRating = new IssueCommentRating(issueComment, user, ratingModelRequest.getRating()); + if (this.issueCommentRatingRepository.existsByIdAndRating(issueCommentRating.getId(), issueCommentRating.getRating())) { + this.issueCommentRatingRepository.delete(issueCommentRating); + issueCommentRating.setRating(0); + return issueCommentRating; + } + return this.issueCommentRatingRepository.save(issueCommentRating); + } + + @Override + @Transactional + public CandidateRating updateCandidateRating(UUID candidateId, UUID userId, RatingModelRequest ratingModelRequest) { + Candidate candidate = this.candidateService.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(userId); + CandidateRating candidateRating = new CandidateRating(candidate, user, ratingModelRequest.getRating()); + if (this.candidateRatingRepository.existsByIdAndRating(candidateRating.getId(), candidateRating.getRating())) { + candidateRating.setRating(0); + } + return this.candidateRatingRepository.save(candidateRating); + } + + @Override + @Transactional + public CandidateCommentRating updateCandidateCommentRating(UUID candidateId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest) { + Candidate candidate = this.candidateService.getCandidateById(candidateId); + CandidateComment candidateComment = this.candidateService.getCommentById(commentId); + UserEntity user = this.userService.getUserById(userId); + CandidateCommentRating candidateCommentRating = new CandidateCommentRating(candidateComment, user, ratingModelRequest.getRating()); + if (this.candidateCommentRatingRepository.existsByIdAndRating(candidateCommentRating.getId(), candidateCommentRating.getRating())) { + this.candidateCommentRatingRepository.delete(candidateCommentRating); + candidateCommentRating.setRating(0); + return candidateCommentRating; + } + return this.candidateCommentRatingRepository.save(candidateCommentRating); + } +} diff --git a/src/main/java/com/patternpedia/api/service/UserService.java b/src/main/java/com/patternpedia/api/service/UserService.java index b138b55..a664af5 100644 --- a/src/main/java/com/patternpedia/api/service/UserService.java +++ b/src/main/java/com/patternpedia/api/service/UserService.java @@ -1,19 +1,28 @@ package com.patternpedia.api.service; +import com.patternpedia.api.entities.user.role.Privilege; +import com.patternpedia.api.entities.user.role.Role; import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.rest.model.user.RoleModel; +import com.patternpedia.api.rest.model.user.RoleModelRequest; +import com.patternpedia.api.rest.model.user.UserModel; +import com.patternpedia.api.rest.model.user.UserModelRequest; import java.util.List; import java.util.UUID; public interface UserService { - UserEntity createUser(UserEntity user); - + UserEntity createUser(UserModelRequest userModelRequest); + List getAllUsers(); UserEntity getUserById(UUID UserId); + UserEntity updateUser(UUID userId, UserModelRequest userModelRequest); + void deleteUser(UUID UserId); - List getAllUsers(); + /** Role */ + List getAllRoles(); - UserEntity updateUser(UserEntity user); + List getAllPrivileges(); - void deleteUser(UUID UserId); + Role updateRole(UUID roleId, UUID privilegeId, RoleModelRequest roleModelRequest); } diff --git a/src/main/java/com/patternpedia/api/service/UserServiceImpl.java b/src/main/java/com/patternpedia/api/service/UserServiceImpl.java index cea3b7b..8e03e95 100644 --- a/src/main/java/com/patternpedia/api/service/UserServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/UserServiceImpl.java @@ -1,74 +1,134 @@ package com.patternpedia.api.service; +import com.patternpedia.api.entities.user.role.RoleConstant; +import com.patternpedia.api.entities.user.role.Privilege; +import com.patternpedia.api.entities.user.role.Role; import com.patternpedia.api.entities.user.UserEntity; import com.patternpedia.api.exception.*; +import com.patternpedia.api.repositories.PrivilegeRepository; +import com.patternpedia.api.repositories.RoleRepository; import com.patternpedia.api.repositories.UserRepository; +import com.patternpedia.api.rest.model.user.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.UUID; +import java.util.*; @Service @Transactional public class UserServiceImpl implements UserService { private UserRepository userRepository; + private RoleRepository roleRepository; + private PrivilegeRepository privilegeRepository; + private final PasswordEncoder passwordEncoder; Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); - public UserServiceImpl(UserRepository userRepository) { + public UserServiceImpl( + UserRepository userRepository, + RoleRepository roleRepository, + PrivilegeRepository privilegeRepository, + PasswordEncoder passwordEncoder) { this.userRepository = userRepository; + this.roleRepository = roleRepository; + this.privilegeRepository = privilegeRepository; + this.passwordEncoder = passwordEncoder; } @Override @Transactional - public UserEntity createUser(UserEntity user) { - if (null == user) { - throw new NullUserException(); - } + public UserEntity createUser(UserModelRequest userModelRequest) { + if (null == userModelRequest) + throw new RuntimeException("User to update is null!"); + // DEFAULT password + if (userModelRequest.getPassword() == null) + userModelRequest.setPassword("pass"); - UserEntity newUser = this.userRepository.save(user); - logger.info(String.format("Create Issue %s: ", newUser.toString())); - return newUser; + UserEntity user = new UserEntity(userModelRequest, passwordEncoder.encode(userModelRequest.getPassword())); + if (this.roleRepository.findByName(userModelRequest.getRole()) != null) { + user.setRole(this.roleRepository.findByName(userModelRequest.getRole())); + } else { + user.setRole(this.roleRepository.findByName(RoleConstant.MEMBER)); + } + return this.userRepository.save(user); } @Override @Transactional(readOnly = true) - public UserEntity getUserById(UUID userId) { - return this.userRepository.findById(userId) - .orElseThrow(() -> new UserNotFoundException(userId)); + public List getAllUsers() { + return this.userRepository.findAll(); } @Override @Transactional(readOnly = true) - public List getAllUsers() { - return this.userRepository.findAll(); + public UserEntity getUserById(UUID userId) { + return this.userRepository.findById(userId) + .orElseThrow(() -> new ResourceNotFoundException(String.format("User with ID %s not found!", userId))); } @Override @Transactional - public UserEntity updateUser(UserEntity user) { - if (null == user) { - throw new NullUserException(); - } - if (!this.userRepository.existsById(user.getId())) { - throw new UserNotFoundException(user.getId()); + public UserEntity updateUser(UUID userId, UserModelRequest userModelRequest) { + if (userModelRequest == null) + throw new RuntimeException("User to update is null!"); + if (!this.roleRepository.existsByName(userModelRequest.getRole())) + throw new ResourceNotFoundException(String.format("User Role %s not found!", userModelRequest.getRole())); + + UserEntity user = this.getUserById(userId); + if (!user.getRole().getName().equals(userModelRequest.getRole())) + user.setRole(this.roleRepository.findByName(userModelRequest.getRole())); + if (userModelRequest.getOldPassword() != null || userModelRequest.getPassword() != null) { + if (!passwordEncoder.matches(userModelRequest.getOldPassword(), user.getPassword()) && !user.getRole().getName().equals(RoleConstant.ADMIN)) + throw new ResourceNotFoundException(String.format("Password ERROR")); + user.setPassword(passwordEncoder.encode(userModelRequest.getPassword())); } + user.updateUserEntity(userModelRequest); return this.userRepository.save(user); } @Override @Transactional public void deleteUser(UUID userId) { - UserEntity user = this.getUserById(userId); - if (null == user) { - throw new NullUserException(); - } - + this.getUserById(userId); this.userRepository.deleteById(userId); } + + /** + * Role && Permission + */ + @Override + @Transactional(readOnly = true) + public List getAllRoles() { + return this.roleRepository.findAll(); + } + + @Override + @Transactional(readOnly = true) + public List getAllPrivileges() { + return this.privilegeRepository.findAll(); + } + + @Override + @Transactional + public Role updateRole(UUID roleId, UUID privilegeId, RoleModelRequest roleModelRequest) { + if (roleModelRequest == null) + throw new RuntimeException("Role to update is null!"); + + Role role = this.roleRepository.findById(roleId).orElseThrow(() -> new ResourceNotFoundException(String.format(" Role %s not found!", roleId))); + Privilege privilege = this.privilegeRepository.findById(privilegeId).orElseThrow(() -> new ResourceNotFoundException(String.format("Privilege %s not found!", privilegeId))); + + if (role.getPrivileges().contains(privilege) && !roleModelRequest.isCheckboxValue()) + role.getPrivileges().remove(privilege); + + if (!role.getPrivileges().contains(privilege) && roleModelRequest.isCheckboxValue()) + role.getPrivileges().add(privilege); + + return this.roleRepository.save(role); + } } diff --git a/src/main/resources/applicationYML.yml b/src/main/resources/applicationYML.yml deleted file mode 100644 index eeca5ac..0000000 --- a/src/main/resources/applicationYML.yml +++ /dev/null @@ -1,35 +0,0 @@ -server: - port: 8080 - -spring: - datasource: - url: jdbc:postgresql://localhost:5432/postgres - username: postgres - password: postgres - initialization-mode: always - jpa: - hibernate: - ddl-auto: create #update - properties: - hibernate: - enable_lazy_load_no_trans: true - jdbc: - lob: - non_contextual_creation: true - security: - user: - password: pass - name: user - -security: - oauth2: - resource: -# user-info-uri: http://localhost:8081/userinfo -# token-info-uri: http://localhost:8081/oauth/check_token - jwk: - key-set-uri: http://localhost:8081/.well-known/jwks.json - -springdoc: - swagger-ui: - path: /swagger-ui.html - diff --git a/src/main/resources/db/migration/data.sql b/src/main/resources/db/migration/data.sql new file mode 100644 index 0000000..b6f7ba9 --- /dev/null +++ b/src/main/resources/db/migration/data.sql @@ -0,0 +1,6 @@ +INSERT INTO user_entity VALUES ('6f6f9111-8d88-4b65-8dca-7b14c0e354ae', 'admin@mail', 'admin', '$2a$10$hoLdIpsbbYlOts0zIqIH5uucveGPIwhs4whXIUanKm2ISEaOjhkIG'); +INSERT INTO user_entity_roles VALUES ('6f6f9111-8d88-4b65-8dca-7b14c0e354ae', 'MEMBER'); +INSERT INTO user_entity_roles VALUES ('6f6f9111-8d88-4b65-8dca-7b14c0e354ae', 'ADMIN'); + +INSERT INTO user_entity VALUES ('92cc4758-4ed6-4159-9c69-66fd8f6eab35', 'member@mail', 'member', '$2a$10$hoLdIpsbbYlOts0zIqIH5uucveGPIwhs4whXIUanKm2ISEaOjhkIG'); +INSERT INTO user_entity_roles VALUES ('92cc4758-4ed6-4159-9c69-66fd8f6eab35', 'MEMBER'); From 9b7f80e5df08424eaefb3eb58984b01f3392a276 Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Mon, 15 Jun 2020 01:49:34 +0200 Subject: [PATCH 03/68] CHANGED Models --- docs/dev/index.md | 5 +- .../api/config/ResourceServerConfig.java | 2 +- .../api/config/SetupDataLoader.java | 153 ------------------ .../api/entities/candidate/Candidate.java | 10 +- .../api/entities/user/UserEntity.java | 2 + .../controller/PatternLanguageController.java | 12 ++ .../api/rest/controller/UserController.java | 2 +- .../rest/model/candidate/CandidateModel.java | 2 +- .../shared/PatternLanguageSchemaModel.java | 29 ++++ .../rest/model/shared/PatternSchemaModel.java | 31 ++++ 10 files changed, 84 insertions(+), 164 deletions(-) delete mode 100644 src/main/java/com/patternpedia/api/config/SetupDataLoader.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/PatternLanguageSchemaModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/PatternSchemaModel.java diff --git a/docs/dev/index.md b/docs/dev/index.md index fed1006..16eccda 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -3,7 +3,6 @@ This document provides an index to all development guidelines and background inf - [ADR](/adr) - Information on Architectural decisions can be found here ## Quick Develop - 1. Clone the repository `git clone https://github.com/PatternPedia/pattern-pedia-views-backend.git`. 2. Build the repository `mvn package -DskipTests` (skiping the tests for a faster build), Java 8 required. 3. Clone the repository `git clone https://github.com/PatternPedia/pattern-pedia-views-ui.git`. diff --git a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java index 0e5c515..76e7901 100644 --- a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java +++ b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java @@ -36,7 +36,7 @@ public void configure(HttpSecurity http) throws Exception { // .antMatchers(HttpMethod.GET, "/**").permitAll() // .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") // .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") -// .antMatchers(HttpMethod.DELETE, "/**").hasAuthority("ADMIN") +// .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('delete')") // .anyRequest().authenticated() //END::Comment for local development with authorization // START::Uncomment for local development without authorization diff --git a/src/main/java/com/patternpedia/api/config/SetupDataLoader.java b/src/main/java/com/patternpedia/api/config/SetupDataLoader.java deleted file mode 100644 index 7697b9c..0000000 --- a/src/main/java/com/patternpedia/api/config/SetupDataLoader.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.patternpedia.api.config; - -import com.patternpedia.api.entities.user.role.PrivilegeConstant; -import com.patternpedia.api.entities.user.role.RoleConstant; -import com.patternpedia.api.entities.user.role.Privilege; -import com.patternpedia.api.entities.user.role.Role; -import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.repositories.PrivilegeRepository; -import com.patternpedia.api.repositories.RoleRepository; -import com.patternpedia.api.repositories.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Component; - -import javax.transaction.Transactional; -import java.util.Arrays; -import java.util.Collection; - -@Component -public class SetupDataLoader implements ApplicationListener { - - boolean alreadySetup = false; - - @Autowired - private UserRepository userRepository; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private PrivilegeRepository privilegeRepository; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Override - @Transactional - public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { - if (alreadySetup) - return; - - /** Privileges */ - /** USER */ - Privilege readUserAllPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.READ_USER_ALL); - Privilege readUserPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.READ_USER); - Privilege createUserPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.CREATE_USER); - Privilege updateUserPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.UPDATE_USER); - Privilege deleteUserPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.DELETE_USER); - /** ISSUE */ - Privilege readIssuePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.READ_ISSUE); - Privilege createIssuePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.CREATE_ISSUE); - Privilege updateIssuePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.UPDATE_ISSUE); - Privilege deleteIssuePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.DELETE_ISSUE); - /** CANDIDATE */ - Privilege readCandidatePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.READ_CANDIDATE); - Privilege createCandidatePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.CREATE_CANDIDATE); - Privilege updateCandidatePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.UPDATE_CANDIDATE); - Privilege deleteCandidatePrivilege = createPrivilegeIfNotFound(PrivilegeConstant.DELETE_CANDIDATE); - /** ROLE */ - String UPDATE_ROLE = "UPDATE_ROLE"; - /** DEVELOPER */ - Privilege developerPrivilege = createPrivilegeIfNotFound(PrivilegeConstant.DEVELOPER); - - /** Roles */ - createRoleIfNotFound(RoleConstant.MEMBER, Arrays.asList( - //USER - updateUserPrivilege, readUserPrivilege, - //ISSUES - readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege - )); - createRoleIfNotFound(RoleConstant.EXPERT, Arrays.asList( - //USER - updateUserPrivilege, - //ISSUES - readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, - //CANDIDATE - createCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege - )); - createRoleIfNotFound(RoleConstant.LIBRARIAN, Arrays.asList( - //USER - readUserAllPrivilege, readUserPrivilege, createUserPrivilege, updateUserPrivilege, deleteUserPrivilege, - //ISSUES - readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, - //CANDIDATE - createCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege - )); - createRoleIfNotFound(RoleConstant.ADMIN, Arrays.asList( - //USER - readUserAllPrivilege, readUserPrivilege, createUserPrivilege, updateUserPrivilege, deleteUserPrivilege, - //ISSUES - readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, - //CANDIDATE - createCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege, - //DEVELOPER - developerPrivilege - )); - createRoleIfNotFound(RoleConstant.DEVELOPER, Arrays.asList( - //USER - readUserAllPrivilege, readUserPrivilege, createUserPrivilege, updateUserPrivilege, deleteUserPrivilege, - //ISSUES - readIssuePrivilege, createIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, - //CANDIDATE - createCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege, - //DEVELOPER - developerPrivilege - )); - - createUser(new UserEntity("MEMBER", "member@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.MEMBER))); - createUser(new UserEntity("MEMBER_1", "member1@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.MEMBER))); - createUser(new UserEntity("EXPERT", "expert@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.EXPERT))); - createUser(new UserEntity("LIBRARIAN", "librarian@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.LIBRARIAN))); - createUser(new UserEntity("ADMIN", "admin@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.ADMIN))); - createUser(new UserEntity("DEVELOPER", "developer@mail", passwordEncoder.encode("pass"), roleRepository.findByName(RoleConstant.DEVELOPER))); - - - - alreadySetup = true; - } - - @Transactional - void createUser(UserEntity userEntity) { - UserEntity user = userRepository.findByEmail(userEntity.getEmail()); - if (user == null) - userRepository.save(userEntity); - } - - @Transactional - Role createRoleIfNotFound(String name, Collection privileges) { - - Role role = roleRepository.findByName(name); - if (role == null) { - role = new Role(name); - role.setPrivileges(privileges); - roleRepository.save(role); - } - return role; - } - - @Transactional - Privilege createPrivilegeIfNotFound(String name) { - - Privilege privilege = privilegeRepository.findByName(name); - if (privilege == null) { - privilege = new Privilege(name); - privilegeRepository.save(privilege); - } - return privilege; - } - - -} diff --git a/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java b/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java index 1a32547..cd4ff31 100644 --- a/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java +++ b/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java @@ -11,8 +11,10 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; +import org.hibernate.annotations.Type; import javax.persistence.*; +import javax.validation.constraints.NotNull; import java.util.*; @Entity @@ -28,10 +30,10 @@ public class Candidate extends EntityWithURI { @ManyToOne private PatternLanguage patternLanguage; -// @Type(type = "jsonb") -// @Column(columnDefinition = "jsonb") -// @NotNull - private String content; + @Type(type = "jsonb") + @Column(columnDefinition = "jsonb") + @NotNull + private Object content; private String version = "0.1.0"; diff --git a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java b/src/main/java/com/patternpedia/api/entities/user/UserEntity.java index 0cd8968..627b810 100644 --- a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java +++ b/src/main/java/com/patternpedia/api/entities/user/UserEntity.java @@ -41,6 +41,8 @@ public class UserEntity implements Serializable{ @Column(nullable = false, unique = true) private String email; + @NaturalId(mutable = true) + @Column(nullable = false, unique = true) private String name; @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) diff --git a/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java b/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java index ac6dccf..024a9d7 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java @@ -12,6 +12,8 @@ import com.patternpedia.api.entities.PatternSchema; import com.patternpedia.api.rest.model.PatternLanguageGraphModel; import com.patternpedia.api.rest.model.PatternLanguageModel; +import com.patternpedia.api.rest.model.shared.PatternLanguageSchemaModel; +import com.patternpedia.api.rest.model.shared.PatternSchemaModel; import com.patternpedia.api.service.PatternLanguageService; import com.fasterxml.jackson.databind.ObjectMapper; @@ -126,6 +128,16 @@ ResponseEntity deletePatternLanguage(@PathVariable UUID patternLanguageId) { return ResponseEntity.noContent().build(); } + @GetMapping(value = "/patternSchemas") + CollectionModel> getAllPatternLanguagesWithSchema() { + List> patternLanguages = this.patternLanguageService.getPatternLanguages() + .stream() + .map(patternLanguage -> new EntityModel<>(new PatternLanguageSchemaModel(patternLanguage))) + .collect(Collectors.toList()); + + return new CollectionModel<>(patternLanguages); + } + @GetMapping(value = "/{patternLanguageId}/patternSchema") EntityModel getPatternSchema(@PathVariable UUID patternLanguageId) { PatternSchema schema = this.patternLanguageService.getPatternSchemaByPatternLanguageId(patternLanguageId); diff --git a/src/main/java/com/patternpedia/api/rest/controller/UserController.java b/src/main/java/com/patternpedia/api/rest/controller/UserController.java index ef8a878..da20459 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/UserController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/UserController.java @@ -41,7 +41,7 @@ public UserController( * GET Methods */ @GetMapping(value = "") -// @PreAuthorize(value = "hasAuthority('ADMIN')") + @PreAuthorize(value = "hasAuthority('READ_USER_ALL')") CollectionModel> getAll() { List> users = this.userService.getAllUsers() .stream() diff --git a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java index 43df7ab..f5fb376 100644 --- a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java @@ -27,7 +27,7 @@ public class CandidateModel { private String iconUrl; private UUID patternLanguageId; private String patternLanguageName; - private String content; + private Object content; private String version; // RESPONSE // RESPONSE diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/PatternLanguageSchemaModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/PatternLanguageSchemaModel.java new file mode 100644 index 0000000..d8f54db --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/PatternLanguageSchemaModel.java @@ -0,0 +1,29 @@ +package com.patternpedia.api.rest.model.shared; + +import com.patternpedia.api.entities.PatternLanguage; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.*; +import java.util.stream.Collectors; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class PatternLanguageSchemaModel { + + private UUID patternLanguageId; + private String patternLanguageName; + Collection patternSchema = new ArrayList<>(); + + public PatternLanguageSchemaModel(PatternLanguage patternLanguage) { + this.patternLanguageId = patternLanguage.getId(); + this.patternLanguageName = patternLanguage.getName(); + this.patternSchema = patternLanguage.getPatternSchema().getPatternSectionSchemas().stream().map(patternSectionSchema -> new PatternSchemaModel(patternSectionSchema)) + .collect(Collectors.toList()) + .stream().sorted(Comparator.comparing(PatternSchemaModel::getPosition)). + collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/PatternSchemaModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/PatternSchemaModel.java new file mode 100644 index 0000000..59439b4 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/PatternSchemaModel.java @@ -0,0 +1,31 @@ +package com.patternpedia.api.rest.model.shared; + +import com.patternpedia.api.entities.PatternSection; +import com.patternpedia.api.entities.PatternSectionSchema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class PatternSchemaModel implements Comparable { + + private String label; + private String name; + private String type; + private Integer position; + + public PatternSchemaModel(PatternSectionSchema patternSectionSchema) { + this.label = patternSectionSchema.getLabel(); + this.name = patternSectionSchema.getName(); + this.type = patternSectionSchema.getType(); + this.position = patternSectionSchema.getPosition(); + } + + public int compareTo(PatternSchemaModel o) + { + return Integer.compare(this.position, o.position); + } + +} From 9a0f49fb72411fe4884f95bb4d08e732f5c79258 Mon Sep 17 00:00:00 2001 From: lqwert <59832601+lqwert@users.noreply.github.com> Date: Mon, 15 Jun 2020 01:57:21 +0200 Subject: [PATCH 04/68] Update index.md --- docs/dev/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/dev/index.md b/docs/dev/index.md index 16eccda..9460beb 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -23,6 +23,9 @@ This document provides an index to all development guidelines and background inf #### IntelliJ 3. [Follow PatternPediaAPI from Step 5 pls](#step5) +#### Turn On/Off +Comment the marked lines in the following file to turn on/off [Security Config file](https://github.com/PatternPedia/pattern-pedia-views-backend/blob/ba-meyer-master/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java). An easier way will be added in future realease. + #### Default User During development default users are - Admin: name: `admin@mail` password: `pass` From 46f5f57e5d8db095ff7b0c06012964195ae1a7cf Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Wed, 1 Jul 2020 12:26:17 +0200 Subject: [PATCH 05/68] Changed CandidateService --- .../patternpedia/api/service/CandidateServiceImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java index 5470c67..0594d33 100644 --- a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java @@ -9,6 +9,7 @@ import com.patternpedia.api.entities.user.UserEntity; import com.patternpedia.api.repositories.*; import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; +import com.patternpedia.api.rest.model.shared.AuthorModel; import com.patternpedia.api.rest.model.shared.CommentModel; import com.patternpedia.api.util.RatingHelper; import org.slf4j.Logger; @@ -76,7 +77,14 @@ public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UU // ADD authors Candidate newCandidate = this.candidateRepository.save(candidate); - newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(userId), AuthorConstant.OWNER)); + if (candidateModelRequest.getAuthors() != null) { + for (AuthorModel authorModel : candidateModelRequest.getAuthors()) { + newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(authorModel.getUserId()), authorModel.getAuthorRole())); + } + } else { + newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(userId), AuthorConstant.OWNER)); + } + // ADD pattern language if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) From 35dfccf25d9d41581eed92d7b53ef03700e6cd74 Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Tue, 7 Jul 2020 00:16:35 +0200 Subject: [PATCH 06/68] CHANGED interface, DELETED unused code --- .../api/config/ResourceServerConfig.java | 22 ++++++------- .../api/entities/user/UserEntity.java | 1 - .../entities/user/role/PrivilegeConstant.java | 32 +++++++++---------- .../api/entities/user/role/RoleConstant.java | 15 +++++---- .../api/rest/controller/AuthorController.java | 2 -- .../api/rest/controller/IssueController.java | 3 -- .../api/rest/model/user/RoleModel.java | 2 -- .../api/service/AuthorService.java | 2 -- .../api/service/CandidateServiceImpl.java | 3 -- 9 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java index 76e7901..32b8308 100644 --- a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java +++ b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java @@ -19,9 +19,9 @@ @Configuration @EnableResourceServer -// START::Comment for local development with authorization -//@EnableGlobalMethodSecurity(prePostEnabled = true) -// END::Comment for local development with authorization +// START::Comment for local development without authorization +@EnableGlobalMethodSecurity(prePostEnabled = true) +// END::Comment for local development without authorization class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override @@ -33,15 +33,15 @@ public void configure(HttpSecurity http) throws Exception { .authorizeRequests() .antMatchers("/swagger-ui/**").permitAll() // START::Comment for local development with authorization -// .antMatchers(HttpMethod.GET, "/**").permitAll() -// .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") -// .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") -// .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('delete')") -// .anyRequest().authenticated() - //END::Comment for local development with authorization + .antMatchers(HttpMethod.GET, "/**").permitAll() + .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") + .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") + .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('delete')") + .anyRequest().authenticated() + //END::Comment for local development without authorization // START::Uncomment for local development without authorization - .anyRequest().permitAll() - // END::Uncomment for local development without authorization +// .anyRequest().permitAll() + // END::Uncomment for local development withoutout authorization .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); diff --git a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java b/src/main/java/com/patternpedia/api/entities/user/UserEntity.java index 627b810..363dedf 100644 --- a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java +++ b/src/main/java/com/patternpedia/api/entities/user/UserEntity.java @@ -24,7 +24,6 @@ @Entity @Data @NoArgsConstructor -//@NamedQuery(name = "UserEntity.findAll", query="select u from UserEntity u order by u.role.name") public class UserEntity implements Serializable{ /** User fields*/ diff --git a/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java b/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java index 1d86fc0..cb56865 100644 --- a/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java +++ b/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java @@ -1,24 +1,24 @@ package com.patternpedia.api.entities.user.role; -public interface PrivilegeConstant { +public class PrivilegeConstant { /** USER */ - String READ_USER_ALL = "READ_USER_ALL"; - String READ_USER = "READ_USER"; - String CREATE_USER = "CREATE_USER"; - String UPDATE_USER = "UPDATE_USER"; - String DELETE_USER = "DELETE_USER"; + public static final String READ_USER_ALL = "READ_USER_ALL"; + public static final String READ_USER = "READ_USER"; + public static final String CREATE_USER = "CREATE_USER"; + public static final String UPDATE_USER = "UPDATE_USER"; + public static final String DELETE_USER = "DELETE_USER"; /** ISSUE */ - String READ_ISSUE = "READ_ISSUE"; - String CREATE_ISSUE = "CREATE_ISSUE"; - String UPDATE_ISSUE = "UPDATE_ISSUE"; - String DELETE_ISSUE = "DELETE_ISSUE"; + public static final String READ_ISSUE = "READ_ISSUE"; + public static final String CREATE_ISSUE = "CREATE_ISSUE"; + public static final String UPDATE_ISSUE = "UPDATE_ISSUE"; + public static final String DELETE_ISSUE = "DELETE_ISSUE"; /** CANDIDATE */ - String READ_CANDIDATE = "READ_CANDIDATE"; - String CREATE_CANDIDATE = "CREATE_CANDIDATE"; - String UPDATE_CANDIDATE = "UPDATE_CANDIDATE"; - String DELETE_CANDIDATE = "DELETE_CANDIDATE"; + public static final String READ_CANDIDATE = "READ_CANDIDATE"; + public static final String CREATE_CANDIDATE = "CREATE_CANDIDATE"; + public static final String UPDATE_CANDIDATE = "UPDATE_CANDIDATE"; + public static final String DELETE_CANDIDATE = "DELETE_CANDIDATE"; /** ROLE */ - String UPDATE_ROLE = "UPDATE_ROLE"; + public static final String UPDATE_ROLE = "UPDATE_ROLE"; /** DEVELOPER */ - String DEVELOPER = "DEVELOPER"; + public static final String DEVELOPER = "DEVELOPER"; } diff --git a/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java b/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java index 5b7e4d5..dbdadbd 100644 --- a/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java +++ b/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java @@ -1,10 +1,11 @@ package com.patternpedia.api.entities.user.role; -public interface RoleConstant { - String MEMBER = "MEMBER"; -// String AUTHOR = "AUTHOR"; - String EXPERT = "EXPERT"; - String LIBRARIAN = "LIBRARIAN"; - String ADMIN = "ADMIN"; - String DEVELOPER = "DEVELOPER"; +public class RoleConstant { + public static final String MEMBER = "MEMBER"; + // String AUTHOR = "AUTHOR"; + public static final String EXPERT = "EXPERT"; + public static final String LIBRARIAN = "LIBRARIAN"; + public static final String ADMIN = "ADMIN"; + public static final String DEVELOPER = "DEVELOPER"; } + diff --git a/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java b/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java index c3b7db3..b41bbc5 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java @@ -38,7 +38,6 @@ public AuthorController( * GET Methods */ @GetMapping(value = "") -// @PreAuthorize(value = "hasAuthority('ADMIN')") CollectionModel> getAll() { List> authors = this.userService.getAllUsers() .stream() @@ -48,7 +47,6 @@ CollectionModel> getAll() { } @GetMapping(value = "/roles") -// @PreAuthorize(value = "hasAuthority('ADMIN')") String[] getAllRoles() { return new String[]{AuthorConstant.MEMBER, AuthorConstant.MAINTAINER, AuthorConstant.OWNER}; } diff --git a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java b/src/main/java/com/patternpedia/api/rest/controller/IssueController.java index 984842a..58f67bb 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/IssueController.java @@ -74,7 +74,6 @@ ResponseEntity> newIssue(@RequestBody IssueModelRequest } @PostMapping(value = "/{issueId}/comments") -// @PreAuthorize(value = "#oauth2.hasScope('write')") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueComment(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); @@ -97,14 +96,12 @@ ResponseEntity> putIssueCommentRating(@PathVariable UU * DELETE Methods */ @DeleteMapping(value = "/{issueId}") -// @PreAuthorize(value = "#oauth2.hasScope('de')") ResponseEntity deleteIssue(@PathVariable UUID issueId) { this.issueService.deleteIssue(issueId); return ResponseEntity.noContent().build(); } @DeleteMapping(value = "/{issueId}/comments/{issueCommentId}") -// @PreAuthorize(value = "#oauth2.hasScope('de')") ResponseEntity deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal) { return this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName())); } diff --git a/src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java b/src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java index bb9e035..cb89209 100644 --- a/src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java @@ -16,13 +16,11 @@ public class RoleModel { private UUID id; private String name; -// private Collection privileges; private Collection privileges; public RoleModel (Role role) { this.id = role.getId(); this.name = role.getName(); -// this.privileges = role.getPrivileges().stream().map(privilege -> new PrivilegeModel(privilege)).collect(Collectors.toList()); this.privileges = role.getPrivileges().stream().map(privilege -> privilege.getName()).collect(Collectors.toList()); } diff --git a/src/main/java/com/patternpedia/api/service/AuthorService.java b/src/main/java/com/patternpedia/api/service/AuthorService.java index 451682c..51bf4bb 100644 --- a/src/main/java/com/patternpedia/api/service/AuthorService.java +++ b/src/main/java/com/patternpedia/api/service/AuthorService.java @@ -19,6 +19,4 @@ public interface AuthorService { CandidateAuthor saveCandidateAuthor(UUID userId, UUID candidateId, AuthorModelRequest authorModelRequest); void deleteCandidateAuthor(UUID userId, UUID candidateId); - -// Candidate updateCandidateAuthor(UUID candidateId, AuthorModelRequest authorModelRequest); } diff --git a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java index 0594d33..2c8e474 100644 --- a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java @@ -72,9 +72,6 @@ public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UU if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); - -// throw new ResourceNotFoundException(String.format("Pattern Language %s does not exist", candidateModelRequest.getPatternLanguageId())); - // ADD authors Candidate newCandidate = this.candidateRepository.save(candidate); if (candidateModelRequest.getAuthors() != null) { From 4bade8c3836c35d46c9b4818895a4ccfcfda02c6 Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Tue, 7 Jul 2020 00:47:04 +0200 Subject: [PATCH 07/68] CHANGED index --- docs/dev/index.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/dev/index.md b/docs/dev/index.md index 9460beb..0b3f605 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -4,6 +4,11 @@ This document provides an index to all development guidelines and background inf ## Quick Develop ### PatternPediaAuth +PatternPediaAuth is a Spring Boot Authentication Server and it's main purpose is to give PatternPediaAPI user management capabilities. +This is achieved through using the OAuth 2.0 Authentication Code Flow, additionally new users can create accounts. +It runs on Port 8081 + +### Development 1. Clone the repository `git clone https://github.com/PatternPedia/pattern-pedia-auth.git`. 2. Navigate to repository directory `cd pattern-pedia-auth/`. 2. Build the repository @@ -23,8 +28,10 @@ This document provides an index to all development guidelines and background inf #### IntelliJ 3. [Follow PatternPediaAPI from Step 5 pls](#step5) -#### Turn On/Off -Comment the marked lines in the following file to turn on/off [Security Config file](https://github.com/PatternPedia/pattern-pedia-views-backend/blob/ba-meyer-master/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java). An easier way will be added in future realease. +#### Turn authentication on/off for PatternPediaAPI +If you don't need the capabilities of the PatternPediaAuth server during development. You can follow the instructions in the following file +[Security Config file](https://github.com/PatternPedia/pattern-pedia-views-backend/blob/ba-meyer-master/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java) +to turn those off or on. An easier way will be added in future realease. #### Default User During development default users are From 679fe49b06605016c73b9cbf5c8b1673a310fa29 Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Tue, 7 Jul 2020 12:26:18 +0200 Subject: [PATCH 08/68] CHANGED userServiceImp --- src/main/java/com/patternpedia/api/service/UserServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/patternpedia/api/service/UserServiceImpl.java b/src/main/java/com/patternpedia/api/service/UserServiceImpl.java index 8e03e95..4022244 100644 --- a/src/main/java/com/patternpedia/api/service/UserServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/UserServiceImpl.java @@ -47,7 +47,7 @@ public UserEntity createUser(UserModelRequest userModelRequest) { throw new RuntimeException("User to update is null!"); // DEFAULT password if (userModelRequest.getPassword() == null) - userModelRequest.setPassword("pass"); + throw new RuntimeException("Password is null"); UserEntity user = new UserEntity(userModelRequest, passwordEncoder.encode(userModelRequest.getPassword())); if (this.roleRepository.findByName(userModelRequest.getRole()) != null) { From 351ee840d450f68a50242d9fbf367a89ee7b398f Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Mon, 5 Oct 2020 13:29:06 +0200 Subject: [PATCH 09/68] ADDED features --- src/main/java/com/patternpedia/api/.DS_Store | Bin 0 -> 6148 bytes .../patternpedia/api/config/Authority.java | 43 +++++ .../api/entities/candidate/Candidate.java | 6 + .../entities/candidate/CandidateRating.java | 19 +- .../candidate/evidence/CandidateEvidence.java | 59 ++++++ .../evidence/CandidateEvidenceRating.java | 67 +++++++ .../api/entities/issue/Issue.java | 5 + .../issue/evidence/IssueEvidence.java | 54 ++++++ .../issue/evidence/IssueEvidenceRating.java | 69 +++++++ .../api/entities/shared/Evidence.java | 53 ++++++ .../api/entities/user/UserEntity.java | 14 +- .../api/entities/user/role/Privilege.java | 2 + .../entities/user/role/PrivilegeConstant.java | 55 ++++-- .../api/entities/user/role/Role.java | 8 + .../CandidateEvidenceRatingRepository.java | 10 + .../CandidateEvidenceRepository.java | 9 + .../CandidateRatingRepository.java | 5 +- .../IssueEvidenceRatingRepository.java | 10 + .../repositories/IssueEvidenceRepository.java | 11 ++ .../rest/controller/CandidateController.java | 42 ++++- .../api/rest/controller/IssueController.java | 17 ++ .../api/rest/controller/RatingController.java | 19 +- .../api/rest/controller/UserController.java | 7 +- .../rest/model/candidate/CandidateModel.java | 22 +-- .../candidate/CandidateModelRequest.java | 2 + .../api/rest/model/issue/IssueModel.java | 3 + .../api/rest/model/shared/EvidenceModel.java | 72 ++++++++ .../api/rest/model/shared/RatingModel.java | 24 ++- .../model/shared/RatingModelMultiRequest.java | 13 ++ .../api/rest/model/shared/RatingType.java | 7 + .../api/rest/model/user/UserModel.java | 19 +- .../api/service/CandidateService.java | 13 +- .../api/service/CandidateServiceImpl.java | 174 ++++++++++++++---- .../api/service/IssueService.java | 15 ++ .../api/service/IssueServiceImpl.java | 74 +++++++- .../api/service/RatingService.java | 11 +- .../api/service/RatingServiceImpl.java | 87 ++++++++- 37 files changed, 1012 insertions(+), 108 deletions(-) create mode 100644 src/main/java/com/patternpedia/api/.DS_Store create mode 100644 src/main/java/com/patternpedia/api/config/Authority.java create mode 100644 src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidence.java create mode 100644 src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidenceRating.java create mode 100644 src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidence.java create mode 100644 src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidenceRating.java create mode 100644 src/main/java/com/patternpedia/api/entities/shared/Evidence.java create mode 100644 src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRatingRepository.java create mode 100644 src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRepository.java create mode 100644 src/main/java/com/patternpedia/api/repositories/IssueEvidenceRatingRepository.java create mode 100644 src/main/java/com/patternpedia/api/repositories/IssueEvidenceRepository.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/RatingModelMultiRequest.java create mode 100644 src/main/java/com/patternpedia/api/rest/model/shared/RatingType.java diff --git a/src/main/java/com/patternpedia/api/.DS_Store b/src/main/java/com/patternpedia/api/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..12db7cf64da79dd932ccfccbbd901c4eda211125 GIT binary patch literal 6148 zcmeHKI|>3Z5S>vG!N$@uSMUZw^aNf&P!vH{5VYRPb9pr1d>UQtw2?P3dC6p6LSC`6 zBO*G#Y-b`95gEY^B@zm@)+3y3!9m+;d(#Yi0p zwti-h{ zq5pp-aYY5Fz+Wk#gT-nw$CI+Qb{=Q7w!qhL%elkNFn0c7o_bQ`6`Nzf VCbof2N8IT^{tTEdG%E0G1s?X~6^#G@ literal 0 HcmV?d00001 diff --git a/src/main/java/com/patternpedia/api/config/Authority.java b/src/main/java/com/patternpedia/api/config/Authority.java new file mode 100644 index 0000000..1393a27 --- /dev/null +++ b/src/main/java/com/patternpedia/api/config/Authority.java @@ -0,0 +1,43 @@ +package com.patternpedia.api.config; + +public interface Authority { + /** ISSUE */ + String ISSUE_READ = "hasAuthority('ISSUE_READ')"; + String ISSUE_CREATE = "hasAuthority(ISSUE_CREATE')"; + String ISSUE_EDIT = "hasAuthority('ISSUE_EDIT')"; + String ISSUE_DELETE = "hasAuthority('ISSUE_DELETE')"; + String ISSUE_READ_ALL = "hasAuthority('ISSUE_READ_ALL')"; + String ISSUE_EDIT_ALL = "hasAuthority('ISSUE_EDIT_ALL')"; + String ISSUE_DELETE_ALL = "hasAuthority('ISSUE_DELETE_ALL')"; + String ISSUE_TO_PATTERN_CANDIDATE = "hasAuthority('ISSUE_TO_PATTERN_CANDIDATE')"; + /** CANDIDATE */ + String PATTERN_CANDIDATE_READ = "hasAuthority('PATTERN_CANDIDATE_READ')"; + String PATTERN_CANDIDATE_CREATE = "hasAuthority('PATTERN_CANDIDATE_CREATE')"; + String PATTERN_CANDIDATE_EDIT = "hasAuthority('PATTERN_CANDIDATE_EDIT')"; + String PATTERN_CANDIDATE_DELETE = "hasAuthority('PATTERN_CANDIDATE_DELETE')"; + String PATTERN_CANDIDATE_READ_ALL = "hasAuthority('PATTERN_CANDIDATE_READ_ALL')"; + String PATTERN_CANDIDATE_EDIT_ALL = "hasAuthority('PATTERN_CANDIDATE_EDIT_ALL')"; + String PATTERN_CANDIDATE_DELETE_ALL = "hasAuthority('PATTERN_CANDIDATE_DELETE_ALL')"; + String PATTERN_CANDIDATE_TO_PATTERN = "hasAuthority('PATTERN_CANDIDATE_TO_PATTERN')"; + /** Pattern */ + String APPROVED_PATTERN_READ = "hasAuthority(APPROVED_PATTERN_READ')"; + String APPROVED_PATTERN_CREATE = "hasAuthority('APPROVED_PATTERN_CREATE')"; + String APPROVED_PATTERN_EDIT = "hasAuthority('APPROVED_PATTERN_EDIT')"; + String APPROVED_PATTERN_DELETE = "hasAuthority('APPROVED_PATTERN_DELETE')"; + String APPROVED_PATTERN_READ_ALL = "hasAuthority('APPROVED_PATTERN_READ_ALL')"; + String APPROVED_PATTERN_EDIT_ALL = "hasAuthority('APPROVED_PATTERN_EDIT_ALL')"; + String APPROVED_PATTERN_DELETE_ALL = "hasAuthority('APPROVED_PATTERN_DELETE_ALL')"; + /** USER */ + String USER_READ = "hasAuthority('USER_READ')"; + String USER_CREATE = "hasAuthority('USER_CREATE')"; + String USER_EDIT = "hasAuthority('USER_EDIT')"; + String USER_DELETE = "hasAuthority('USER_DELETE')"; + String USER_READ_ALL = "hasAuthority('USER_READ_ALL')"; + String USER_EDIT_ALL = "hasAuthority('USER_EDIT_ALL')"; + String USER_DELETE_ALL = "hasAuthority('USER_DELETE_ALL')"; + String USER_ALL = "hasAuthority('USER_ALL')"; + /** GENERAL */ + String COMMENT = "hasAuthority('COMMENT')"; + String VOTE = "hasAuthority('VOTE')"; + String EVIDENCE = "hasAuthority('EVIDENCE')"; +} diff --git a/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java b/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java index cd4ff31..11e03a2 100644 --- a/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java +++ b/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java @@ -6,6 +6,8 @@ import com.patternpedia.api.entities.PatternLanguage; import com.patternpedia.api.entities.candidate.author.CandidateAuthor; import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; import lombok.Data; import lombok.EqualsAndHashCode; @@ -49,6 +51,10 @@ public class Candidate extends EntityWithURI { @OneToMany(mappedBy = "candidate", cascade = CascadeType.ALL, orphanRemoval = true) private List comments = new ArrayList<>(); + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @OneToMany(mappedBy = "candidate", cascade = CascadeType.ALL, orphanRemoval = true) + private List evidences = new ArrayList<>(); + public Candidate (CandidateModelRequest candidateModelRequest) { // this.setId(candidateModel.getId()); this.setUri(candidateModelRequest.getUri()); diff --git a/src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java b/src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java index 9077be9..7baf5e3 100644 --- a/src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java +++ b/src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java @@ -12,6 +12,7 @@ import javax.persistence.MapsId; import java.util.Objects; + @Entity @Data @NoArgsConstructor @@ -31,7 +32,9 @@ public class CandidateRating { @EqualsAndHashCode.Include private UserEntity user; - private int rating; + private int readability; + private int understandability; + private int appropriateness; public CandidateRating(Candidate candidate, UserEntity user) { this.candidate = candidate; @@ -39,14 +42,16 @@ public CandidateRating(Candidate candidate, UserEntity user) { this.id = new CompositeKey(candidate.getId(), user.getId()); } - public CandidateRating(Candidate candidate, UserEntity user, int rating) { + public CandidateRating(Candidate candidate, UserEntity user, int readability, int understandability, int appropriateness) { this(candidate, user); - this.rating = rating; + this.readability = readability; + this.understandability = understandability; + this.appropriateness = appropriateness; } @Override public String toString() { - return this.id.toString() + this.rating; + return this.id.toString() + this.readability; } @Override @@ -56,11 +61,13 @@ public boolean equals(Object o) { CandidateRating that = (CandidateRating) o; return Objects.equals(candidate.getName(), that.candidate.getName()) && Objects.equals(user.getName(), that.user.getName()) && - Objects.equals(rating, that.rating); + Objects.equals(readability, that.readability) && + Objects.equals(understandability, that.understandability) && + Objects.equals(appropriateness, that.appropriateness); } @Override public int hashCode() { - return Objects.hash(candidate.getName(), user.getName(), rating); + return Objects.hash(candidate.getName(), user.getName(), readability); } } diff --git a/src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidence.java b/src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidence.java new file mode 100644 index 0000000..394bb43 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidence.java @@ -0,0 +1,59 @@ +package com.patternpedia.api.entities.candidate.evidence; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; +import com.patternpedia.api.entities.shared.Evidence; +import com.patternpedia.api.entities.user.UserEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class CandidateEvidence extends Evidence implements Serializable { + + @JsonIgnore + @ToString.Exclude + @ManyToOne + private Candidate candidate; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @ToString.Exclude + @ManyToOne + private UserEntity user; + + @JsonIgnore + @OneToMany(mappedBy = "candidateEvidence", cascade = CascadeType.ALL, orphanRemoval = true) + private List userRating = new ArrayList<>(); + + public CandidateEvidence(String title, String context, String type, Boolean supporting, String source, Candidate candidate, UserEntity user) { + super(title, context, type, supporting, source); + this.candidate = candidate; + this.user = user; + } + + public CandidateEvidence(IssueEvidence issueEvidence, Candidate candidate, UserEntity user) { + this(issueEvidence.getTitle(), issueEvidence.getContext(), issueEvidence.getType(), issueEvidence.getSupporting(), issueEvidence.getSource(), candidate, user); + } + + public void updateEvidence(String title, String context, String type, Boolean supporting, String source) { + this.setTitle(title); + this.setContext(context); + this.setType(type); + this.setSupporting(supporting); + this.setSource(source); + } +} \ No newline at end of file diff --git a/src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidenceRating.java b/src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidenceRating.java new file mode 100644 index 0000000..0f803c0 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidenceRating.java @@ -0,0 +1,67 @@ +package com.patternpedia.api.entities.candidate.evidence; + +import com.patternpedia.api.entities.shared.CompositeKey; +import com.patternpedia.api.entities.user.UserEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import java.util.Objects; + +@Entity +@Data +@NoArgsConstructor +public class CandidateEvidenceRating { + + @EmbeddedId + @EqualsAndHashCode.Include + private CompositeKey id; + + @ManyToOne + @MapsId("entityId") + @EqualsAndHashCode.Include + private CandidateEvidence candidateEvidence; + + @ManyToOne + @MapsId("userId") + @EqualsAndHashCode.Include + private UserEntity user; + + private int rating; + + public CandidateEvidenceRating(CandidateEvidence candidateEvidence, UserEntity user) { + this.candidateEvidence = candidateEvidence; + this.user = user; + this.id = new CompositeKey(candidateEvidence.getId(), user.getId()); + } + + public CandidateEvidenceRating(CandidateEvidence candidateEvidence, UserEntity user, int rating) { + this(candidateEvidence, user); + this.rating = rating; + } + + @Override + public String toString() { + return this.id.toString() + this.rating; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CandidateEvidenceRating)) return false; + CandidateEvidenceRating that = (CandidateEvidenceRating) o; + return Objects.equals(candidateEvidence.getTitle(), that.candidateEvidence.getTitle()) && + Objects.equals(user.getName(), that.user.getName()) && + Objects.equals(rating, that.candidateEvidence); + } + + @Override + public int hashCode() { + return Objects.hash(candidateEvidence.getTitle(), user.getName(), rating); + } +} + diff --git a/src/main/java/com/patternpedia/api/entities/issue/Issue.java b/src/main/java/com/patternpedia/api/entities/issue/Issue.java index 997dd7f..09d480e 100644 --- a/src/main/java/com/patternpedia/api/entities/issue/Issue.java +++ b/src/main/java/com/patternpedia/api/entities/issue/Issue.java @@ -5,6 +5,7 @@ import com.patternpedia.api.entities.EntityWithURI; import com.patternpedia.api.entities.issue.author.IssueAuthor; import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; import com.patternpedia.api.rest.model.issue.IssueModelRequest; import lombok.Data; import lombok.EqualsAndHashCode; @@ -35,6 +36,10 @@ public class Issue extends EntityWithURI { @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true) private List comments = new ArrayList<>(); + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true) + private List evidences = new ArrayList<>(); + public Issue (IssueModelRequest issueModelRequest) { this.setUri(issueModelRequest.getUri()); this.setName(issueModelRequest.getName()); diff --git a/src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidence.java b/src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidence.java new file mode 100644 index 0000000..52b2423 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidence.java @@ -0,0 +1,54 @@ +package com.patternpedia.api.entities.issue.evidence; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.shared.Evidence; +import com.patternpedia.api.entities.user.UserEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class IssueEvidence extends Evidence implements Serializable { + + @JsonIgnore + @ToString.Exclude + @ManyToOne + private Issue issue; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @ToString.Exclude + @ManyToOne + private UserEntity user; + + @JsonIgnore + @OneToMany(mappedBy = "issueEvidence", cascade = CascadeType.ALL, orphanRemoval = true) + private List userRating = new ArrayList<>(); + + public IssueEvidence(String title, String context, String type, Boolean supporting, String source, Issue issue, UserEntity user) { + super(title, context, type, supporting, source); + this.issue = issue; + this.user = user; + } + + public void updateEvidence(String title, String context, String type, Boolean supporting, String source) { + this.setTitle(title); + this.setContext(context); + this.setType(type); + this.setSupporting(supporting); + this.setSource(source); + } +} diff --git a/src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidenceRating.java b/src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidenceRating.java new file mode 100644 index 0000000..f9300d9 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidenceRating.java @@ -0,0 +1,69 @@ +package com.patternpedia.api.entities.issue.evidence; + +import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.shared.CompositeKey; +import com.patternpedia.api.entities.user.UserEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import java.util.Objects; + +@Entity +@Data +@NoArgsConstructor +public class IssueEvidenceRating { + + @EmbeddedId + @EqualsAndHashCode.Include + private CompositeKey id; + + @ManyToOne + @MapsId("entityId") + @EqualsAndHashCode.Include + private IssueEvidence issueEvidence; + + @ManyToOne + @MapsId("userId") + @EqualsAndHashCode.Include + private UserEntity user; + + private int rating; + + public IssueEvidenceRating(IssueEvidence issueEvidence, UserEntity user) { + this.issueEvidence = issueEvidence; + this.user = user; + this.id = new CompositeKey(issueEvidence.getId(), user.getId()); + } + + public IssueEvidenceRating(IssueEvidence issueEvidence, UserEntity user, int rating) { + this(issueEvidence, user); + this.rating = rating; + } + + @Override + public String toString() { + return this.id.toString() + this.rating; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof IssueEvidenceRating)) return false; + IssueEvidenceRating that = (IssueEvidenceRating) o; + return Objects.equals(issueEvidence.getTitle(), that.issueEvidence.getTitle()) && + Objects.equals(user.getName(), that.user.getName()) && + Objects.equals(rating, that.rating); + } + + @Override + public int hashCode() { + return Objects.hash(issueEvidence.getTitle(), user.getName(), rating); + } +} diff --git a/src/main/java/com/patternpedia/api/entities/shared/Evidence.java b/src/main/java/com/patternpedia/api/entities/shared/Evidence.java new file mode 100644 index 0000000..616aec9 --- /dev/null +++ b/src/main/java/com/patternpedia/api/entities/shared/Evidence.java @@ -0,0 +1,53 @@ +package com.patternpedia.api.entities.shared; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import java.util.Objects; +import java.util.UUID; + +@MappedSuperclass +@Data +@NoArgsConstructor +public abstract class Evidence { + + @Id + @GeneratedValue(generator = "pg-uuid") + private UUID id; + + private String title; + private String context; + private String type; + private Boolean supporting; + private String source; + + public Evidence(String title, String context, String type, Boolean supporting, String source) { + this.title = title; + this.context = context; + this.type = type; + this.supporting = supporting; + this.source = source; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Evidence)) return false; + Evidence that = (Evidence) o; + return id.equals(that.id) && + title.equals(that.title); + } + + @Override + public int hashCode() { + return Objects.hash(id, title); + } + + @Override + public String toString() { + return "Evidence: " + this.title + this.id.toString(); + } +} diff --git a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java b/src/main/java/com/patternpedia/api/entities/user/UserEntity.java index 363dedf..30f511e 100644 --- a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java +++ b/src/main/java/com/patternpedia/api/entities/user/UserEntity.java @@ -2,20 +2,20 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.patternpedia.api.entities.candidate.CandidateRating; import com.patternpedia.api.entities.candidate.comment.CandidateComment; import com.patternpedia.api.entities.candidate.author.CandidateAuthor; -import com.patternpedia.api.entities.candidate.CandidateRating; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.author.IssueAuthor; import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; import com.patternpedia.api.entities.user.role.Role; import com.patternpedia.api.rest.model.user.UserModel; -import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; import org.hibernate.annotations.NaturalId; -import org.hibernate.annotations.TypeDef; import javax.persistence.*; import java.io.Serializable; @@ -60,6 +60,10 @@ public class UserEntity implements Serializable{ @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List issueComments = new ArrayList<>(); + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List issueEvidence = new ArrayList<>(); + /** Candidate fields*/ @JsonIgnore @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) @@ -73,6 +77,10 @@ public class UserEntity implements Serializable{ @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List candidateComments = new ArrayList<>(); + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List candidateEvidence = new ArrayList<>(); + /** Pattern fields*/ // @JsonIgnore // @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) diff --git a/src/main/java/com/patternpedia/api/entities/user/role/Privilege.java b/src/main/java/com/patternpedia/api/entities/user/role/Privilege.java index 79607b8..fa3e730 100644 --- a/src/main/java/com/patternpedia/api/entities/user/role/Privilege.java +++ b/src/main/java/com/patternpedia/api/entities/user/role/Privilege.java @@ -43,4 +43,6 @@ public int hashCode() { public String toString() { return "Privileges: " + this.name; } + + } diff --git a/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java b/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java index cb56865..d913d18 100644 --- a/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java +++ b/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java @@ -1,24 +1,43 @@ package com.patternpedia.api.entities.user.role; public class PrivilegeConstant { - /** USER */ - public static final String READ_USER_ALL = "READ_USER_ALL"; - public static final String READ_USER = "READ_USER"; - public static final String CREATE_USER = "CREATE_USER"; - public static final String UPDATE_USER = "UPDATE_USER"; - public static final String DELETE_USER = "DELETE_USER"; /** ISSUE */ - public static final String READ_ISSUE = "READ_ISSUE"; - public static final String CREATE_ISSUE = "CREATE_ISSUE"; - public static final String UPDATE_ISSUE = "UPDATE_ISSUE"; - public static final String DELETE_ISSUE = "DELETE_ISSUE"; + public static final String ISSUE_READ = "ISSUE_READ"; + public static final String ISSUE_CREATE = "ISSUE_CREATE"; + public static final String ISSUE_EDIT = "ISSUE_EDIT"; + public static final String ISSUE_DELETE = "ISSUE_DELETE"; + public static final String ISSUE_READ_ALL = "ISSUE_READ_ALL"; + public static final String ISSUE_EDIT_ALL = "ISSUE_EDIT_ALL"; + public static final String ISSUE_DELETE_ALL = "ISSUE_DELETE_ALL"; + public static final String ISSUE_TO_PATTERN_CANDIDATE = "ISSUE_TO_PATTERN_CANDIDATE"; /** CANDIDATE */ - public static final String READ_CANDIDATE = "READ_CANDIDATE"; - public static final String CREATE_CANDIDATE = "CREATE_CANDIDATE"; - public static final String UPDATE_CANDIDATE = "UPDATE_CANDIDATE"; - public static final String DELETE_CANDIDATE = "DELETE_CANDIDATE"; - /** ROLE */ - public static final String UPDATE_ROLE = "UPDATE_ROLE"; - /** DEVELOPER */ - public static final String DEVELOPER = "DEVELOPER"; + public static final String PATTERN_CANDIDATE_READ = "PATTERN_CANDIDATE_READ"; + public static final String PATTERN_CANDIDATE_CREATE = "PATTERN_CANDIDATE_CREATE"; + public static final String PATTERN_CANDIDATE_EDIT = "PATTERN_CANDIDATE_EDIT"; + public static final String PATTERN_CANDIDATE_DELETE = "PATTERN_CANDIDATE_DELETE"; + public static final String PATTERN_CANDIDATE_READ_ALL = "PATTERN_CANDIDATE_READ_ALL"; + public static final String PATTERN_CANDIDATE_EDIT_ALL = "PATTERN_CANDIDATE_EDIT_ALL"; + public static final String PATTERN_CANDIDATE_DELETE_ALL = "PATTERN_CANDIDATE_DELETE_ALL"; + public static final String PATTERN_CANDIDATE_TO_PATTERN = "PATTERN_CANDIDATE_TO_PATTERN"; + /** Pattern */ + public static final String APPROVED_PATTERN_READ = "APPROVED_PATTERN_READ"; + public static final String APPROVED_PATTERN_CREATE = "APPROVED_PATTERN_CREATE"; + public static final String APPROVED_PATTERN_EDIT = "APPROVED_PATTERN_EDIT"; + public static final String APPROVED_PATTERN_DELETE = "APPROVED_PATTERN_DELETE"; + public static final String APPROVED_PATTERN_READ_ALL = "APPROVED_PATTERN_READ_ALL"; + public static final String APPROVED_PATTERN_EDIT_ALL = "APPROVED_PATTERN_EDIT_ALL"; + public static final String APPROVED_PATTERN_DELETE_ALL = "APPROVED_PATTERN_DELETE_ALL"; + /** USER */ + public static final String USER_READ = "USER_READ"; + public static final String USER_CREATE = "USER_CREATE"; + public static final String USER_EDIT = "USER_EDIT"; + public static final String USER_DELETE = "USER_DELETE"; + public static final String USER_READ_ALL = "USER_READ_ALL"; + public static final String USER_EDIT_ALL = "USER_EDIT_ALL"; + public static final String USER_DELETE_ALL = "USER_DELETE_ALL"; + public static final String USER_ALL = "USER_ALL"; + /** GENERAL */ + public static final String COMMENT = "COMMENT"; + public static final String VOTE = "VOTE"; + public static final String EVIDENCE = "EVIDENCE"; } diff --git a/src/main/java/com/patternpedia/api/entities/user/role/Role.java b/src/main/java/com/patternpedia/api/entities/user/role/Role.java index d621aff..9c776ee 100644 --- a/src/main/java/com/patternpedia/api/entities/user/role/Role.java +++ b/src/main/java/com/patternpedia/api/entities/user/role/Role.java @@ -30,5 +30,13 @@ public Role(String name) { this.name = name; } + public boolean checkPrivilege(String privilege) { + for (Privilege p : this.privileges) { + if (p.getName().equals(privilege)) { + return true; + } + } + return false; + } } diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRatingRepository.java b/src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRatingRepository.java new file mode 100644 index 0000000..7108f0e --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRatingRepository.java @@ -0,0 +1,10 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; +import com.patternpedia.api.entities.shared.CompositeKey; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CandidateEvidenceRatingRepository extends JpaRepository { + + boolean existsByIdAndRating(CompositeKey compositeKey, int rating); +} diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRepository.java b/src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRepository.java new file mode 100644 index 0000000..9057e6e --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRepository.java @@ -0,0 +1,9 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface CandidateEvidenceRepository extends JpaRepository { +} diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java b/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java index 438499b..7e1c9ba 100644 --- a/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java +++ b/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java @@ -8,5 +8,8 @@ @RepositoryRestResource(exported = false) public interface CandidateRatingRepository extends JpaRepository { - boolean existsByIdAndRating(CompositeKey compositeKey, int rating); + boolean existsById(CompositeKey compositeKey); + boolean existsByIdAndReadability(CompositeKey compositeKey, int rating); + boolean existsByIdAndUnderstandability(CompositeKey compositeKey, int rating); + boolean existsByIdAndAppropriateness(CompositeKey compositeKey, int rating); } diff --git a/src/main/java/com/patternpedia/api/repositories/IssueEvidenceRatingRepository.java b/src/main/java/com/patternpedia/api/repositories/IssueEvidenceRatingRepository.java new file mode 100644 index 0000000..7502584 --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/IssueEvidenceRatingRepository.java @@ -0,0 +1,10 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; +import com.patternpedia.api.entities.shared.CompositeKey; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface IssueEvidenceRatingRepository extends JpaRepository { + + boolean existsByIdAndRating(CompositeKey compositeKey, int rating); +} diff --git a/src/main/java/com/patternpedia/api/repositories/IssueEvidenceRepository.java b/src/main/java/com/patternpedia/api/repositories/IssueEvidenceRepository.java new file mode 100644 index 0000000..da87bc1 --- /dev/null +++ b/src/main/java/com/patternpedia/api/repositories/IssueEvidenceRepository.java @@ -0,0 +1,11 @@ +package com.patternpedia.api.repositories; + +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface IssueEvidenceRepository extends JpaRepository { + +} diff --git a/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java b/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java index e6f0d25..7d47c37 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java @@ -1,9 +1,11 @@ package com.patternpedia.api.rest.controller; import com.fasterxml.jackson.databind.ObjectMapper; +import com.patternpedia.api.config.Authority; import com.patternpedia.api.rest.model.candidate.CandidateModel; import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; import com.patternpedia.api.service.CandidateService; import com.patternpedia.api.service.PatternLanguageService; import org.slf4j.Logger; @@ -54,7 +56,6 @@ CollectionModel> all() { } @GetMapping(value = "/{candidateId}") - @PreAuthorize(value = "#oauth2.hasScope('read')") ResponseEntity> getCandidateById(@PathVariable UUID candidateId) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateById(candidateId)))); } @@ -68,44 +69,73 @@ ResponseEntity> getCandidateByUri(@PathVariable Stri * CREATE Methods */ @PostMapping(value = "") - @PreAuthorize(value = "#oauth2.hasScope('write')") +// @PreAuthorize(value = Authority.PATTERN_CANDIDATE_CREATE) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newCandidate(@RequestBody CandidateModelRequest candidateModelRequest, @AuthenticationPrincipal Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createCandidate(candidateModelRequest, UUID.fromString(principal.getName()))))); } @PostMapping(value = "/{candidateId}/comments") + @PreAuthorize(value = Authority.COMMENT) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.candidateService.createComment(candidateId, UUID.fromString(principal.getName()), commentModel)))); } + @PostMapping(value = "/{candidateId}/evidences") + @PreAuthorize(value = Authority.EVIDENCE) + @ResponseStatus(HttpStatus.CREATED) + ResponseEntity> newIssueEvidence(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + return ResponseEntity.ok(new EntityModel<>(new EvidenceModel(this.candidateService.createEvidence(candidateId, UUID.fromString(principal.getName()), evidenceModel)))); + } + /** * UPDATE Methods */ @PutMapping(value = "/{candidateId}") +// @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT) + @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidate(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CandidateModelRequest candidateModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidate(candidateId, UUID.fromString(principal.getName()), candidateModelRequest)))); } @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}") + @PreAuthorize(value = Authority.COMMENT) + @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.candidateService.updateComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()), commentModel)))); } + + @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") + @PreAuthorize(value = Authority.EVIDENCE) + @ResponseStatus(HttpStatus.ACCEPTED) + ResponseEntity> putIssueEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + return ResponseEntity.ok(new EntityModel<>(new EvidenceModel(this.candidateService.updateEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); + } + /** * DELETE Methods */ @DeleteMapping(value = "/{candidateId}") -// @PreAuthorize(value = "#oauth2.hasScope('de')") - ResponseEntity deleteCandidate(@PathVariable UUID candidateId) { - this.candidateService.deleteCandidate(candidateId); +// @PreAuthorize(value = Authority.PATTERN_CANDIDATE_DELETE) + @ResponseStatus(HttpStatus.OK) + ResponseEntity deleteCandidate(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal) { + this.candidateService.deleteCandidate(candidateId, UUID.fromString(principal.getName())); return ResponseEntity.noContent().build(); } @DeleteMapping(value = "/{candidateId}/comments/{candidateCommentId}") -// @PreAuthorize(value = "#oauth2.hasScope('de')") + @PreAuthorize(value = Authority.COMMENT) + @ResponseStatus(HttpStatus.OK) ResponseEntity deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal) { return this.candidateService.deleteComment(candidateId, candidateCommentId, UUID.fromString(principal.getName())); } + + @DeleteMapping(value = "/{issueId}/evidences/{issueEvidenceId}") + @PreAuthorize(value = Authority.EVIDENCE) + @ResponseStatus(HttpStatus.OK) + ResponseEntity deleteEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal) { + return this.candidateService.deleteEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName())); + } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java b/src/main/java/com/patternpedia/api/rest/controller/IssueController.java index 58f67bb..84641d1 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/IssueController.java @@ -4,6 +4,7 @@ import com.patternpedia.api.rest.model.issue.IssueModelRequest; import com.patternpedia.api.rest.model.shared.CommentModel; import com.patternpedia.api.rest.model.issue.IssueModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; import com.patternpedia.api.service.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -79,6 +80,12 @@ ResponseEntity> newIssueComment(@PathVariable UUID iss return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); } + @PostMapping(value = "/{issueId}/evidences") + @ResponseStatus(HttpStatus.CREATED) + ResponseEntity> newIssueEvidence(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + return ResponseEntity.ok(new EntityModel<>(new EvidenceModel(this.issueService.createEvidence(issueId, UUID.fromString(principal.getName()), evidenceModel)))); + } + /** * UPDATE Methods */ @@ -92,6 +99,11 @@ ResponseEntity> putIssueCommentRating(@PathVariable UU return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.issueService.updateComment(issueId, issueCommentId, UUID.fromString(principal.getName()), commentModel)))); } + @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}") + ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + return ResponseEntity.ok(new EntityModel<>(new EvidenceModel(this.issueService.updateEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); + } + /** * DELETE Methods */ @@ -105,4 +117,9 @@ ResponseEntity deleteIssue(@PathVariable UUID issueId) { ResponseEntity deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal) { return this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName())); } + + @DeleteMapping(value = "/{issueId}/evidences/{issueEvidenceId}") + ResponseEntity deleteEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal) { + return this.issueService.deleteEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName())); + } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/RatingController.java b/src/main/java/com/patternpedia/api/rest/controller/RatingController.java index 2225296..df1a38d 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/RatingController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/RatingController.java @@ -2,10 +2,7 @@ import com.patternpedia.api.rest.model.candidate.CandidateModel; import com.patternpedia.api.rest.model.issue.IssueModel; -import com.patternpedia.api.rest.model.shared.AuthorModelRequest; -import com.patternpedia.api.rest.model.shared.CommentModel; -import com.patternpedia.api.rest.model.shared.RatingModel; -import com.patternpedia.api.rest.model.shared.RatingModelRequest; +import com.patternpedia.api.rest.model.shared.*; import com.patternpedia.api.service.RatingService; import org.springframework.hateoas.EntityModel; import org.springframework.http.ResponseEntity; @@ -40,13 +37,23 @@ ResponseEntity> putIssueCommentRating(@PathVariable UUI return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } + @PutMapping(value = "/issues/{issueId}/evidences/{issueEvidenceId}") + ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { + return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateIssueEvidenceRating(issueId, issueEvidenceId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); + } + @PutMapping(value = "/candidates/{candidateId}") - ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelRequest)))); + ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { + return ResponseEntity.ok(new EntityModel<>(this.ratingService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelMultiRequest))); } @PutMapping(value = "/candidates/{candidateId}/comments/{candidateCommentId}") ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateCandidateCommentRating(candidateId, candidateCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } + + @PutMapping(value = "/candidates/{candidateId}/evidences/{candidateEvidenceId}") + ResponseEntity> putCandidateEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { + return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateCandidateEvidenceRating(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); + } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/UserController.java b/src/main/java/com/patternpedia/api/rest/controller/UserController.java index da20459..997d264 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/UserController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/UserController.java @@ -1,5 +1,6 @@ package com.patternpedia.api.rest.controller; +import com.patternpedia.api.config.Authority; import com.patternpedia.api.rest.model.user.*; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; @@ -41,7 +42,7 @@ public UserController( * GET Methods */ @GetMapping(value = "") - @PreAuthorize(value = "hasAuthority('READ_USER_ALL')") + @PreAuthorize(value = Authority.USER_READ_ALL) CollectionModel> getAll() { List> users = this.userService.getAllUsers() .stream() @@ -77,6 +78,7 @@ CollectionModel> getAllPrivileges() { * CREATE Methods */ @PostMapping(value = "") + @PreAuthorize(value = Authority.USER_CREATE) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newUser(@RequestBody UserModelRequest userModelRequest) { return ResponseEntity.ok(new EntityModel<>(new UserModel(this.userService.createUser(userModelRequest)))); @@ -86,12 +88,14 @@ ResponseEntity> newUser(@RequestBody UserModelRequest use * UPDATE Methods */ @PutMapping(value = "/{userId}") + @PreAuthorize(value = Authority.USER_EDIT) @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> updateUser(@PathVariable UUID userId, @RequestBody UserModelRequest userModelRequest) { return ResponseEntity.ok(new EntityModel<>(new UserModel(this.userService.updateUser(userId, userModelRequest)))); } @PutMapping(value = "/roles/{roleId}/privileges/{privilegeId}") + @PreAuthorize(value = Authority.USER_READ_ALL) @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> updateUserRole(@PathVariable UUID roleId, @PathVariable UUID privilegeId, @RequestBody RoleModelRequest roleModelRequest) { return ResponseEntity.ok(new EntityModel<>(new RoleModel(this.userService.updateRole(roleId, privilegeId, roleModelRequest)))); @@ -101,6 +105,7 @@ ResponseEntity> updateUserRole(@PathVariable UUID roleId, * DELETE Methods */ @DeleteMapping(value = "/{userId}") + @PreAuthorize(value = Authority.USER_DELETE) ResponseEntity deleteUser(@PathVariable UUID userId) { this.userService.deleteUser(userId); return ResponseEntity.noContent().build(); diff --git a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java index f5fb376..8b28861 100644 --- a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java @@ -2,10 +2,10 @@ import com.patternpedia.api.entities.PatternLanguage; import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.CandidateRating; -import com.patternpedia.api.entities.issue.IssueRating; import com.patternpedia.api.rest.model.shared.AuthorModel; import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; +import com.patternpedia.api.rest.model.shared.RatingModel; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -30,11 +30,13 @@ public class CandidateModel { private Object content; private String version; // RESPONSE - // RESPONSE - private Collection upVotes = new ArrayList<>(); - private Collection downVotes = new ArrayList<>(); + private Collection readability = new ArrayList<>(); + private Collection understandability = new ArrayList<>(); + private Collection appropriateness = new ArrayList<>(); private List authors = new ArrayList<>(); private List comments = new ArrayList<>(); + private List evidences = new ArrayList<>(); + public CandidateModel(Candidate candidate) { PatternLanguage patternLanguage = candidate.getPatternLanguage(); @@ -45,14 +47,12 @@ public CandidateModel(Candidate candidate) { this.content = candidate.getContent(); this.version = candidate.getVersion(); // RESPONSE - for (CandidateRating candidateRating: candidate.getUserRating()) { - if (candidateRating.getRating() == 1) - this.upVotes.add(candidateRating.getUser().getId()); - if (candidateRating.getRating() == -1) - this.downVotes.add(candidateRating.getUser().getId()); - } + this.readability = candidate.getUserRating().stream().map(candidateRating -> new RatingModel(candidateRating, candidateRating.getReadability())).collect(Collectors.toList()); + this.understandability = candidate.getUserRating().stream().map(candidateRating -> new RatingModel(candidateRating, candidateRating.getUnderstandability())).collect(Collectors.toList()); + this.appropriateness = candidate.getUserRating().stream().map(candidateRating -> new RatingModel(candidateRating, candidateRating.getAppropriateness())).collect(Collectors.toList()); this.authors = candidate.getAuthors().stream().map(issueAuthor -> new AuthorModel(issueAuthor.getUser(), issueAuthor.getRole())).collect(Collectors.toList()); this.comments = candidate.getComments().stream().map(issueComment -> CommentModel.from(issueComment)).collect(Collectors.toList()); + this.evidences = candidate.getEvidences().stream().map(candidateEvidence -> EvidenceModel.from(candidateEvidence)).collect(Collectors.toList()); if (patternLanguage != null) { this.patternLanguageId = patternLanguage.getId(); diff --git a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java index 8d5f030..48902db 100644 --- a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java +++ b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java @@ -8,12 +8,14 @@ import lombok.NoArgsConstructor; import java.util.List; +import java.util.UUID; @NoArgsConstructor @Data @EqualsAndHashCode(callSuper = false) public class CandidateModelRequest extends CandidateModel { + private UUID issueId; private Integer updateRating; private List updateAuthors; } diff --git a/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java b/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java index 82b37b2..798a8f6 100644 --- a/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java @@ -4,6 +4,7 @@ import com.patternpedia.api.entities.issue.IssueRating; import com.patternpedia.api.rest.model.shared.AuthorModel; import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; import com.patternpedia.api.rest.model.shared.RatingModel; import lombok.Data; import lombok.EqualsAndHashCode; @@ -30,6 +31,7 @@ public class IssueModel { private Collection downVotes = new ArrayList<>(); private List authors = new ArrayList<>(); private List comments = new ArrayList<>(); + private List evidences = new ArrayList<>(); public IssueModel(Issue issue) { this.id = issue.getId(); @@ -46,5 +48,6 @@ public IssueModel(Issue issue) { } this.authors = issue.getAuthors().stream().map(issueAuthor -> new AuthorModel(issueAuthor.getUser(), issueAuthor.getRole())).collect(Collectors.toList()); this.comments = issue.getComments().stream().map(issueComment -> CommentModel.from(issueComment)).collect(Collectors.toList()); + this.evidences = issue.getEvidences().stream().map(issueEvidence -> EvidenceModel.from(issueEvidence)).collect(Collectors.toList()); } } diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java new file mode 100644 index 0000000..dbf33d2 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java @@ -0,0 +1,72 @@ +package com.patternpedia.api.rest.model.shared; + +import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; +import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; +import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class EvidenceModel { + + private UUID id; + private UUID userId; + private String userName; + private String title; + private String context; + private String type; + private Boolean supporting; + private String source; + private Collection upVotes = new ArrayList<>(); + private Collection downVotes = new ArrayList<>(); + + /** For Issue Comments*/ + public EvidenceModel(IssueEvidence issueEvidence) { + this.id = issueEvidence.getId(); + this.userId = issueEvidence.getUser().getId(); + this.userName = issueEvidence.getUser().getName(); + this.title = issueEvidence.getTitle(); + this.context = issueEvidence.getContext(); + this.type = issueEvidence.getType(); + this.supporting = issueEvidence.getSupporting(); + this.source = issueEvidence.getSource(); + for (IssueEvidenceRating issueRating: issueEvidence.getUserRating()) { + if (issueRating.getRating() == 1) + this.upVotes.add(issueRating.getUser().getId()); + if (issueRating.getRating() == -1) + this.downVotes.add(issueRating.getUser().getId()); + } + } + public static EvidenceModel from(IssueEvidence issueEvidence) { return new EvidenceModel(issueEvidence); } + + /** For Candidate Evidence*/ + public EvidenceModel(CandidateEvidence candidateEvidence) { + this.id = candidateEvidence.getId(); + this.userId = candidateEvidence.getUser().getId(); + this.userName = candidateEvidence.getUser().getName(); + this.title = candidateEvidence.getTitle(); + this.context = candidateEvidence.getContext(); + this.type = candidateEvidence.getType(); + this.supporting = candidateEvidence.getSupporting(); + this.source = candidateEvidence.getSource(); + for (CandidateEvidenceRating candidateEvidenceRating: candidateEvidence.getUserRating()) { + if (candidateEvidenceRating.getRating() == 1) + this.upVotes.add(candidateEvidenceRating.getUser().getId()); + if (candidateEvidenceRating.getRating() == -1) + this.downVotes.add(candidateEvidenceRating.getUser().getId()); + } + } + public static EvidenceModel from(CandidateEvidence candidateEvidence) { return new EvidenceModel(candidateEvidence); } +} diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java index 79233bf..5b2b958 100644 --- a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java @@ -2,13 +2,14 @@ import com.patternpedia.api.entities.candidate.CandidateRating; import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; import com.patternpedia.api.entities.issue.IssueRating; import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import java.util.Collection; import java.util.UUID; @NoArgsConstructor @@ -29,13 +30,30 @@ public RatingModel(IssueCommentRating issueCommentRating) { this.userId = issueCommentRating.getUser().getId(); } - public RatingModel(CandidateRating candidateRating) { - this.rating = candidateRating.getRating(); + public RatingModel(IssueEvidenceRating issueEvidenceRating) { + this.rating = issueEvidenceRating.getRating(); + this.userId = issueEvidenceRating.getUser().getId(); + } + + public RatingModel(CandidateRating candidateRating, int rating) { + this.rating = rating; this.userId = candidateRating.getUser().getId(); } +// public RatingModel(CandidateRating candidateRating) { +// int readability = candidateRating.getReadability(); +// int understandability = candidateRating.getUnderstandability(); +// int appropriateness = candidateRating.getAppropriateness(); +// this.userId = candidateRating.getUser().getId(); +// } + public RatingModel(CandidateCommentRating candidateCommentRating) { this.rating = candidateCommentRating.getRating(); this.userId = candidateCommentRating.getUser().getId(); } + + public RatingModel(CandidateEvidenceRating candidateEvidenceRating) { + this.rating = candidateEvidenceRating.getRating(); + this.userId = candidateEvidenceRating.getUser().getId(); + } } diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModelMultiRequest.java b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModelMultiRequest.java new file mode 100644 index 0000000..a18f3e0 --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModelMultiRequest.java @@ -0,0 +1,13 @@ +package com.patternpedia.api.rest.model.shared; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +public class RatingModelMultiRequest extends RatingModelRequest { + + private RatingType ratingType; +} diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingType.java b/src/main/java/com/patternpedia/api/rest/model/shared/RatingType.java new file mode 100644 index 0000000..97d9b7d --- /dev/null +++ b/src/main/java/com/patternpedia/api/rest/model/shared/RatingType.java @@ -0,0 +1,7 @@ +package com.patternpedia.api.rest.model.shared; + +public enum RatingType { + READABILITY, + UNDERSTANDABILITY, + APPROPIATENESS; +} diff --git a/src/main/java/com/patternpedia/api/rest/model/user/UserModel.java b/src/main/java/com/patternpedia/api/rest/model/user/UserModel.java index 7d7afab..1011a89 100644 --- a/src/main/java/com/patternpedia/api/rest/model/user/UserModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/user/UserModel.java @@ -1,8 +1,10 @@ package com.patternpedia.api.rest.model.user; import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.rest.model.candidate.CandidateModel; import com.patternpedia.api.rest.model.issue.IssueModel; import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; import com.patternpedia.api.rest.model.shared.RatingModel; import lombok.Data; import lombok.EqualsAndHashCode; @@ -25,15 +27,30 @@ public class UserModel { private List issues; private List issueComments; private List issueRatings; + private List issueEvidences; + private List candidates; + private List candidateComments; + private List candidatesRatings; + private List candidatesEvidences; + private List patterns = new ArrayList<>(); + private List patternComments = new ArrayList<>(); + private List patternRatings = new ArrayList<>(); + private List patternEvidences = new ArrayList<>(); public UserModel(UserEntity user) { this.id = user.getId(); this.role = user.getRole().getName(); this.email = user.getEmail(); this.name = user.getName(); + // ISSUE this.issues = user.getIssues().stream().map(issueAuthor -> new IssueModel(issueAuthor.getIssue())).collect(Collectors.toList()); this.issueComments = user.getIssueComments().stream().map(issueComment -> new CommentModel(issueComment)).collect(Collectors.toList()); this.issueRatings = user.getIssueRatings().stream().map((issueRating -> new IssueModel(issueRating.getIssue()))).collect(Collectors.toList()); - + this.issueEvidences = user.getIssueEvidence().stream().map(issueEvidence -> new EvidenceModel(issueEvidence)).collect(Collectors.toList()); + // CANDIDATE + this.candidates = user.getCandidates().stream().map(candidateAuthor -> new CandidateModel(candidateAuthor.getCandidate())).collect(Collectors.toList()); + this.candidateComments = user.getCandidateComments().stream().map(candidateComment -> new CommentModel(candidateComment)).collect(Collectors.toList()); + this.candidatesRatings = user.getCandidateRatings().stream().map((candidateRating -> new CandidateModel(candidateRating.getCandidate()))).collect(Collectors.toList()); + this.candidatesEvidences = user.getCandidateEvidence().stream().map(candidateEvidence -> new EvidenceModel(candidateEvidence)).collect(Collectors.toList()); } } diff --git a/src/main/java/com/patternpedia/api/service/CandidateService.java b/src/main/java/com/patternpedia/api/service/CandidateService.java index 58e3245..453d340 100644 --- a/src/main/java/com/patternpedia/api/service/CandidateService.java +++ b/src/main/java/com/patternpedia/api/service/CandidateService.java @@ -2,8 +2,10 @@ import com.patternpedia.api.entities.candidate.Candidate; import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; import org.springframework.http.ResponseEntity; import java.util.List; @@ -22,7 +24,7 @@ public interface CandidateService { Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRequest candidateModelRequest); - void deleteCandidate(UUID candidateId); + void deleteCandidate(UUID candidateId, UUID userId); /** Comment */ CandidateComment createComment(UUID candidateId, UUID userId, CommentModel commentModel); @@ -32,4 +34,13 @@ public interface CandidateService { CandidateComment updateComment(UUID candidateId, UUID commentId, UUID userId, CommentModel commentModel); ResponseEntity deleteComment(UUID candidateId, UUID commentId, UUID userId); + + /** Evidence */ + CandidateEvidence createEvidence(UUID candidateId, UUID userId, EvidenceModel evidenceModel); + + CandidateEvidence getEvidenceById(UUID evidenceId); + + CandidateEvidence updateEvidence(UUID candidateId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); + + ResponseEntity deleteEvidence(UUID candidateId, UUID evidenceId, UUID userId); } diff --git a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java index 2c8e474..bcbebe1 100644 --- a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java @@ -3,14 +3,18 @@ import com.patternpedia.api.entities.candidate.Candidate; import com.patternpedia.api.entities.candidate.comment.CandidateComment; import com.patternpedia.api.entities.candidate.author.CandidateAuthor; -import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; -import com.patternpedia.api.entities.issue.comment.IssueComment; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; +import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; import com.patternpedia.api.entities.shared.AuthorConstant; import com.patternpedia.api.entities.user.UserEntity; +import com.patternpedia.api.entities.user.role.PrivilegeConstant; import com.patternpedia.api.repositories.*; import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; import com.patternpedia.api.rest.model.shared.AuthorModel; import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; import com.patternpedia.api.util.RatingHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,27 +33,28 @@ public class CandidateServiceImpl implements CandidateService { private CandidateRepository candidateRepository; - private CandidateRatingRepository candidateRatingRepository; private CandidateCommentRepository candidateCommentRepository; + private CandidateEvidenceRepository candidateEvidenceRepository; private PatternLanguageService patternLanguageService; private UserService userService; - private RatingHelper ratingHelper; + private IssueService issueService; Logger logger = LoggerFactory.getLogger(IssueServiceImpl.class); public CandidateServiceImpl( CandidateRepository candidateRepository, - CandidateRatingRepository candidateRatingRepository, CandidateCommentRepository candidateCommentRepository, + CandidateEvidenceRepository candidateEvidenceRepository, PatternLanguageService patternLanguageService, - UserService userService + UserService userService, + IssueService issueService ) { this.candidateRepository = candidateRepository; - this.candidateRatingRepository = candidateRatingRepository; this.candidateCommentRepository = candidateCommentRepository; + this.candidateEvidenceRepository = candidateEvidenceRepository; this.patternLanguageService = patternLanguageService; this.userService = userService; - this.ratingHelper = new RatingHelper(); + this.issueService = issueService; } @Override @@ -65,6 +70,7 @@ public Candidate saveCandidate(Candidate candidate) { @Transactional public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UUID userId) { Candidate candidate = new Candidate(candidateModelRequest); + UserEntity user = this.userService.getUserById(userId); if (null == candidate) throw new RuntimeException("Candidate to create is null"); if (this.candidateRepository.existsByName(candidate.getName())) @@ -72,22 +78,35 @@ public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UU if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); - // ADD authors - Candidate newCandidate = this.candidateRepository.save(candidate); - if (candidateModelRequest.getAuthors() != null) { - for (AuthorModel authorModel : candidateModelRequest.getAuthors()) { - newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(authorModel.getUserId()), authorModel.getAuthorRole())); + // ISSUE TO PATTERN + if (user.getRole().checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_CREATE) || this.issueService.authorPermissions(candidateModelRequest.getIssueId(), userId)) { + Candidate newCandidate = this.candidateRepository.save(candidate); + if (candidateModelRequest.getIssueId() != null) { + logger.info("Issue to Candidate request"); + Issue issue = this.issueService.getIssueById(candidateModelRequest.getIssueId()); + for (IssueEvidence issueEvidence: issue.getEvidences()) { + CandidateEvidence evidence = new CandidateEvidence(issueEvidence, newCandidate, user); + newCandidate.getEvidences().add(evidence); + } + this.issueService.deleteIssue(candidateModelRequest.getIssueId()); + } + // ADD authorr + if (candidateModelRequest.getAuthors() != null) { + for (AuthorModel authorModel : candidateModelRequest.getAuthors()) { + newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(authorModel.getUserId()), authorModel.getAuthorRole())); + } + } else { + newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(userId), AuthorConstant.OWNER)); } - } else { - newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(userId), AuthorConstant.OWNER)); - } - - // ADD pattern language - if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) - newCandidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); + // ADD pattern language + if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) + newCandidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); - return this.candidateRepository.save(newCandidate); + return this.candidateRepository.save(newCandidate); + } else { + throw new RuntimeException("You don't have the permission"); + } } @Override @@ -117,30 +136,55 @@ public Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRe throw new RuntimeException("Candidate to update is null!"); } Candidate candidate = this.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(userId); - // UPDATE issue fields - if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) { - Candidate candidateByURI = this.getCandidateByURI(candidateModelRequest.getUri()); - // NOT uri & name change - if (!candidateByURI.getId().equals(candidate.getId())) { - throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); + if (user.getRole().checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EDIT_ALL) || this.authorPermissions(candidateModelRequest.getId(), userId)) { + // UPDATE issue fields + if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) { + Candidate candidateByURI = this.getCandidateByURI(candidateModelRequest.getUri()); + // NOT uri & name change + if (!candidateByURI.getId().equals(candidate.getId())) { + throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); + } } - } - // ADD pattern language - if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) - candidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); + // ADD pattern language + if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) + candidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); - // UPDATE issue fields - candidate.updateCandidate(candidateModelRequest); + // UPDATE issue fields + candidate.updateCandidate(candidateModelRequest); - return this.candidateRepository.save(candidate); + return this.candidateRepository.save(candidate); + } else { + throw new RuntimeException("You don't have the permission"); + } } @Override @Transactional - public void deleteCandidate(UUID candidateId) { - this.getCandidateById(candidateId); - this.candidateRepository.deleteById(candidateId); + public void deleteCandidate(UUID candidateId, UUID userId) { + UserEntity user = this.userService.getUserById(userId); + + if (user.getRole().checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_DELETE_ALL) || this.authorPermissions(candidateId, userId)) { + this.candidateRepository.deleteById(candidateId); + } else { + throw new RuntimeException("You don't have the permission"); + } + + } + + public boolean authorPermissions(UUID candidateId, UUID userId) { + if (candidateId == null) + return false; + Candidate candidate = this.getCandidateById(candidateId); + for (CandidateAuthor author : candidate.getAuthors()) { + if (author.getUser().getId() == userId) { + if (author.getRole().equals(AuthorConstant.OWNER) || author.getRole().equals(AuthorConstant.MAINTAINER)) { + return true; + } + } + } + return false; } /** @@ -194,4 +238,60 @@ private CandidateComment authCandidateComment(UUID candidateId, UUID commentId, throw new EntityNotFoundException(String.format("Candidate comment with id %s does not belong to user with id %s", commentId, userId)); return candidateComment; } + + /** + * Evidence + */ + @Override + @Transactional + public CandidateEvidence createEvidence(UUID candidateId, UUID userId, EvidenceModel evidenceModel) { + Candidate candidate = this.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(userId); + + CandidateEvidence candidateEvidence = new CandidateEvidence( + evidenceModel.getTitle(), + evidenceModel.getContext(), + evidenceModel.getType(), + evidenceModel.getSupporting(), + evidenceModel.getSource(), + candidate, user); + return this.candidateEvidenceRepository.save(candidateEvidence); + } + + @Override + @Transactional(readOnly = true) + public CandidateEvidence getEvidenceById(UUID evidenceId) { + return this.candidateEvidenceRepository.findById(evidenceId) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Candidate evidence with ID %s not found!", evidenceId))); + } + + @Override + @Transactional + public CandidateEvidence updateEvidence(UUID candidateId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel) { + if (evidenceModel == null) + throw new RuntimeException("Candidate evidence to update is null!"); + CandidateEvidence candidateEvidence = this.authCandidateEvidence(candidateId, evidenceId, userId); + // UPDATE Candidate evidence + candidateEvidence.updateEvidence(evidenceModel.getTitle(), evidenceModel.getContext(), evidenceModel.getType(), evidenceModel.getSupporting(), evidenceModel.getSource()); + return this.candidateEvidenceRepository.save(candidateEvidence); + } + + @Override + @Transactional + public ResponseEntity deleteEvidence(UUID candidateId, UUID evidenceId, UUID userId) { + this.authCandidateEvidence(candidateId, evidenceId, userId); + this.candidateEvidenceRepository.deleteById(evidenceId); + return ResponseEntity.noContent().build(); + } + + private CandidateEvidence authCandidateEvidence(UUID candidateId, UUID evidenceId, UUID userId) { + CandidateEvidence candidateEvidence = this.getEvidenceById(evidenceId); + // CORRECT Evidence + if (!candidateEvidence.getCandidate().equals(this.getCandidateById(candidateId))) + throw new EntityNotFoundException(String.format("Candidate comment with id %s does not belong to candidate with id %s", evidenceId, candidateId)); + // CORRECT user + if (!candidateEvidence.getUser().equals(this.userService.getUserById(userId))) + throw new EntityNotFoundException(String.format("Candidate comment with id %s does not belong to user with id %s", evidenceId, userId)); + return candidateEvidence; + } } diff --git a/src/main/java/com/patternpedia/api/service/IssueService.java b/src/main/java/com/patternpedia/api/service/IssueService.java index 115b365..612f0e1 100644 --- a/src/main/java/com/patternpedia/api/service/IssueService.java +++ b/src/main/java/com/patternpedia/api/service/IssueService.java @@ -4,8 +4,10 @@ import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; import com.patternpedia.api.rest.model.issue.IssueModelRequest; import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; import org.springframework.http.ResponseEntity; import java.util.UUID; @@ -26,6 +28,8 @@ public interface IssueService { void deleteIssue(UUID issueId); + boolean authorPermissions(UUID issueId, UUID userId); + /** Comment */ IssueComment createComment(UUID issueId, UUID userId, CommentModel commentModel); @@ -34,4 +38,15 @@ public interface IssueService { IssueComment updateComment(UUID issueId, UUID commentId, UUID userId, CommentModel commentModel); ResponseEntity deleteComment(UUID issueId, UUID commentId, UUID userId); + + /** Evidence */ + IssueEvidence createEvidence(UUID issueId, UUID userId, EvidenceModel evidenceModel); + + IssueEvidence getEvidenceById(UUID issueEvidenceId); + + IssueEvidence updateEvidence(UUID issueId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); + + ResponseEntity deleteEvidence(UUID issueId, UUID evidenceId, UUID userId); + + } diff --git a/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java b/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java index 140499b..31d127a 100644 --- a/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java @@ -3,13 +3,13 @@ import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.Issue; import com.patternpedia.api.entities.issue.author.IssueAuthor; -import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; import com.patternpedia.api.entities.shared.AuthorConstant; import com.patternpedia.api.entities.user.UserEntity; import com.patternpedia.api.repositories.*; import com.patternpedia.api.rest.model.issue.IssueModelRequest; -import com.patternpedia.api.rest.model.shared.AuthorModel; import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.EvidenceModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.rest.webmvc.ResourceNotFoundException; @@ -27,7 +27,7 @@ public class IssueServiceImpl implements IssueService { private IssueRepository issueRepository; private IssueCommentRepository issueCommentRepository; - private IssueCommentRatingRepository issueCommentRatingRepository; + private IssueEvidenceRepository issueEvidenceRepository; private UserService userService; Logger logger = LoggerFactory.getLogger(IssueServiceImpl.class); @@ -35,12 +35,12 @@ public class IssueServiceImpl implements IssueService { public IssueServiceImpl( IssueRepository issueRepository, IssueCommentRepository issueCommentRepository, - IssueCommentRatingRepository issueCommentRatingRepository, + IssueEvidenceRepository issueEvidenceRepository, UserService userService ) { this.issueRepository = issueRepository; this.issueCommentRepository = issueCommentRepository; - this.issueCommentRatingRepository = issueCommentRatingRepository; + this.issueEvidenceRepository = issueEvidenceRepository; this.userService = userService; } @@ -116,6 +116,20 @@ public void deleteIssue(UUID IssueId) { this.issueRepository.deleteById(IssueId); } + public boolean authorPermissions(UUID issueId, UUID userId) { + if (issueId == null) + return false; + Issue issue = this.getIssueById(issueId); + for (IssueAuthor author : issue.getAuthors()) { + if (author.getUser().getId() == userId) { + if (author.getRole().equals(AuthorConstant.OWNER) || author.getRole().equals(AuthorConstant.MAINTAINER) ) { + return true; + } + } + } + return false; + } + /** * Comment */ @@ -165,4 +179,54 @@ private IssueComment authIssueComment(UUID issueId, UUID commentId, UUID userId) throw new EntityNotFoundException(String.format("Issue comment with id %s does not belong to user with id %s", commentId, userId)); return issueComment; } + + /** + * Evidence + */ + @Override + @Transactional + public IssueEvidence createEvidence(UUID issueId, UUID userId, EvidenceModel evidenceModel) { + Issue issue = this.getIssueById(issueId); + UserEntity user = this.userService.getUserById(userId); + + IssueEvidence issueEvidence = new IssueEvidence(evidenceModel.getTitle(), evidenceModel.getContext(), evidenceModel.getType(), evidenceModel.getSupporting(), evidenceModel.getSource(), issue, user); + return this.issueEvidenceRepository.save(issueEvidence); + } + + @Override + @Transactional(readOnly = true) + public IssueEvidence getEvidenceById(UUID issueEvidenceId) { + return this.issueEvidenceRepository.findById(issueEvidenceId) + .orElseThrow(() -> new ResourceNotFoundException(String.format("Issue comment with ID %s not found!", issueEvidenceId))); + } + + @Override + @Transactional + public IssueEvidence updateEvidence(UUID issueId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel) { + if (evidenceModel == null) + throw new RuntimeException("Issue comment to update is null!"); + IssueEvidence issueEvidence = this.authIssueEvidence(issueId, evidenceId, userId); + // UPDATE issue evidence + issueEvidence.updateEvidence(evidenceModel.getTitle(), evidenceModel.getContext(), evidenceModel.getType(), evidenceModel.getSupporting(), evidenceModel.getSource()); + return this.issueEvidenceRepository.save(issueEvidence); + } + + @Override + @Transactional + public ResponseEntity deleteEvidence(UUID issueId, UUID evidenceId, UUID userId) { + this.authIssueEvidence(issueId, evidenceId, userId); + this.issueEvidenceRepository.deleteById(evidenceId); + return ResponseEntity.noContent().build(); + } + + private IssueEvidence authIssueEvidence(UUID issueId, UUID commentId, UUID userId) { + IssueEvidence issueEvidence = this.getEvidenceById(commentId); + // CORRECT Issue + if (!issueEvidence.getIssue().equals(this.getIssueById(issueId))) + throw new EntityNotFoundException(String.format("Issue comment with id %s does not belong to issue with id %s", commentId, issueId)); + // CORRECT user + if (!issueEvidence.getUser().equals(this.userService.getUserById(userId))) + throw new EntityNotFoundException(String.format("Issue comment with id %s does not belong to user with id %s", commentId, userId)); + return issueEvidence; + } } diff --git a/src/main/java/com/patternpedia/api/service/RatingService.java b/src/main/java/com/patternpedia/api/service/RatingService.java index c4569d4..42287f9 100644 --- a/src/main/java/com/patternpedia/api/service/RatingService.java +++ b/src/main/java/com/patternpedia/api/service/RatingService.java @@ -1,21 +1,24 @@ package com.patternpedia.api.service; -import com.patternpedia.api.entities.candidate.Candidate; import com.patternpedia.api.entities.candidate.CandidateRating; import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; import com.patternpedia.api.entities.issue.IssueRating; -import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; +import com.patternpedia.api.rest.model.shared.RatingModel; +import com.patternpedia.api.rest.model.shared.RatingModelMultiRequest; import com.patternpedia.api.rest.model.shared.RatingModelRequest; -import java.util.Collection; import java.util.UUID; public interface RatingService { IssueRating updateIssueRating(UUID issueId, UUID userId, RatingModelRequest ratingModelRequest); IssueCommentRating updateIssueCommentRating(UUID issueId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); + IssueEvidenceRating updateIssueEvidenceRating(UUID issueId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest); - CandidateRating updateCandidateRating(UUID candidateId, UUID userId, RatingModelRequest ratingModelRequest); + RatingModel updateCandidateRating(UUID candidateId, UUID userId, RatingModelMultiRequest ratingModelMultiRequest); CandidateCommentRating updateCandidateCommentRating(UUID candidateId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); + CandidateEvidenceRating updateCandidateEvidenceRating(UUID candidateId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest); } diff --git a/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java b/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java index 3571734..11db01b 100644 --- a/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java @@ -4,18 +4,26 @@ import com.patternpedia.api.entities.candidate.CandidateRating; import com.patternpedia.api.entities.candidate.comment.CandidateComment; import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; import com.patternpedia.api.entities.issue.Issue; import com.patternpedia.api.entities.issue.IssueRating; import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.comment.IssueCommentRating; +import com.patternpedia.api.entities.issue.evidence.IssueEvidence; +import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; import com.patternpedia.api.entities.user.UserEntity; import com.patternpedia.api.repositories.*; +import com.patternpedia.api.rest.model.shared.RatingModel; +import com.patternpedia.api.rest.model.shared.RatingModelMultiRequest; import com.patternpedia.api.rest.model.shared.RatingModelRequest; +import com.patternpedia.api.rest.model.shared.RatingType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.persistence.EntityExistsException; import java.util.UUID; @Service @@ -26,26 +34,32 @@ public class RatingServiceImpl implements RatingService { private IssueRatingRepository issueRatingRepository; private IssueCommentRatingRepository issueCommentRatingRepository; + private IssueEvidenceRatingRepository issueEvidenceRatingRepository; private IssueService issueService; private CandidateRatingRepository candidateRatingRepository; private CandidateCommentRatingRepository candidateCommentRatingRepository; + private CandidateEvidenceRatingRepository candidateEvidenceRatingRepository; private CandidateService candidateService; private UserService userService; public RatingServiceImpl( IssueRatingRepository issueRatingRepository, IssueCommentRatingRepository issueCommentRatingRepository, + IssueEvidenceRatingRepository issueEvidenceRatingRepository, IssueService issueService, CandidateRatingRepository candidateRatingRepository, CandidateCommentRatingRepository candidateCommentRatingRepository, + CandidateEvidenceRatingRepository candidateEvidenceRatingRepository, CandidateService candidateService, UserService userService ) { this.issueRatingRepository = issueRatingRepository; this.issueCommentRatingRepository = issueCommentRatingRepository; + this.issueEvidenceRatingRepository = issueEvidenceRatingRepository; this.issueService = issueService; this.candidateRatingRepository = candidateRatingRepository; this.candidateCommentRatingRepository = candidateCommentRatingRepository; + this.candidateEvidenceRatingRepository = candidateEvidenceRatingRepository; this.candidateService = candidateService; this.userService = userService; } @@ -82,14 +96,62 @@ public IssueCommentRating updateIssueCommentRating(UUID issueId, UUID commentId, @Override @Transactional - public CandidateRating updateCandidateRating(UUID candidateId, UUID userId, RatingModelRequest ratingModelRequest) { + public IssueEvidenceRating updateIssueEvidenceRating(UUID issueId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest) { + Issue issue = this.issueService.getIssueById(issueId); + IssueEvidence issueEvidence = this.issueService.getEvidenceById(evidenceID); + UserEntity user = this.userService.getUserById(userId); + IssueEvidenceRating issueEvidenceRating = new IssueEvidenceRating(issueEvidence, user, ratingModelRequest.getRating()); + if (this.issueEvidenceRatingRepository.existsByIdAndRating(issueEvidenceRating.getId(), issueEvidenceRating.getRating())) { + this.issueEvidenceRatingRepository.delete(issueEvidenceRating); + issueEvidenceRating.setRating(0); + return issueEvidenceRating; + } + return this.issueEvidenceRatingRepository.save(issueEvidenceRating); + } + + @Override + @Transactional + public RatingModel updateCandidateRating(UUID candidateId, UUID userId, RatingModelMultiRequest ratingModelMultiRequest) { Candidate candidate = this.candidateService.getCandidateById(candidateId); UserEntity user = this.userService.getUserById(userId); - CandidateRating candidateRating = new CandidateRating(candidate, user, ratingModelRequest.getRating()); - if (this.candidateRatingRepository.existsByIdAndRating(candidateRating.getId(), candidateRating.getRating())) { - candidateRating.setRating(0); + CandidateRating candidateRating = new CandidateRating(candidate, user); + if (this.candidateRatingRepository.existsById(candidateRating.getId())) { + candidateRating = this.candidateRatingRepository.getOne(candidateRating.getId()); + } + if (ratingModelMultiRequest.getRatingType().equals(RatingType.READABILITY)) { + candidateRating.setReadability(ratingModelMultiRequest.getRating()); +// if (this.candidateRatingRepository.existsByIdAndReadability(candidateRating.getId(), candidateRating.getReadability())) { +// candidateRating.setReadability(-1); +// return new RatingModel(candidateRating, candidateRating.getReadability()); +// } + + } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.UNDERSTANDABILITY)) { + candidateRating.setUnderstandability(ratingModelMultiRequest.getRating()); +// if (this.candidateRatingRepository.existsByIdAndUnderstandability(candidateRating.getId(), candidateRating.getUnderstandability())) { +// candidateRating.setUnderstandability(-1); +// return new RatingModel(candidateRating, candidateRating.getUnderstandability()); +// } + + } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.APPROPIATENESS)) { + candidateRating.setAppropriateness(ratingModelMultiRequest.getRating()); +// if (this.candidateRatingRepository.existsByIdAndAppropriateness(candidateRating.getId(), candidateRating.getAppropriateness())) { +// candidateRating.setAppropriateness(-1); +// return new RatingModel(candidateRating, candidateRating.getAppropriateness()); +// } + + } else { + throw new EntityExistsException(String.format("Rating type does not exists", ratingModelMultiRequest.getRatingType())); } - return this.candidateRatingRepository.save(candidateRating); + CandidateRating updatedCandidateRating = this.candidateRatingRepository.save(candidateRating); + + if (ratingModelMultiRequest.getRatingType().equals(RatingType.READABILITY)) { + return new RatingModel(updatedCandidateRating, updatedCandidateRating.getReadability()); + } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.UNDERSTANDABILITY)) { + return new RatingModel(updatedCandidateRating, updatedCandidateRating.getUnderstandability()); + } else{ + return new RatingModel(updatedCandidateRating, updatedCandidateRating.getAppropriateness()); + } + } @Override @@ -106,4 +168,19 @@ public CandidateCommentRating updateCandidateCommentRating(UUID candidateId, UUI } return this.candidateCommentRatingRepository.save(candidateCommentRating); } + + @Override + @Transactional + public CandidateEvidenceRating updateCandidateEvidenceRating(UUID candidateId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest) { + Candidate candidate = this.candidateService.getCandidateById(candidateId); + CandidateEvidence candidateEvidence = this.candidateService.getEvidenceById(evidenceID); + UserEntity user = this.userService.getUserById(userId); + CandidateEvidenceRating candidateEvidenceRating = new CandidateEvidenceRating(candidateEvidence, user, ratingModelRequest.getRating()); + if (this.candidateEvidenceRatingRepository.existsByIdAndRating(candidateEvidenceRating.getId(), candidateEvidenceRating.getRating())) { + this.candidateEvidenceRatingRepository.delete(candidateEvidenceRating); + candidateEvidenceRating.setRating(0); + return candidateEvidenceRating; + } + return this.candidateEvidenceRatingRepository.save(candidateEvidenceRating); + } } From abf98f8b95fe51c631697a602e8cc9b209edd16c Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Thu, 8 Oct 2020 23:47:29 +0200 Subject: [PATCH 10/68] CHAGE code clean up --- .../api/rest/controller/RatingController.java | 59 ------ .../api/service/AuthorService.java | 22 --- .../api/service/AuthorServiceImpl.java | 88 --------- .../api/service/RatingService.java | 24 --- .../api/service/RatingServiceImpl.java | 186 ------------------ .../api/integration/IssueControllerTest.java | 4 + 6 files changed, 4 insertions(+), 379 deletions(-) delete mode 100644 src/main/java/com/patternpedia/api/rest/controller/RatingController.java delete mode 100644 src/main/java/com/patternpedia/api/service/AuthorService.java delete mode 100644 src/main/java/com/patternpedia/api/service/AuthorServiceImpl.java delete mode 100644 src/main/java/com/patternpedia/api/service/RatingService.java delete mode 100644 src/main/java/com/patternpedia/api/service/RatingServiceImpl.java create mode 100644 src/test/java/com/patternpedia/api/integration/IssueControllerTest.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/RatingController.java b/src/main/java/com/patternpedia/api/rest/controller/RatingController.java deleted file mode 100644 index df1a38d..0000000 --- a/src/main/java/com/patternpedia/api/rest/controller/RatingController.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.patternpedia.api.rest.controller; - -import com.patternpedia.api.rest.model.candidate.CandidateModel; -import com.patternpedia.api.rest.model.issue.IssueModel; -import com.patternpedia.api.rest.model.shared.*; -import com.patternpedia.api.service.RatingService; -import org.springframework.hateoas.EntityModel; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; - -import java.security.Principal; -import java.util.UUID; - -@RestController -@RequestMapping(value = "/ratings", produces = "application/hal+json") -public class RatingController { - - private RatingService ratingService; - - public RatingController( - RatingService ratingService - ) { - this.ratingService = ratingService; - } - - /** - * UPDATE Methods - */ - @PutMapping(value = "/issues/{issueId}") - ResponseEntity> putIssueRating(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateIssueRating(issueId, UUID.fromString(principal.getName()), ratingModelRequest)))); - } - - @PutMapping(value = "/issues/{issueId}/comments/{issueCommentId}") - ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); - } - - @PutMapping(value = "/issues/{issueId}/evidences/{issueEvidenceId}") - ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { - return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateIssueEvidenceRating(issueId, issueEvidenceId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); - } - - @PutMapping(value = "/candidates/{candidateId}") - ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { - return ResponseEntity.ok(new EntityModel<>(this.ratingService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelMultiRequest))); - } - - @PutMapping(value = "/candidates/{candidateId}/comments/{candidateCommentId}") - ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateCandidateCommentRating(candidateId, candidateCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); - } - - @PutMapping(value = "/candidates/{candidateId}/evidences/{candidateEvidenceId}") - ResponseEntity> putCandidateEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { - return ResponseEntity.ok(new EntityModel<>(new RatingModel(this.ratingService.updateCandidateEvidenceRating(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); - } -} diff --git a/src/main/java/com/patternpedia/api/service/AuthorService.java b/src/main/java/com/patternpedia/api/service/AuthorService.java deleted file mode 100644 index 51bf4bb..0000000 --- a/src/main/java/com/patternpedia/api/service/AuthorService.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.patternpedia.api.service; - -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.author.CandidateAuthor; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.issue.author.IssueAuthor; -import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.rest.model.shared.AuthorModel; -import com.patternpedia.api.rest.model.shared.AuthorModelRequest; -import org.apache.catalina.User; - -import java.util.Collection; -import java.util.UUID; - -public interface AuthorService { - - IssueAuthor saveIssueAuthor(UUID userId, UUID issueId, AuthorModelRequest authorModelRequest); - void deleteIssueAuthor(UUID userId, UUID issueId); - - CandidateAuthor saveCandidateAuthor(UUID userId, UUID candidateId, AuthorModelRequest authorModelRequest); - void deleteCandidateAuthor(UUID userId, UUID candidateId); -} diff --git a/src/main/java/com/patternpedia/api/service/AuthorServiceImpl.java b/src/main/java/com/patternpedia/api/service/AuthorServiceImpl.java deleted file mode 100644 index 8116fc8..0000000 --- a/src/main/java/com/patternpedia/api/service/AuthorServiceImpl.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.patternpedia.api.service; - -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.author.CandidateAuthor; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.issue.IssueRating; -import com.patternpedia.api.entities.issue.author.IssueAuthor; -import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.repositories.CandidateAuthorRepository; -import com.patternpedia.api.repositories.IssueAuthorRepository; -import com.patternpedia.api.rest.model.shared.AuthorModel; -import com.patternpedia.api.rest.model.shared.AuthorModelRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.UUID; - -@Service -@Transactional -public class AuthorServiceImpl implements AuthorService { - - Logger logger = LoggerFactory.getLogger(AuthorServiceImpl.class); - - private IssueAuthorRepository issueAuthorRepository; - private IssueService issueService; - private CandidateAuthorRepository candidateAuthorRepository; - private CandidateService candidateService; - private UserService userService; - - public AuthorServiceImpl( - IssueAuthorRepository issueAuthorRepository, - IssueService issueService, - CandidateAuthorRepository candidateAuthorRepository, - CandidateService candidateService, - UserService userService - ) { - this.issueAuthorRepository = issueAuthorRepository; - this.issueService = issueService; - this.candidateAuthorRepository = candidateAuthorRepository; - this.candidateService = candidateService; - this.userService = userService; - } - - @Override - @Transactional - public IssueAuthor saveIssueAuthor(UUID userId, UUID issueId, AuthorModelRequest authorModelRequest) { - Issue issue = issueService.getIssueById(issueId); - UserEntity user = userService.getUserById(userId); - IssueAuthor issueAuthor = new IssueAuthor(issue, user, authorModelRequest.getAuthorRole()); - return this.issueAuthorRepository.save(issueAuthor); - } - - @Override - @Transactional - public void deleteIssueAuthor(UUID userId, UUID issueId) { - Issue issue = this.issueService.getIssueById(issueId); - UserEntity user = this.userService.getUserById(userId); - IssueAuthor issueAuthor = new IssueAuthor(issue, user); - if (this.issueAuthorRepository.existsById(issueAuthor.getId())) { - this.issueAuthorRepository.deleteById(issueAuthor.getId()); - } - } - - @Override - @Transactional - public CandidateAuthor saveCandidateAuthor(UUID userId, UUID candidateId, AuthorModelRequest authorModelRequest) { - Candidate candidate = this.candidateService.getCandidateById(candidateId); - UserEntity user = this.userService.getUserById(userId); - CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user, authorModelRequest.getAuthorRole()); - return this.candidateAuthorRepository.save(candidateAuthor); - } - - @Override - @Transactional - public void deleteCandidateAuthor(UUID userId, UUID candidateId) { - Candidate candidate = this.candidateService.getCandidateById(candidateId); - UserEntity user = this.userService.getUserById(userId); - CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user); - if (this.candidateAuthorRepository.existsById(candidateAuthor.getId())) { - this.candidateAuthorRepository.deleteById(candidateAuthor.getId()); - } - } - -} - diff --git a/src/main/java/com/patternpedia/api/service/RatingService.java b/src/main/java/com/patternpedia/api/service/RatingService.java deleted file mode 100644 index 42287f9..0000000 --- a/src/main/java/com/patternpedia/api/service/RatingService.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.patternpedia.api.service; - -import com.patternpedia.api.entities.candidate.CandidateRating; -import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; -import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; -import com.patternpedia.api.entities.issue.IssueRating; -import com.patternpedia.api.entities.issue.comment.IssueCommentRating; -import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; -import com.patternpedia.api.rest.model.shared.RatingModel; -import com.patternpedia.api.rest.model.shared.RatingModelMultiRequest; -import com.patternpedia.api.rest.model.shared.RatingModelRequest; - -import java.util.UUID; - -public interface RatingService { - - IssueRating updateIssueRating(UUID issueId, UUID userId, RatingModelRequest ratingModelRequest); - IssueCommentRating updateIssueCommentRating(UUID issueId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); - IssueEvidenceRating updateIssueEvidenceRating(UUID issueId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest); - - RatingModel updateCandidateRating(UUID candidateId, UUID userId, RatingModelMultiRequest ratingModelMultiRequest); - CandidateCommentRating updateCandidateCommentRating(UUID candidateId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); - CandidateEvidenceRating updateCandidateEvidenceRating(UUID candidateId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest); -} diff --git a/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java b/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java deleted file mode 100644 index 11db01b..0000000 --- a/src/main/java/com/patternpedia/api/service/RatingServiceImpl.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.patternpedia.api.service; - -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.candidate.CandidateRating; -import com.patternpedia.api.entities.candidate.comment.CandidateComment; -import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; -import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; -import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.issue.IssueRating; -import com.patternpedia.api.entities.issue.comment.IssueComment; -import com.patternpedia.api.entities.issue.comment.IssueCommentRating; -import com.patternpedia.api.entities.issue.evidence.IssueEvidence; -import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; -import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.repositories.*; -import com.patternpedia.api.rest.model.shared.RatingModel; -import com.patternpedia.api.rest.model.shared.RatingModelMultiRequest; -import com.patternpedia.api.rest.model.shared.RatingModelRequest; -import com.patternpedia.api.rest.model.shared.RatingType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.persistence.EntityExistsException; -import java.util.UUID; - -@Service -@Transactional -public class RatingServiceImpl implements RatingService { - - Logger logger = LoggerFactory.getLogger(RatingServiceImpl.class); - - private IssueRatingRepository issueRatingRepository; - private IssueCommentRatingRepository issueCommentRatingRepository; - private IssueEvidenceRatingRepository issueEvidenceRatingRepository; - private IssueService issueService; - private CandidateRatingRepository candidateRatingRepository; - private CandidateCommentRatingRepository candidateCommentRatingRepository; - private CandidateEvidenceRatingRepository candidateEvidenceRatingRepository; - private CandidateService candidateService; - private UserService userService; - - public RatingServiceImpl( - IssueRatingRepository issueRatingRepository, - IssueCommentRatingRepository issueCommentRatingRepository, - IssueEvidenceRatingRepository issueEvidenceRatingRepository, - IssueService issueService, - CandidateRatingRepository candidateRatingRepository, - CandidateCommentRatingRepository candidateCommentRatingRepository, - CandidateEvidenceRatingRepository candidateEvidenceRatingRepository, - CandidateService candidateService, - UserService userService - ) { - this.issueRatingRepository = issueRatingRepository; - this.issueCommentRatingRepository = issueCommentRatingRepository; - this.issueEvidenceRatingRepository = issueEvidenceRatingRepository; - this.issueService = issueService; - this.candidateRatingRepository = candidateRatingRepository; - this.candidateCommentRatingRepository = candidateCommentRatingRepository; - this.candidateEvidenceRatingRepository = candidateEvidenceRatingRepository; - this.candidateService = candidateService; - this.userService = userService; - } - - @Override - @Transactional - public IssueRating updateIssueRating(UUID issueId, UUID userId, RatingModelRequest ratingModelRequest) { - Issue issue = this.issueService.getIssueById(issueId); - UserEntity user = this.userService.getUserById(userId); - IssueRating issueRating = new IssueRating(issue, user, ratingModelRequest.getRating()); - - if (this.issueRatingRepository.existsByIdAndRating(issueRating.getId(), issueRating.getRating())) { - this.issueRatingRepository.delete(issueRating); - issueRating.setRating(0); - return issueRating; - } - return this.issueRatingRepository.save(issueRating); - } - - @Override - @Transactional - public IssueCommentRating updateIssueCommentRating(UUID issueId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest) { - Issue issue = this.issueService.getIssueById(issueId); - IssueComment issueComment = this.issueService.getCommentById(commentId); - UserEntity user = this.userService.getUserById(userId); - IssueCommentRating issueCommentRating = new IssueCommentRating(issueComment, user, ratingModelRequest.getRating()); - if (this.issueCommentRatingRepository.existsByIdAndRating(issueCommentRating.getId(), issueCommentRating.getRating())) { - this.issueCommentRatingRepository.delete(issueCommentRating); - issueCommentRating.setRating(0); - return issueCommentRating; - } - return this.issueCommentRatingRepository.save(issueCommentRating); - } - - @Override - @Transactional - public IssueEvidenceRating updateIssueEvidenceRating(UUID issueId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest) { - Issue issue = this.issueService.getIssueById(issueId); - IssueEvidence issueEvidence = this.issueService.getEvidenceById(evidenceID); - UserEntity user = this.userService.getUserById(userId); - IssueEvidenceRating issueEvidenceRating = new IssueEvidenceRating(issueEvidence, user, ratingModelRequest.getRating()); - if (this.issueEvidenceRatingRepository.existsByIdAndRating(issueEvidenceRating.getId(), issueEvidenceRating.getRating())) { - this.issueEvidenceRatingRepository.delete(issueEvidenceRating); - issueEvidenceRating.setRating(0); - return issueEvidenceRating; - } - return this.issueEvidenceRatingRepository.save(issueEvidenceRating); - } - - @Override - @Transactional - public RatingModel updateCandidateRating(UUID candidateId, UUID userId, RatingModelMultiRequest ratingModelMultiRequest) { - Candidate candidate = this.candidateService.getCandidateById(candidateId); - UserEntity user = this.userService.getUserById(userId); - CandidateRating candidateRating = new CandidateRating(candidate, user); - if (this.candidateRatingRepository.existsById(candidateRating.getId())) { - candidateRating = this.candidateRatingRepository.getOne(candidateRating.getId()); - } - if (ratingModelMultiRequest.getRatingType().equals(RatingType.READABILITY)) { - candidateRating.setReadability(ratingModelMultiRequest.getRating()); -// if (this.candidateRatingRepository.existsByIdAndReadability(candidateRating.getId(), candidateRating.getReadability())) { -// candidateRating.setReadability(-1); -// return new RatingModel(candidateRating, candidateRating.getReadability()); -// } - - } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.UNDERSTANDABILITY)) { - candidateRating.setUnderstandability(ratingModelMultiRequest.getRating()); -// if (this.candidateRatingRepository.existsByIdAndUnderstandability(candidateRating.getId(), candidateRating.getUnderstandability())) { -// candidateRating.setUnderstandability(-1); -// return new RatingModel(candidateRating, candidateRating.getUnderstandability()); -// } - - } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.APPROPIATENESS)) { - candidateRating.setAppropriateness(ratingModelMultiRequest.getRating()); -// if (this.candidateRatingRepository.existsByIdAndAppropriateness(candidateRating.getId(), candidateRating.getAppropriateness())) { -// candidateRating.setAppropriateness(-1); -// return new RatingModel(candidateRating, candidateRating.getAppropriateness()); -// } - - } else { - throw new EntityExistsException(String.format("Rating type does not exists", ratingModelMultiRequest.getRatingType())); - } - CandidateRating updatedCandidateRating = this.candidateRatingRepository.save(candidateRating); - - if (ratingModelMultiRequest.getRatingType().equals(RatingType.READABILITY)) { - return new RatingModel(updatedCandidateRating, updatedCandidateRating.getReadability()); - } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.UNDERSTANDABILITY)) { - return new RatingModel(updatedCandidateRating, updatedCandidateRating.getUnderstandability()); - } else{ - return new RatingModel(updatedCandidateRating, updatedCandidateRating.getAppropriateness()); - } - - } - - @Override - @Transactional - public CandidateCommentRating updateCandidateCommentRating(UUID candidateId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest) { - Candidate candidate = this.candidateService.getCandidateById(candidateId); - CandidateComment candidateComment = this.candidateService.getCommentById(commentId); - UserEntity user = this.userService.getUserById(userId); - CandidateCommentRating candidateCommentRating = new CandidateCommentRating(candidateComment, user, ratingModelRequest.getRating()); - if (this.candidateCommentRatingRepository.existsByIdAndRating(candidateCommentRating.getId(), candidateCommentRating.getRating())) { - this.candidateCommentRatingRepository.delete(candidateCommentRating); - candidateCommentRating.setRating(0); - return candidateCommentRating; - } - return this.candidateCommentRatingRepository.save(candidateCommentRating); - } - - @Override - @Transactional - public CandidateEvidenceRating updateCandidateEvidenceRating(UUID candidateId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest) { - Candidate candidate = this.candidateService.getCandidateById(candidateId); - CandidateEvidence candidateEvidence = this.candidateService.getEvidenceById(evidenceID); - UserEntity user = this.userService.getUserById(userId); - CandidateEvidenceRating candidateEvidenceRating = new CandidateEvidenceRating(candidateEvidence, user, ratingModelRequest.getRating()); - if (this.candidateEvidenceRatingRepository.existsByIdAndRating(candidateEvidenceRating.getId(), candidateEvidenceRating.getRating())) { - this.candidateEvidenceRatingRepository.delete(candidateEvidenceRating); - candidateEvidenceRating.setRating(0); - return candidateEvidenceRating; - } - return this.candidateEvidenceRatingRepository.save(candidateEvidenceRating); - } -} diff --git a/src/test/java/com/patternpedia/api/integration/IssueControllerTest.java b/src/test/java/com/patternpedia/api/integration/IssueControllerTest.java new file mode 100644 index 0000000..5fa7108 --- /dev/null +++ b/src/test/java/com/patternpedia/api/integration/IssueControllerTest.java @@ -0,0 +1,4 @@ +package com.patternpedia.api.integration; + +public class IssueControllerTest { +} From 24c651835f187ff0530ecc1d7036d132b40d591d Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Thu, 8 Oct 2020 23:48:40 +0200 Subject: [PATCH 11/68] CHAGE code clean up --- .../api/entities/PatternGraph.java | 7 + .../api/entities/PatternLanguage.java | 2 + .../api/entities/PatternSchema.java | 6 + .../api/entities/user/role/RoleConstant.java | 5 +- .../api/rest/controller/AuthorController.java | 53 +------ .../rest/controller/CandidateController.java | 67 +++++--- .../api/rest/controller/IssueController.java | 65 ++++++-- .../controller/PatternLanguageController.java | 10 ++ .../api/rest/controller/UserController.java | 1 - .../rest/model/candidate/CandidateModel.java | 33 +++- .../api/rest/model/issue/IssueModel.java | 23 ++- .../rest/model/shared/AuthorModelRequest.java | 4 +- .../api/rest/model/shared/CommentModel.java | 54 +++++-- .../api/rest/model/shared/EvidenceModel.java | 67 +++++--- .../api/rest/model/shared/RatingModel.java | 7 - .../api/service/CandidateService.java | 29 +++- .../api/service/CandidateServiceImpl.java | 144 +++++++++++++++--- .../api/service/IssueService.java | 30 +++- .../api/service/IssueServiceImpl.java | 127 ++++++++++++--- .../patternpedia/api/service/UserService.java | 2 - src/main/resources/application.properties | 12 +- 21 files changed, 540 insertions(+), 208 deletions(-) diff --git a/src/main/java/com/patternpedia/api/entities/PatternGraph.java b/src/main/java/com/patternpedia/api/entities/PatternGraph.java index c4e0080..400dfb3 100644 --- a/src/main/java/com/patternpedia/api/entities/PatternGraph.java +++ b/src/main/java/com/patternpedia/api/entities/PatternGraph.java @@ -11,6 +11,8 @@ import lombok.NoArgsConstructor; import org.hibernate.annotations.Type; +import java.util.Objects; + @Entity @Data @EqualsAndHashCode(callSuper = true) @@ -21,4 +23,9 @@ public abstract class PatternGraph extends EntityWithURI { @Type(type = "jsonb") @Column(columnDefinition = "jsonb") private Object graph; + + @Override + public int hashCode() { + return Objects.hash(graph); + } } diff --git a/src/main/java/com/patternpedia/api/entities/PatternLanguage.java b/src/main/java/com/patternpedia/api/entities/PatternLanguage.java index bad2fb4..219a9a2 100644 --- a/src/main/java/com/patternpedia/api/entities/PatternLanguage.java +++ b/src/main/java/com/patternpedia/api/entities/PatternLanguage.java @@ -41,4 +41,6 @@ public class PatternLanguage extends PatternGraph { @JsonIgnore @OneToMany(mappedBy = "patternLanguage", fetch = FetchType.LAZY) private List undirectedEdges; + + } diff --git a/src/main/java/com/patternpedia/api/entities/PatternSchema.java b/src/main/java/com/patternpedia/api/entities/PatternSchema.java index 922d9e7..869927b 100644 --- a/src/main/java/com/patternpedia/api/entities/PatternSchema.java +++ b/src/main/java/com/patternpedia/api/entities/PatternSchema.java @@ -1,6 +1,7 @@ package com.patternpedia.api.entities; import java.util.List; +import java.util.Objects; import java.util.UUID; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -33,4 +34,9 @@ public class PatternSchema { @OneToOne @MapsId private PatternLanguage patternLanguage; + + @Override + public int hashCode() { + return Objects.hash(id, patternSectionSchemas); + } } diff --git a/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java b/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java index dbdadbd..4a8268f 100644 --- a/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java +++ b/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java @@ -2,10 +2,13 @@ public class RoleConstant { public static final String MEMBER = "MEMBER"; - // String AUTHOR = "AUTHOR"; + public static final String HELPER = "HELPER"; + public static final String MAINTAINER = "MAINTAINER"; + public static final String OWNER = "OWNER"; public static final String EXPERT = "EXPERT"; public static final String LIBRARIAN = "LIBRARIAN"; public static final String ADMIN = "ADMIN"; public static final String DEVELOPER = "DEVELOPER"; + } diff --git a/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java b/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java index b41bbc5..311fcba 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java @@ -4,10 +4,9 @@ import com.patternpedia.api.rest.model.candidate.CandidateModel; import com.patternpedia.api.rest.model.issue.IssueModel; import com.patternpedia.api.rest.model.shared.AuthorModel; -import com.patternpedia.api.rest.model.shared.AuthorModelRequest; -import com.patternpedia.api.rest.model.user.UserModel; -import com.patternpedia.api.service.AuthorService; import com.patternpedia.api.service.UserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpStatus; @@ -23,20 +22,18 @@ @RequestMapping(value = "/authors", produces = "application/hal+json") public class AuthorController { - private AuthorService authorService; private UserService userService; public AuthorController( - AuthorService authorService, UserService userService ) { - this.authorService = authorService; this.userService = userService; } /** * GET Methods */ + @Operation(operationId = "getallUsersAsAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all authors") @GetMapping(value = "") CollectionModel> getAll() { List> authors = this.userService.getAllUsers() @@ -46,51 +43,9 @@ CollectionModel> getAll() { return new CollectionModel<>(authors); } + @Operation(operationId = "getAllAuthorRoles", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all author roles") @GetMapping(value = "/roles") String[] getAllRoles() { return new String[]{AuthorConstant.MEMBER, AuthorConstant.MAINTAINER, AuthorConstant.OWNER}; } - - /** - * CREATE Methods - */ - @PostMapping(value = "/{userId}/issues/{issueId}") - @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newIssueAuthor(@PathVariable UUID userId, @PathVariable UUID issueId, @RequestBody AuthorModelRequest authorModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new AuthorModel(this.authorService.saveIssueAuthor(userId, issueId, authorModelRequest)))); - } - - @PostMapping(value = "/{userId}/candidates/{candidateId}") - @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newCandidateAuthor(@PathVariable UUID userId, @PathVariable UUID candidateId, @RequestBody AuthorModelRequest authorModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new AuthorModel(this.authorService.saveCandidateAuthor(userId, candidateId, authorModelRequest)))); - } - - /** - * UPDATE Methods - */ - @PutMapping(value = "/{userId}/issues/{issueId}") - ResponseEntity> putIssueAuthor(@PathVariable UUID userId, @PathVariable UUID issueId, @RequestBody AuthorModelRequest authorModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new AuthorModel(this.authorService.saveIssueAuthor(userId, issueId, authorModelRequest)))); - } - - @PutMapping(value = "/{userId}/candidates/{candidateId}") - ResponseEntity> putCandidateAuthor(@PathVariable UUID userId, @PathVariable UUID candidateId, @RequestBody AuthorModelRequest authorModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new AuthorModel(this.authorService.saveCandidateAuthor(userId, candidateId, authorModelRequest)))); - } - - /** - * DELETE Methods - */ - @DeleteMapping(value = "/{userId}/issues/{issueId}") - ResponseEntity deleteIssueAuthor(@PathVariable UUID userId, @PathVariable UUID issueId) { - this.authorService.deleteIssueAuthor(userId, issueId); - return ResponseEntity.noContent().build(); - } - - @DeleteMapping(value = "/{userId}/candidates/{candidateId}") - ResponseEntity deleteCandidateAuthor(@PathVariable UUID userId, @PathVariable UUID candidateId) { - this.authorService.deleteCandidateAuthor(userId, candidateId); - return ResponseEntity.noContent().build(); - } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java b/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java index 6f8c138..cd2aa87 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java @@ -4,8 +4,8 @@ import com.patternpedia.api.config.Authority; import com.patternpedia.api.rest.model.candidate.CandidateModel; import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; -import com.patternpedia.api.rest.model.shared.CommentModel; -import com.patternpedia.api.rest.model.shared.EvidenceModel; +import com.patternpedia.api.rest.model.issue.IssueModel; +import com.patternpedia.api.rest.model.shared.*; import com.patternpedia.api.service.CandidateService; import com.patternpedia.api.service.PatternLanguageService; import io.swagger.v3.core.util.Json; @@ -90,15 +90,16 @@ ResponseEntity> newCandidate(@RequestBody CandidateM @PostMapping(value = "/{candidateId}/comments") @PreAuthorize(value = Authority.COMMENT) @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { - return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.candidateService.createComment(candidateId, UUID.fromString(principal.getName()), commentModel)))); + ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createComment(candidateId, UUID.fromString(principal.getName()), commentModel)))); } + @Operation(operationId = "createCandidateEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate evidence") @PostMapping(value = "/{candidateId}/evidences") @PreAuthorize(value = Authority.EVIDENCE) @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newIssueEvidence(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { - return ResponseEntity.ok(new EntityModel<>(new EvidenceModel(this.candidateService.createEvidence(candidateId, UUID.fromString(principal.getName()), evidenceModel)))); + ResponseEntity> newIssueEvidence(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createEvidence(candidateId, UUID.fromString(principal.getName()), evidenceModel)))); } /** @@ -106,24 +107,49 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID c */ @Operation(operationId = "updateCandidate", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate") @PutMapping(value = "/{candidateId}") -// @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT) @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidate(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CandidateModelRequest candidateModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidate(candidateId, UUID.fromString(principal.getName()), candidateModelRequest)))); } + @Operation(operationId = "updateCandidateRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate rating") + @PutMapping(value = "/{candidateId}/ratings") + ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); + } + + @Operation(operationId = "updateCandidateAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate authors") + @PutMapping(value = "{candidateId}/authors") + ResponseEntity> putCandidateAuthor(@PathVariable UUID candidateId, @RequestBody AuthorModelRequest authorModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.saveCandidateAuthor(candidateId, authorModelRequest)))); + } + + @Operation(operationId = "updateCandidateComment", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment") @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}") @PreAuthorize(value = Authority.COMMENT) @ResponseStatus(HttpStatus.ACCEPTED) - ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { - return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.candidateService.updateComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()), commentModel)))); + ResponseEntity> putCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()), commentModel)))); + } + + @Operation(operationId = "updateCandidateCommentRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment rating") + @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}/ratings") + ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateCommentRating(candidateId, candidateCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } + @Operation(operationId = "updateCandidateEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence") @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") @PreAuthorize(value = Authority.EVIDENCE) @ResponseStatus(HttpStatus.ACCEPTED) - ResponseEntity> putIssueEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { - return ResponseEntity.ok(new EntityModel<>(new EvidenceModel(this.candidateService.updateEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); + ResponseEntity> putIssueEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); + } + + @Operation(operationId = "updateCandidateEvidenceRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence rating") + @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}/ratings") + ResponseEntity> putCandidateEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateEvidenceRating(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } /** @@ -131,24 +157,31 @@ ResponseEntity> putIssueEvidenceRating(@PathVariable */ @Operation(operationId = "deleteCandidateById", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate by id") @DeleteMapping(value = "/{candidateId}") -// @PreAuthorize(value = Authority.PATTERN_CANDIDATE_DELETE) @ResponseStatus(HttpStatus.OK) ResponseEntity deleteCandidate(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal) { this.candidateService.deleteCandidate(candidateId, UUID.fromString(principal.getName())); return ResponseEntity.noContent().build(); } + @Operation(operationId = "deleteCandidateAuthor", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate author") + @DeleteMapping(value = "{candidateId}/authors/{userId}") + ResponseEntity> deleteCandidateAuthor(@PathVariable UUID candidateId, @PathVariable UUID userId) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteCandidateAuthor(candidateId, userId)))); + } + + @Operation(operationId = "deleteCandidateComment", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate comment") @DeleteMapping(value = "/{candidateId}/comments/{candidateCommentId}") @PreAuthorize(value = Authority.COMMENT) @ResponseStatus(HttpStatus.OK) - ResponseEntity deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal) { - return this.candidateService.deleteComment(candidateId, candidateCommentId, UUID.fromString(principal.getName())); + ResponseEntity> deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()))))); } - @DeleteMapping(value = "/{issueId}/evidences/{issueEvidenceId}") + @Operation(operationId = "deleteCandidateEvidence", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate evidence") + @DeleteMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") @PreAuthorize(value = Authority.EVIDENCE) @ResponseStatus(HttpStatus.OK) - ResponseEntity deleteEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal) { - return this.candidateService.deleteEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName())); + ResponseEntity> deleteEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal) { + return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()))))); } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java b/src/main/java/com/patternpedia/api/rest/controller/IssueController.java index 83d9bf2..282b1d2 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/IssueController.java @@ -2,9 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.patternpedia.api.rest.model.issue.IssueModelRequest; -import com.patternpedia.api.rest.model.shared.CommentModel; +import com.patternpedia.api.rest.model.shared.*; import com.patternpedia.api.rest.model.issue.IssueModel; -import com.patternpedia.api.rest.model.shared.EvidenceModel; import com.patternpedia.api.service.*; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -19,6 +18,7 @@ import org.springframework.web.bind.annotation.*; import java.security.Principal; +import java.util.Comparator; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -52,6 +52,8 @@ CollectionModel> getAll() { List> issues = this.issueService.getAllIssues() .stream() .map(issue -> new EntityModel<>(new IssueModel(issue))) +// .sorted(Comparator.comparingInt(i -> i.getContent().getRating())) + .sorted((i1, i2) -> Integer.compare(i2.getContent().getRating(), i1.getContent().getRating())) .collect(Collectors.toList()); return new CollectionModel<>(issues); } @@ -83,14 +85,15 @@ ResponseEntity> newIssue(@RequestBody IssueModelRequest @Operation(operationId = "createIssueComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue comment") @PostMapping(value = "/{issueId}/comments") @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newIssueComment(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { - return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); + ResponseEntity> newIssueComment(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); } + @Operation(operationId = "createIssueEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue evidence") @PostMapping(value = "/{issueId}/evidences") @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newIssueEvidence(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { - return ResponseEntity.ok(new EntityModel<>(new EvidenceModel(this.issueService.createEvidence(issueId, UUID.fromString(principal.getName()), evidenceModel)))); + ResponseEntity> newIssueEvidence(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createEvidence(issueId, UUID.fromString(principal.getName()), evidenceModel)))); } /** @@ -102,14 +105,40 @@ ResponseEntity> putIssue(@PathVariable UUID issueId, @Au return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssue(issueId, UUID.fromString(principal.getName()), issueModelRequest)))); } + @Operation(operationId = "updateIssueRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue ratings") + @PutMapping(value = "/{issueId}/ratings") + ResponseEntity> putIssueRating(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueRating(issueId, UUID.fromString(principal.getName()), ratingModelRequest)))); + } + + @Operation(operationId = "updateIssueAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue authors") + @PutMapping(value = "{issueId}/authors") + ResponseEntity> putIssueAuthor(@PathVariable UUID issueId, @RequestBody AuthorModelRequest authorModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.saveIssueAuthor(issueId, authorModelRequest)))); + } + + @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment") @PutMapping(value = "/{issueId}/comments/{issueCommentId}") - ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { - return ResponseEntity.ok(new EntityModel<>(new CommentModel(this.issueService.updateComment(issueId, issueCommentId, UUID.fromString(principal.getName()), commentModel)))); + ResponseEntity> putIssueComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateComment(issueId, issueCommentId, UUID.fromString(principal.getName()), commentModel)))); + } + + @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment rating") + @PutMapping(value = "/{issueId}/comments/{issueCommentId}/ratings") + ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } + @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}") - ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { - return ResponseEntity.ok(new EntityModel<>(new EvidenceModel(this.issueService.updateEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); + ResponseEntity> putIssueEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); + } + + @Operation(operationId = "updateIssueEvidenceRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence rating") + @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}/ratings") + ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueEvidenceRating(issueId, issueEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } /** @@ -122,13 +151,21 @@ ResponseEntity deleteIssue(@PathVariable UUID issueId) { return ResponseEntity.noContent().build(); } + @Operation(operationId = "deleteIssueAuthor", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue") + @DeleteMapping(value = "{issueId}/authors/{userId}") + ResponseEntity> deleteIssueAuthor(@PathVariable UUID issueId, @PathVariable UUID userId) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteIssueAuthor(issueId, userId)))); + } + + @Operation(operationId = "deleteIssueComment", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue comment") @DeleteMapping(value = "/{issueId}/comments/{issueCommentId}") - ResponseEntity deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal) { - return this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName())); + ResponseEntity> deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName()))))); } + @Operation(operationId = "deleteIssueEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue evidence") @DeleteMapping(value = "/{issueId}/evidences/{issueEvidenceId}") - ResponseEntity deleteEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal) { - return this.issueService.deleteEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName())); + ResponseEntity> deleteEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()))))); } } diff --git a/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java b/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java index 7356176..5e0f3e7 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java @@ -138,6 +138,16 @@ ResponseEntity deletePatternLanguage(@PathVariable UUID patternLanguageId) return ResponseEntity.noContent().build(); } + @GetMapping(value = "/patternSchemas") + CollectionModel> getAllPatternLanguagesWithSchema() { + List> patternLanguages = this.patternLanguageService.getPatternLanguages() + .stream() + .map(patternLanguage -> new EntityModel<>(new PatternLanguageSchemaModel(patternLanguage))) + .collect(Collectors.toList()); + + return new CollectionModel<>(patternLanguages); + } + @Operation(operationId = "getPatternSchema", responses = {@ApiResponse(responseCode = "200")}, description = "Get pattern schema by pattern language id") @GetMapping(value = "/{patternLanguageId}/patternSchema") EntityModel getPatternSchema(@PathVariable UUID patternLanguageId) { diff --git a/src/main/java/com/patternpedia/api/rest/controller/UserController.java b/src/main/java/com/patternpedia/api/rest/controller/UserController.java index 6d66f43..262bbf9 100644 --- a/src/main/java/com/patternpedia/api/rest/controller/UserController.java +++ b/src/main/java/com/patternpedia/api/rest/controller/UserController.java @@ -4,7 +4,6 @@ import com.patternpedia.api.rest.model.user.*; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; -import com.patternpedia.api.entities.user.UserRole; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; diff --git a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java index 8b28861..01d44a2 100644 --- a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java @@ -30,6 +30,9 @@ public class CandidateModel { private Object content; private String version; // RESPONSE + private double ratingReadability = 0; + private double ratingUnderstandability = 0; + private double ratingAppropriateness = 0; private Collection readability = new ArrayList<>(); private Collection understandability = new ArrayList<>(); private Collection appropriateness = new ArrayList<>(); @@ -47,12 +50,30 @@ public CandidateModel(Candidate candidate) { this.content = candidate.getContent(); this.version = candidate.getVersion(); // RESPONSE - this.readability = candidate.getUserRating().stream().map(candidateRating -> new RatingModel(candidateRating, candidateRating.getReadability())).collect(Collectors.toList()); - this.understandability = candidate.getUserRating().stream().map(candidateRating -> new RatingModel(candidateRating, candidateRating.getUnderstandability())).collect(Collectors.toList()); - this.appropriateness = candidate.getUserRating().stream().map(candidateRating -> new RatingModel(candidateRating, candidateRating.getAppropriateness())).collect(Collectors.toList()); - this.authors = candidate.getAuthors().stream().map(issueAuthor -> new AuthorModel(issueAuthor.getUser(), issueAuthor.getRole())).collect(Collectors.toList()); - this.comments = candidate.getComments().stream().map(issueComment -> CommentModel.from(issueComment)).collect(Collectors.toList()); - this.evidences = candidate.getEvidences().stream().map(candidateEvidence -> EvidenceModel.from(candidateEvidence)).collect(Collectors.toList()); + this.readability = candidate.getUserRating().stream().map(candidateRating -> { + this.ratingReadability += candidateRating.getReadability(); + return new RatingModel(candidateRating, candidateRating.getReadability()); + }).collect(Collectors.toList()); + this.understandability = candidate.getUserRating().stream().map(candidateRating -> { + this.ratingUnderstandability += candidateRating.getUnderstandability(); + return new RatingModel(candidateRating, candidateRating.getUnderstandability()); + }).collect(Collectors.toList()); + this.appropriateness = candidate.getUserRating().stream().map(candidateRating -> { + this.ratingAppropriateness += candidateRating.getAppropriateness(); + return new RatingModel(candidateRating, candidateRating.getAppropriateness()); + }).collect(Collectors.toList()); + + this.ratingReadability = Math.round((this.ratingReadability / this.readability.size()) * 100.0) / 100.0; + this.ratingUnderstandability = Math.round((this.ratingUnderstandability / this.understandability.size()) * 100.0) / 100.0; + this.ratingAppropriateness = Math.round((this.ratingAppropriateness / this.appropriateness.size()) * 100.0) / 100.0; + + this.authors = candidate.getAuthors().stream().map(author -> new AuthorModel(author.getUser(), author.getRole())).collect(Collectors.toList()); + this.comments = candidate.getComments().stream().map(issueComment -> CommentModel.from(issueComment)) + .sorted((o1, o2) -> Integer.compare(o2.getRating(), o1.getRating())) + .collect(Collectors.toList()); + this.evidences = candidate.getEvidences().stream().map(candidateEvidence -> EvidenceModel.from(candidateEvidence)) + .sorted((o1, o2) -> Integer.compare(o2.getRating(), o1.getRating())) + .collect(Collectors.toList()); if (patternLanguage != null) { this.patternLanguageId = patternLanguage.getId(); diff --git a/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java b/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java index 798a8f6..6d0405d 100644 --- a/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java @@ -10,10 +10,7 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; @Data @@ -27,6 +24,7 @@ public class IssueModel { private String description; private String version; // RESPONSE + private int rating; private Collection upVotes = new ArrayList<>(); private Collection downVotes = new ArrayList<>(); private List authors = new ArrayList<>(); @@ -40,14 +38,23 @@ public IssueModel(Issue issue) { this.description = issue.getDescription(); this.version = issue.getVersion(); //Response + this.rating = 0; for (IssueRating issueRating: issue.getUserRating()) { - if (issueRating.getRating() == 1) + if (issueRating.getRating() == 1) { this.upVotes.add(issueRating.getUser().getId()); - if (issueRating.getRating() == -1) + this.rating = this.rating + 1; + } + if (issueRating.getRating() == -1) { this.downVotes.add(issueRating.getUser().getId()); + this.rating = this.rating - 1; + } } this.authors = issue.getAuthors().stream().map(issueAuthor -> new AuthorModel(issueAuthor.getUser(), issueAuthor.getRole())).collect(Collectors.toList()); - this.comments = issue.getComments().stream().map(issueComment -> CommentModel.from(issueComment)).collect(Collectors.toList()); - this.evidences = issue.getEvidences().stream().map(issueEvidence -> EvidenceModel.from(issueEvidence)).collect(Collectors.toList()); + this.comments = issue.getComments().stream().map(issueComment -> CommentModel.from(issueComment)) + .sorted((o1, o2) -> Integer.compare(o2.getRating(), o1.getRating())) + .collect(Collectors.toList()); + this.evidences = issue.getEvidences().stream().map(issueEvidence -> EvidenceModel.from(issueEvidence)) + .sorted((o1, o2) -> Integer.compare(o2.getRating(), o1.getRating())) + .collect(Collectors.toList()); } } diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java b/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java index a885e01..e8b636f 100644 --- a/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java +++ b/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java @@ -9,7 +9,5 @@ @NoArgsConstructor @Data @EqualsAndHashCode(callSuper = false) -public class AuthorModelRequest { - - private String authorRole; +public class AuthorModelRequest extends AuthorModel { } diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java index 96528d3..89771f8 100644 --- a/src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java @@ -22,36 +22,62 @@ public class CommentModel { private UUID userId; private String userName; private String text; + private int rating; private Collection upVotes = new ArrayList<>(); private Collection downVotes = new ArrayList<>(); - /** For Issue Comments*/ + /** + * For Issue Comments + */ public CommentModel(IssueComment issueComment) { - this.id = issueComment.getId(); + this.id = issueComment.getId(); this.userId = issueComment.getUser().getId(); this.userName = issueComment.getUser().getName(); - this.text = issueComment.getText(); - for (IssueCommentRating issueRating: issueComment.getUserRating()) { - if (issueRating.getRating() == 1) + this.text = issueComment.getText(); + this.rating = 0; + for (IssueCommentRating issueRating : issueComment.getUserRating()) { + if (issueRating.getRating() == 1) { this.upVotes.add(issueRating.getUser().getId()); - if (issueRating.getRating() == -1) + this.rating = this.rating + 1; + } + if (issueRating.getRating() == -1) { this.downVotes.add(issueRating.getUser().getId()); + this.rating = this.rating - 1; + } } } - public static CommentModel from(IssueComment issueComment) { return new CommentModel(issueComment); } - /** For Candidate Comments*/ + public static CommentModel from(IssueComment issueComment) { + return new CommentModel(issueComment); + } + + /** + * For Candidate Comments + */ public CommentModel(CandidateComment candidateComment) { - this.id = candidateComment.getId(); + this.id = candidateComment.getId(); this.userId = candidateComment.getUser().getId(); this.userName = candidateComment.getUser().getName(); - this.text = candidateComment.getText(); - for (CandidateCommentRating candidateCommentRating: candidateComment.getUserRating()) { - if (candidateCommentRating.getRating() == 1) + this.text = candidateComment.getText(); + this.rating = 0; + for (CandidateCommentRating candidateCommentRating : candidateComment.getUserRating()) { + if (candidateCommentRating.getRating() == 1) { this.upVotes.add(candidateCommentRating.getUser().getId()); - if (candidateCommentRating.getRating() == -1) + this.rating = this.rating + 1; + } + if (candidateCommentRating.getRating() == -1) { this.downVotes.add(candidateCommentRating.getUser().getId()); + this.rating = this.rating - 1; + } } } - public static CommentModel from(CandidateComment candidateComment) { return new CommentModel(candidateComment); } + + public static CommentModel from(CandidateComment candidateComment) { + return new CommentModel(candidateComment); + } + + public int compareTo(CommentModel o) + { + return(rating - o.rating); + } } diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java index dbf33d2..c3bbf2f 100644 --- a/src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java @@ -29,44 +29,65 @@ public class EvidenceModel { private String type; private Boolean supporting; private String source; + private int rating; private Collection upVotes = new ArrayList<>(); private Collection downVotes = new ArrayList<>(); - /** For Issue Comments*/ + /** + * For Issue Comments + */ public EvidenceModel(IssueEvidence issueEvidence) { - this.id = issueEvidence.getId(); + this.id = issueEvidence.getId(); this.userId = issueEvidence.getUser().getId(); this.userName = issueEvidence.getUser().getName(); - this.title = issueEvidence.getTitle(); - this.context = issueEvidence.getContext(); - this.type = issueEvidence.getType(); - this.supporting = issueEvidence.getSupporting(); - this.source = issueEvidence.getSource(); - for (IssueEvidenceRating issueRating: issueEvidence.getUserRating()) { - if (issueRating.getRating() == 1) + this.title = issueEvidence.getTitle(); + this.context = issueEvidence.getContext(); + this.type = issueEvidence.getType(); + this.supporting = issueEvidence.getSupporting(); + this.source = issueEvidence.getSource(); + this.rating = 0; + for (IssueEvidenceRating issueRating : issueEvidence.getUserRating()) { + if (issueRating.getRating() == 1) { this.upVotes.add(issueRating.getUser().getId()); - if (issueRating.getRating() == -1) + this.rating = this.rating + 1; + } + if (issueRating.getRating() == -1) { this.downVotes.add(issueRating.getUser().getId()); + this.rating = this.rating - 1; + } } } - public static EvidenceModel from(IssueEvidence issueEvidence) { return new EvidenceModel(issueEvidence); } - /** For Candidate Evidence*/ + public static EvidenceModel from(IssueEvidence issueEvidence) { + return new EvidenceModel(issueEvidence); + } + + /** + * For Candidate Evidence + */ public EvidenceModel(CandidateEvidence candidateEvidence) { - this.id = candidateEvidence.getId(); - this.userId = candidateEvidence.getUser().getId(); - this.userName = candidateEvidence.getUser().getName(); - this.title = candidateEvidence.getTitle(); - this.context = candidateEvidence.getContext(); - this.type = candidateEvidence.getType(); + this.id = candidateEvidence.getId(); + this.userId = candidateEvidence.getUser().getId(); + this.userName = candidateEvidence.getUser().getName(); + this.title = candidateEvidence.getTitle(); + this.context = candidateEvidence.getContext(); + this.type = candidateEvidence.getType(); this.supporting = candidateEvidence.getSupporting(); - this.source = candidateEvidence.getSource(); - for (CandidateEvidenceRating candidateEvidenceRating: candidateEvidence.getUserRating()) { - if (candidateEvidenceRating.getRating() == 1) + this.source = candidateEvidence.getSource(); + this.rating = 0; + for (CandidateEvidenceRating candidateEvidenceRating : candidateEvidence.getUserRating()) { + if (candidateEvidenceRating.getRating() == 1) { this.upVotes.add(candidateEvidenceRating.getUser().getId()); - if (candidateEvidenceRating.getRating() == -1) + this.rating = this.rating + 1; + } + if (candidateEvidenceRating.getRating() == -1) { this.downVotes.add(candidateEvidenceRating.getUser().getId()); + this.rating = this.rating - 1; + } } } - public static EvidenceModel from(CandidateEvidence candidateEvidence) { return new EvidenceModel(candidateEvidence); } + + public static EvidenceModel from(CandidateEvidence candidateEvidence) { + return new EvidenceModel(candidateEvidence); + } } diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java index 5b2b958..6f72cc1 100644 --- a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java +++ b/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java @@ -40,13 +40,6 @@ public RatingModel(CandidateRating candidateRating, int rating) { this.userId = candidateRating.getUser().getId(); } -// public RatingModel(CandidateRating candidateRating) { -// int readability = candidateRating.getReadability(); -// int understandability = candidateRating.getUnderstandability(); -// int appropriateness = candidateRating.getAppropriateness(); -// this.userId = candidateRating.getUser().getId(); -// } - public RatingModel(CandidateCommentRating candidateCommentRating) { this.rating = candidateCommentRating.getRating(); this.userId = candidateCommentRating.getUser().getId(); diff --git a/src/main/java/com/patternpedia/api/service/CandidateService.java b/src/main/java/com/patternpedia/api/service/CandidateService.java index 453d340..c333072 100644 --- a/src/main/java/com/patternpedia/api/service/CandidateService.java +++ b/src/main/java/com/patternpedia/api/service/CandidateService.java @@ -1,11 +1,13 @@ package com.patternpedia.api.service; import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.candidate.author.CandidateAuthor; import com.patternpedia.api.entities.candidate.comment.CandidateComment; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; -import com.patternpedia.api.rest.model.shared.CommentModel; -import com.patternpedia.api.rest.model.shared.EvidenceModel; +import com.patternpedia.api.rest.model.shared.*; import org.springframework.http.ResponseEntity; import java.util.List; @@ -24,23 +26,34 @@ public interface CandidateService { Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRequest candidateModelRequest); + Candidate updateCandidateRating(UUID candidateId, UUID userId, RatingModelMultiRequest ratingModelMultiRequest); + void deleteCandidate(UUID candidateId, UUID userId); + /** Author */ + Candidate saveCandidateAuthor(UUID candidateId, AuthorModelRequest authorModelRequest); + + Candidate deleteCandidateAuthor(UUID candidateId, UUID userId); + /** Comment */ - CandidateComment createComment(UUID candidateId, UUID userId, CommentModel commentModel); + Candidate createComment(UUID candidateId, UUID userId, CommentModel commentModel); CandidateComment getCommentById(UUID candidateCommentId); - CandidateComment updateComment(UUID candidateId, UUID commentId, UUID userId, CommentModel commentModel); + Candidate updateComment(UUID candidateId, UUID commentId, UUID userId, CommentModel commentModel); - ResponseEntity deleteComment(UUID candidateId, UUID commentId, UUID userId); + Candidate updateCandidateCommentRating(UUID candidateId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); + + Candidate deleteComment(UUID candidateId, UUID commentId, UUID userId); /** Evidence */ - CandidateEvidence createEvidence(UUID candidateId, UUID userId, EvidenceModel evidenceModel); + Candidate createEvidence(UUID candidateId, UUID userId, EvidenceModel evidenceModel); CandidateEvidence getEvidenceById(UUID evidenceId); - CandidateEvidence updateEvidence(UUID candidateId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); + Candidate updateEvidence(UUID candidateId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); + + Candidate updateCandidateEvidenceRating(UUID candidateId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest); - ResponseEntity deleteEvidence(UUID candidateId, UUID evidenceId, UUID userId); + Candidate deleteEvidence(UUID candidateId, UUID evidenceId, UUID userId); } diff --git a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java index bcbebe1..e77ec49 100644 --- a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java @@ -1,9 +1,12 @@ package com.patternpedia.api.service; import com.patternpedia.api.entities.candidate.Candidate; +import com.patternpedia.api.entities.candidate.CandidateRating; import com.patternpedia.api.entities.candidate.comment.CandidateComment; import com.patternpedia.api.entities.candidate.author.CandidateAuthor; +import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; +import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; import com.patternpedia.api.entities.issue.Issue; import com.patternpedia.api.entities.issue.author.IssueAuthor; import com.patternpedia.api.entities.issue.evidence.IssueEvidence; @@ -12,9 +15,7 @@ import com.patternpedia.api.entities.user.role.PrivilegeConstant; import com.patternpedia.api.repositories.*; import com.patternpedia.api.rest.model.candidate.CandidateModelRequest; -import com.patternpedia.api.rest.model.shared.AuthorModel; -import com.patternpedia.api.rest.model.shared.CommentModel; -import com.patternpedia.api.rest.model.shared.EvidenceModel; +import com.patternpedia.api.rest.model.shared.*; import com.patternpedia.api.util.RatingHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,8 +34,12 @@ public class CandidateServiceImpl implements CandidateService { private CandidateRepository candidateRepository; + private CandidateRatingRepository candidateRatingRepository; + private CandidateAuthorRepository candidateAuthorRepository; private CandidateCommentRepository candidateCommentRepository; + private CandidateCommentRatingRepository candidateCommentRatingRepository; private CandidateEvidenceRepository candidateEvidenceRepository; + private CandidateEvidenceRatingRepository candidateEvidenceRatingRepository; private PatternLanguageService patternLanguageService; private UserService userService; private IssueService issueService; @@ -43,15 +48,23 @@ public class CandidateServiceImpl implements CandidateService { public CandidateServiceImpl( CandidateRepository candidateRepository, + CandidateRatingRepository candidateRatingRepository, + CandidateAuthorRepository candidateAuthorRepository, CandidateCommentRepository candidateCommentRepository, + CandidateCommentRatingRepository candidateCommentRatingRepository, CandidateEvidenceRepository candidateEvidenceRepository, + CandidateEvidenceRatingRepository candidateEvidenceRatingRepository, PatternLanguageService patternLanguageService, UserService userService, IssueService issueService ) { this.candidateRepository = candidateRepository; + this.candidateRatingRepository = candidateRatingRepository; + this.candidateAuthorRepository = candidateAuthorRepository; this.candidateCommentRepository = candidateCommentRepository; + this.candidateCommentRatingRepository = candidateCommentRatingRepository; this.candidateEvidenceRepository = candidateEvidenceRepository; + this.candidateEvidenceRatingRepository = candidateEvidenceRatingRepository; this.patternLanguageService = patternLanguageService; this.userService = userService; this.issueService = issueService; @@ -90,7 +103,7 @@ public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UU } this.issueService.deleteIssue(candidateModelRequest.getIssueId()); } - // ADD authorr + // ADD author if (candidateModelRequest.getAuthors() != null) { for (AuthorModel authorModel : candidateModelRequest.getAuthors()) { newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(authorModel.getUserId()), authorModel.getAuthorRole())); @@ -160,6 +173,40 @@ public Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRe } } + @Override + @Transactional + public Candidate updateCandidateRating(UUID candidateId, UUID userId, RatingModelMultiRequest ratingModelMultiRequest) { + Candidate candidate = this.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(userId); + CandidateRating candidateRating = new CandidateRating(candidate, user); + if (this.candidateRatingRepository.existsById(candidateRating.getId())) { + candidateRating = this.candidateRatingRepository.getOne(candidateRating.getId()); + } + if (ratingModelMultiRequest.getRatingType().equals(RatingType.READABILITY)) { + candidateRating.setReadability(ratingModelMultiRequest.getRating()); + + } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.UNDERSTANDABILITY)) { + candidateRating.setUnderstandability(ratingModelMultiRequest.getRating()); + + } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.APPROPIATENESS)) { + candidateRating.setAppropriateness(ratingModelMultiRequest.getRating()); + + } else { + throw new EntityExistsException(String.format("Rating type does not exists", ratingModelMultiRequest.getRatingType())); + } + CandidateRating updatedCandidateRating = this.candidateRatingRepository.save(candidateRating); + return updatedCandidateRating.getCandidate(); + +// if (ratingModelMultiRequest.getRatingType().equals(RatingType.READABILITY)) { +// return new RatingModel(updatedCandidateRating, updatedCandidateRating.getReadability()); +// } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.UNDERSTANDABILITY)) { +// return new RatingModel(updatedCandidateRating, updatedCandidateRating.getUnderstandability()); +// } else{ +// return new RatingModel(updatedCandidateRating, updatedCandidateRating.getAppropriateness()); +// } + + } + @Override @Transactional public void deleteCandidate(UUID candidateId, UUID userId) { @@ -187,17 +234,43 @@ public boolean authorPermissions(UUID candidateId, UUID userId) { return false; } + /** + * Author + */ + @Override + @Transactional + public Candidate saveCandidateAuthor(UUID candidateId, AuthorModelRequest authorModelRequest) { + Candidate candidate = this.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(authorModelRequest.getUserId()); + CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user, authorModelRequest.getAuthorRole()); + candidateAuthor = this.candidateAuthorRepository.save(candidateAuthor); + return candidateAuthor.getCandidate(); + } + + @Override + @Transactional + public Candidate deleteCandidateAuthor(UUID candidateId, UUID userId) { + Candidate candidate = this.getCandidateById(candidateId); + UserEntity user = this.userService.getUserById(userId); + CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user); + if (this.candidateAuthorRepository.existsById(candidateAuthor.getId())) { + this.candidateAuthorRepository.deleteById(candidateAuthor.getId()); + } + return this.getCandidateById(candidateId); + } + /** * Comment */ @Override @Transactional - public CandidateComment createComment(UUID candidateId, UUID userId, CommentModel commentModel) { + public Candidate createComment(UUID candidateId, UUID userId, CommentModel commentModel) { Candidate candidate = this.getCandidateById(candidateId); UserEntity user = this.userService.getUserById(userId); CandidateComment comment = new CandidateComment(commentModel.getText(), candidate, user); - return this.candidateCommentRepository.save(comment); + comment = this.candidateCommentRepository.save(comment); + return comment.getCandidate(); } @Override @@ -209,7 +282,7 @@ public CandidateComment getCommentById(UUID candidateCommentId) { @Override @Transactional - public CandidateComment updateComment(UUID candidateId, UUID commentId, UUID userId, CommentModel commentModel) { + public Candidate updateComment(UUID candidateId, UUID commentId, UUID userId, CommentModel commentModel) { if (commentModel == null) throw new RuntimeException("Candidate comment to update is null!"); // Used to check if candidate actually exists @@ -217,15 +290,30 @@ public CandidateComment updateComment(UUID candidateId, UUID commentId, UUID use // UPDATE issue comment candidateComment.updateComment(commentModel.getText()); - return this.candidateCommentRepository.save(candidateComment); + candidateComment = this.candidateCommentRepository.save(candidateComment); + return candidateComment.getCandidate(); } @Override @Transactional - public ResponseEntity deleteComment(UUID issueId, UUID commentId, UUID userId) { - this.authCandidateComment(issueId, commentId, userId); + public Candidate updateCandidateCommentRating(UUID candidateId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest) { + Candidate candidate = this.getCandidateById(candidateId); + CandidateComment candidateComment = this.getCommentById(commentId); + UserEntity user = this.userService.getUserById(userId); + CandidateCommentRating candidateCommentRating = new CandidateCommentRating(candidateComment, user, ratingModelRequest.getRating()); + if (this.candidateCommentRatingRepository.existsByIdAndRating(candidateCommentRating.getId(), candidateCommentRating.getRating())) { + candidateCommentRating.setRating(0); + } + candidateCommentRating = this.candidateCommentRatingRepository.save(candidateCommentRating); + return candidateCommentRating.getCandidateComment().getCandidate(); + } + + @Override + @Transactional + public Candidate deleteComment(UUID candidateId, UUID commentId, UUID userId) { + this.authCandidateComment(candidateId, commentId, userId); this.candidateCommentRepository.deleteById(commentId); - return ResponseEntity.noContent().build(); + return this.getCandidateById(candidateId); } private CandidateComment authCandidateComment(UUID candidateId, UUID commentId, UUID userId) { @@ -244,7 +332,7 @@ private CandidateComment authCandidateComment(UUID candidateId, UUID commentId, */ @Override @Transactional - public CandidateEvidence createEvidence(UUID candidateId, UUID userId, EvidenceModel evidenceModel) { + public Candidate createEvidence(UUID candidateId, UUID userId, EvidenceModel evidenceModel) { Candidate candidate = this.getCandidateById(candidateId); UserEntity user = this.userService.getUserById(userId); @@ -255,7 +343,8 @@ public CandidateEvidence createEvidence(UUID candidateId, UUID userId, EvidenceM evidenceModel.getSupporting(), evidenceModel.getSource(), candidate, user); - return this.candidateEvidenceRepository.save(candidateEvidence); + candidateEvidence = this.candidateEvidenceRepository.save(candidateEvidence); + return candidateEvidence.getCandidate(); } @Override @@ -267,24 +356,39 @@ public CandidateEvidence getEvidenceById(UUID evidenceId) { @Override @Transactional - public CandidateEvidence updateEvidence(UUID candidateId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel) { + public Candidate updateEvidence(UUID candidateId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel) { if (evidenceModel == null) throw new RuntimeException("Candidate evidence to update is null!"); - CandidateEvidence candidateEvidence = this.authCandidateEvidence(candidateId, evidenceId, userId); + CandidateEvidence candidateEvidence = this.existsCandidateEvidence(candidateId, evidenceId, userId); // UPDATE Candidate evidence candidateEvidence.updateEvidence(evidenceModel.getTitle(), evidenceModel.getContext(), evidenceModel.getType(), evidenceModel.getSupporting(), evidenceModel.getSource()); - return this.candidateEvidenceRepository.save(candidateEvidence); + candidateEvidence = this.candidateEvidenceRepository.save(candidateEvidence); + return candidateEvidence.getCandidate(); + } + + @Override + @Transactional + public Candidate updateCandidateEvidenceRating(UUID candidateId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest) { + Candidate candidate = this.getCandidateById(candidateId); + CandidateEvidence candidateEvidence = this.getEvidenceById(evidenceID); + UserEntity user = this.userService.getUserById(userId); + CandidateEvidenceRating candidateEvidenceRating = new CandidateEvidenceRating(candidateEvidence, user, ratingModelRequest.getRating()); + if (this.candidateEvidenceRatingRepository.existsByIdAndRating(candidateEvidenceRating.getId(), candidateEvidenceRating.getRating())) { + candidateEvidenceRating.setRating(0); + } + candidateEvidenceRating = this.candidateEvidenceRatingRepository.save(candidateEvidenceRating); + return candidateEvidenceRating.getCandidateEvidence().getCandidate(); } @Override @Transactional - public ResponseEntity deleteEvidence(UUID candidateId, UUID evidenceId, UUID userId) { - this.authCandidateEvidence(candidateId, evidenceId, userId); + public Candidate deleteEvidence(UUID candidateId, UUID evidenceId, UUID userId) { + this.existsCandidateEvidence(candidateId, evidenceId, userId); this.candidateEvidenceRepository.deleteById(evidenceId); - return ResponseEntity.noContent().build(); + return this.getCandidateById(candidateId); } - private CandidateEvidence authCandidateEvidence(UUID candidateId, UUID evidenceId, UUID userId) { + private CandidateEvidence existsCandidateEvidence(UUID candidateId, UUID evidenceId, UUID userId) { CandidateEvidence candidateEvidence = this.getEvidenceById(evidenceId); // CORRECT Evidence if (!candidateEvidence.getCandidate().equals(this.getCandidateById(candidateId))) diff --git a/src/main/java/com/patternpedia/api/service/IssueService.java b/src/main/java/com/patternpedia/api/service/IssueService.java index 612f0e1..3876782 100644 --- a/src/main/java/com/patternpedia/api/service/IssueService.java +++ b/src/main/java/com/patternpedia/api/service/IssueService.java @@ -2,12 +2,18 @@ import java.util.List; +import com.patternpedia.api.entities.issue.IssueRating; +import com.patternpedia.api.entities.issue.author.IssueAuthor; import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.Issue; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; import com.patternpedia.api.entities.issue.evidence.IssueEvidence; +import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; import com.patternpedia.api.rest.model.issue.IssueModelRequest; +import com.patternpedia.api.rest.model.shared.AuthorModelRequest; import com.patternpedia.api.rest.model.shared.CommentModel; import com.patternpedia.api.rest.model.shared.EvidenceModel; +import com.patternpedia.api.rest.model.shared.RatingModelRequest; import org.springframework.http.ResponseEntity; import java.util.UUID; @@ -26,27 +32,39 @@ public interface IssueService { Issue updateIssue(UUID issueId, UUID userId, IssueModelRequest issueModelRequest); + Issue updateIssueRating(UUID issueId, UUID userId, RatingModelRequest ratingModelRequest); + void deleteIssue(UUID issueId); boolean authorPermissions(UUID issueId, UUID userId); + /** Author */ + + Issue saveIssueAuthor(UUID issueId, AuthorModelRequest authorModelRequest); + + Issue deleteIssueAuthor(UUID issueId, UUID userId); + /** Comment */ - IssueComment createComment(UUID issueId, UUID userId, CommentModel commentModel); + Issue createComment(UUID issueId, UUID userId, CommentModel commentModel); IssueComment getCommentById(UUID issueCommentId); - IssueComment updateComment(UUID issueId, UUID commentId, UUID userId, CommentModel commentModel); + Issue updateComment(UUID issueId, UUID commentId, UUID userId, CommentModel commentModel); + + Issue updateIssueCommentRating(UUID issueId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); - ResponseEntity deleteComment(UUID issueId, UUID commentId, UUID userId); + Issue deleteComment(UUID issueId, UUID commentId, UUID userId); /** Evidence */ - IssueEvidence createEvidence(UUID issueId, UUID userId, EvidenceModel evidenceModel); + Issue createEvidence(UUID issueId, UUID userId, EvidenceModel evidenceModel); IssueEvidence getEvidenceById(UUID issueEvidenceId); - IssueEvidence updateEvidence(UUID issueId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); + Issue updateEvidence(UUID issueId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); + + Issue updateIssueEvidenceRating(UUID issueId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest); - ResponseEntity deleteEvidence(UUID issueId, UUID evidenceId, UUID userId); + Issue deleteEvidence(UUID issueId, UUID evidenceId, UUID userId); } diff --git a/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java b/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java index 31d127a..078fc26 100644 --- a/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java +++ b/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java @@ -1,15 +1,20 @@ package com.patternpedia.api.service; +import com.patternpedia.api.entities.issue.IssueRating; import com.patternpedia.api.entities.issue.comment.IssueComment; import com.patternpedia.api.entities.issue.Issue; import com.patternpedia.api.entities.issue.author.IssueAuthor; +import com.patternpedia.api.entities.issue.comment.IssueCommentRating; import com.patternpedia.api.entities.issue.evidence.IssueEvidence; +import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; import com.patternpedia.api.entities.shared.AuthorConstant; import com.patternpedia.api.entities.user.UserEntity; import com.patternpedia.api.repositories.*; import com.patternpedia.api.rest.model.issue.IssueModelRequest; +import com.patternpedia.api.rest.model.shared.AuthorModelRequest; import com.patternpedia.api.rest.model.shared.CommentModel; import com.patternpedia.api.rest.model.shared.EvidenceModel; +import com.patternpedia.api.rest.model.shared.RatingModelRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.rest.webmvc.ResourceNotFoundException; @@ -26,21 +31,33 @@ public class IssueServiceImpl implements IssueService { private IssueRepository issueRepository; + private IssueRatingRepository issueRatingRepository; + private IssueAuthorRepository issueAuthorRepository; private IssueCommentRepository issueCommentRepository; + private IssueCommentRatingRepository issueCommentRatingRepository; private IssueEvidenceRepository issueEvidenceRepository; + private IssueEvidenceRatingRepository issueEvidenceRatingRepository; private UserService userService; Logger logger = LoggerFactory.getLogger(IssueServiceImpl.class); public IssueServiceImpl( IssueRepository issueRepository, + IssueRatingRepository issueRatingRepository, + IssueAuthorRepository issueAuthorRepository, IssueCommentRepository issueCommentRepository, + IssueCommentRatingRepository issueCommentRatingRepository, IssueEvidenceRepository issueEvidenceRepository, + IssueEvidenceRatingRepository issueEvidenceRatingRepository, UserService userService ) { this.issueRepository = issueRepository; + this.issueRatingRepository = issueRatingRepository; + this.issueAuthorRepository = issueAuthorRepository; this.issueCommentRepository = issueCommentRepository; + this.issueCommentRatingRepository = issueCommentRatingRepository; this.issueEvidenceRepository = issueEvidenceRepository; + this.issueEvidenceRatingRepository = issueEvidenceRatingRepository; this.userService = userService; } @@ -109,6 +126,19 @@ public Issue updateIssue(UUID issueId, UUID userId, IssueModelRequest issueModel return this.issueRepository.save(issue); } + @Override + @Transactional + public Issue updateIssueRating(UUID issueId, UUID userId, RatingModelRequest ratingModelRequest) { + Issue issue = this.getIssueById(issueId); + UserEntity user = this.userService.getUserById(userId); + IssueRating issueRating = new IssueRating(issue, user, ratingModelRequest.getRating()); + if (this.issueRatingRepository.existsByIdAndRating(issueRating.getId(), issueRating.getRating())) { + issueRating.setRating(0); + } + issueRating = this.issueRatingRepository.save(issueRating); + return issueRating.getIssue(); + } + @Override @Transactional public void deleteIssue(UUID IssueId) { @@ -130,17 +160,42 @@ public boolean authorPermissions(UUID issueId, UUID userId) { return false; } + /** + * Author + */ + @Override + @Transactional + public Issue saveIssueAuthor(UUID issueId, AuthorModelRequest authorModelRequest) { + Issue issue = this.getIssueById(issueId); + UserEntity user = userService.getUserById(authorModelRequest.getUserId()); + IssueAuthor issueAuthor = new IssueAuthor(issue, user, authorModelRequest.getAuthorRole()); + issueAuthor = this.issueAuthorRepository.save(issueAuthor); + return issueAuthor.getIssue(); + } + + @Override + @Transactional + public Issue deleteIssueAuthor(UUID issueId, UUID userId) { + Issue issue = this.getIssueById(issueId); + UserEntity user = this.userService.getUserById(userId); + IssueAuthor issueAuthor = new IssueAuthor(issue, user); + if (this.issueAuthorRepository.existsById(issueAuthor.getId())) { + this.issueAuthorRepository.deleteById(issueAuthor.getId()); + } + return this.getIssueById(issueId); + } + /** * Comment */ @Override @Transactional - public IssueComment createComment(UUID issueId, UUID userId, CommentModel commentModel) { + public Issue createComment(UUID issueId, UUID userId, CommentModel commentModel) { Issue issue = this.getIssueById(issueId); UserEntity user = this.userService.getUserById(userId); - IssueComment comment = new IssueComment(commentModel.getText(), issue, user); - return this.issueCommentRepository.save(comment); + IssueComment comment = this.issueCommentRepository.save(new IssueComment(commentModel.getText(), issue, user)); + return comment.getIssue(); } @Override @@ -152,24 +207,38 @@ public IssueComment getCommentById(UUID commentId) { @Override @Transactional - public IssueComment updateComment(UUID issueId, UUID commentId, UUID userId, CommentModel commentModel) { + public Issue updateComment(UUID issueId, UUID commentId, UUID userId, CommentModel commentModel) { if (commentModel == null) throw new RuntimeException("Issue comment to update is null!"); - IssueComment issueComment = this.authIssueComment(issueId, commentId, userId); - // UPDATE issue comment - issueComment.updateComment(commentModel.getText()); - return this.issueCommentRepository.save(issueComment); + IssueComment comment = this.existsIssueComment(issueId, commentId, userId); + comment.updateComment(commentModel.getText()); + comment = this.issueCommentRepository.save(comment); + return comment.getIssue(); } @Override @Transactional - public ResponseEntity deleteComment(UUID issueId, UUID commentId, UUID userId) { - this.authIssueComment(issueId, commentId, userId); + public Issue updateIssueCommentRating(UUID issueId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest) { + IssueComment issueComment = this.getCommentById(commentId); + UserEntity user = this.userService.getUserById(userId); + IssueCommentRating issueCommentRating = new IssueCommentRating(issueComment, user, ratingModelRequest.getRating()); + if (this.issueCommentRatingRepository.existsByIdAndRating(issueCommentRating.getId(), issueCommentRating.getRating())) { + issueCommentRating.setRating(0); + } + issueCommentRating = this.issueCommentRatingRepository.save(issueCommentRating); + return issueCommentRating.getIssueComment().getIssue(); + } + + @Override + @Transactional + public Issue deleteComment(UUID issueId, UUID commentId, UUID userId) { + this.existsIssueComment(issueId, commentId, userId); this.issueCommentRepository.deleteById(commentId); - return ResponseEntity.noContent().build(); + return this.getIssueById(issueId); } - private IssueComment authIssueComment(UUID issueId, UUID commentId, UUID userId) { + // Check if Issue comment exists + private IssueComment existsIssueComment(UUID issueId, UUID commentId, UUID userId) { IssueComment issueComment = this.getCommentById(commentId); // CORRECT Issue if (!issueComment.getIssue().equals(this.getIssueById(issueId))) @@ -185,12 +254,13 @@ private IssueComment authIssueComment(UUID issueId, UUID commentId, UUID userId) */ @Override @Transactional - public IssueEvidence createEvidence(UUID issueId, UUID userId, EvidenceModel evidenceModel) { + public Issue createEvidence(UUID issueId, UUID userId, EvidenceModel evidenceModel) { Issue issue = this.getIssueById(issueId); UserEntity user = this.userService.getUserById(userId); IssueEvidence issueEvidence = new IssueEvidence(evidenceModel.getTitle(), evidenceModel.getContext(), evidenceModel.getType(), evidenceModel.getSupporting(), evidenceModel.getSource(), issue, user); - return this.issueEvidenceRepository.save(issueEvidence); + issueEvidence = this.issueEvidenceRepository.save(issueEvidence); + return issueEvidence.getIssue(); } @Override @@ -202,24 +272,39 @@ public IssueEvidence getEvidenceById(UUID issueEvidenceId) { @Override @Transactional - public IssueEvidence updateEvidence(UUID issueId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel) { + public Issue updateEvidence(UUID issueId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel) { if (evidenceModel == null) throw new RuntimeException("Issue comment to update is null!"); - IssueEvidence issueEvidence = this.authIssueEvidence(issueId, evidenceId, userId); + IssueEvidence issueEvidence = this.existsIssueEvidence(issueId, evidenceId, userId); // UPDATE issue evidence issueEvidence.updateEvidence(evidenceModel.getTitle(), evidenceModel.getContext(), evidenceModel.getType(), evidenceModel.getSupporting(), evidenceModel.getSource()); - return this.issueEvidenceRepository.save(issueEvidence); + issueEvidence = this.issueEvidenceRepository.save(issueEvidence); + return issueEvidence.getIssue(); + } + + @Override + @Transactional + public Issue updateIssueEvidenceRating(UUID issueId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest) { + Issue issue = this.getIssueById(issueId); + IssueEvidence issueEvidence = this.getEvidenceById(evidenceID); + UserEntity user = this.userService.getUserById(userId); + IssueEvidenceRating issueEvidenceRating = new IssueEvidenceRating(issueEvidence, user, ratingModelRequest.getRating()); + if (this.issueEvidenceRatingRepository.existsByIdAndRating(issueEvidenceRating.getId(), issueEvidenceRating.getRating())) { + issueEvidenceRating.setRating(0); + } + issueEvidenceRating = this.issueEvidenceRatingRepository.save(issueEvidenceRating); + return issueEvidenceRating.getIssueEvidence().getIssue(); } @Override @Transactional - public ResponseEntity deleteEvidence(UUID issueId, UUID evidenceId, UUID userId) { - this.authIssueEvidence(issueId, evidenceId, userId); + public Issue deleteEvidence(UUID issueId, UUID evidenceId, UUID userId) { + this.existsIssueEvidence(issueId, evidenceId, userId); this.issueEvidenceRepository.deleteById(evidenceId); - return ResponseEntity.noContent().build(); + return this.getIssueById(issueId); } - private IssueEvidence authIssueEvidence(UUID issueId, UUID commentId, UUID userId) { + private IssueEvidence existsIssueEvidence(UUID issueId, UUID commentId, UUID userId) { IssueEvidence issueEvidence = this.getEvidenceById(commentId); // CORRECT Issue if (!issueEvidence.getIssue().equals(this.getIssueById(issueId))) diff --git a/src/main/java/com/patternpedia/api/service/UserService.java b/src/main/java/com/patternpedia/api/service/UserService.java index a664af5..56a07e8 100644 --- a/src/main/java/com/patternpedia/api/service/UserService.java +++ b/src/main/java/com/patternpedia/api/service/UserService.java @@ -21,8 +21,6 @@ public interface UserService { /** Role */ List getAllRoles(); - List getAllPrivileges(); - Role updateRole(UUID roleId, UUID privilegeId, RoleModelRequest roleModelRequest); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3c81189..0a8b234 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,22 +1,18 @@ server.port=8080 -spring.datasource.url=jdbc:postgresql://localhost:5432/patternpedia -spring.datasource.username=patternpedia -spring.datasource.password=patternpedia +spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.username=postgres +spring.datasource.password=postgres spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true spring.jpa.hibernate.ddl-auto=update logging.level.com.patternpedia.api=debug spring.datasource.initialization-mode=always spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true -springdoc.swagger-ui.url=/patternpedia/v3/api-docs -springdoc.swagger-ui.operationsSorter=alpha -springdoc.default-produces-media-type=application/hal+json - security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json #okta.oauth2.issuer=https://dev-918271.okta.com/oauth2/default #okta.oauth2.clientId=0oa1eflyl1wZDVLLg357 # Embedded Tomcat -server.servlet.contextPath=/patternpedia +# server.servlet.contextPath=/patternpedia \ No newline at end of file From 64eda5329d77e91c070f0f2dfd38d551b36fef47 Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Mon, 19 Oct 2020 17:09:25 +0200 Subject: [PATCH 12/68] CHANGED to new db settings --- .docker/docker-compose.yml | 6 +++--- docs/dev/index.md | 2 +- src/main/resources/application.properties | 13 ++++++++----- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index 053a679..ceda43e 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -3,9 +3,9 @@ services: db: image: postgres:10 environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres + POSTGRES_USER: patternpedia + POSTGRES_PASSWORD: patternpedia + POSTGRES_DB: patternpedia ports: - "5432:5432" networks: diff --git a/docs/dev/index.md b/docs/dev/index.md index 0b3f605..6dba51d 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -31,7 +31,7 @@ It runs on Port 8081 #### Turn authentication on/off for PatternPediaAPI If you don't need the capabilities of the PatternPediaAuth server during development. You can follow the instructions in the following file [Security Config file](https://github.com/PatternPedia/pattern-pedia-views-backend/blob/ba-meyer-master/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java) -to turn those off or on. An easier way will be added in future realease. +to turn those off or on. An easier way will be added in a future realease. #### Default User During development default users are diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0a8b234..d71832f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,11 +1,14 @@ server.port=8080 -spring.datasource.url=jdbc:postgresql://localhost:5432/postgres -spring.datasource.username=postgres -spring.datasource.password=postgres +#spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +#spring.datasource.username=postgres +#spring.datasource.password=postgres +spring.datasource.url=jdbc:postgresql://localhost:5432/patternpedia +spring.datasource.username=patternpedia +spring.datasource.password=patternpedia spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true -spring.jpa.hibernate.ddl-auto=update +spring.jpa.hibernate.ddl-auto=create logging.level.com.patternpedia.api=debug spring.datasource.initialization-mode=always spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true @@ -15,4 +18,4 @@ security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks. #okta.oauth2.clientId=0oa1eflyl1wZDVLLg357 # Embedded Tomcat -# server.servlet.contextPath=/patternpedia \ No newline at end of file + server.servlet.contextPath=/patternpedia \ No newline at end of file From 24cffed2214eb43805ab2ec7b3436e0d7f855920 Mon Sep 17 00:00:00 2001 From: Luca Meyer Date: Mon, 19 Oct 2020 17:44:02 +0200 Subject: [PATCH 13/68] CHANGED to authentication off --- .../api/config/ResourceServerConfig.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java index c5e88bd..90818aa 100644 --- a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java +++ b/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java @@ -20,7 +20,7 @@ @Configuration @EnableResourceServer // START::Comment for local development without authorization -@EnableGlobalMethodSecurity(prePostEnabled = true) +//@EnableGlobalMethodSecurity(prePostEnabled = true) // END::Comment for local development without authorization class ResourceServerConfig extends ResourceServerConfigurerAdapter { @@ -33,14 +33,14 @@ public void configure(HttpSecurity http) throws Exception { .authorizeRequests() .antMatchers("/swagger-ui/**").permitAll() // START::Comment for local development with authorization - .antMatchers(HttpMethod.GET, "/**").permitAll() - .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") - .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") - .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('delete')") - .anyRequest().authenticated() +// .antMatchers(HttpMethod.GET, "/**").permitAll() +// .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") +// .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") +// .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('delete')") +// .anyRequest().authenticated() //END::Comment for local development without authorization // START::Uncomment for local development without authorization -// .anyRequest().permitAll() + .anyRequest().permitAll() // END::Uncomment for local development withoutout authorization .and() .sessionManagement() From 0f95fbaad019125af6fff9df878aff62e02670ab Mon Sep 17 00:00:00 2001 From: TYueksel Date: Thu, 15 Jul 2021 20:07:59 +0200 Subject: [PATCH 14/68] Updated .gitignore --- .gitignore | 4 ++++ src/main/java/com/patternpedia/api/.DS_Store | Bin 6148 -> 0 bytes 2 files changed, 4 insertions(+) delete mode 100644 src/main/java/com/patternpedia/api/.DS_Store diff --git a/.gitignore b/.gitignore index a2a3040..1f641f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ + HELP.md target/ !.mvn/wrapper/maven-wrapper.jar @@ -29,3 +30,6 @@ build/ ### VS Code ### .vscode/ + +### MacOS File System ### +**/.DS_STORE diff --git a/src/main/java/com/patternpedia/api/.DS_Store b/src/main/java/com/patternpedia/api/.DS_Store deleted file mode 100644 index 12db7cf64da79dd932ccfccbbd901c4eda211125..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKI|>3Z5S>vG!N$@uSMUZw^aNf&P!vH{5VYRPb9pr1d>UQtw2?P3dC6p6LSC`6 zBO*G#Y-b`95gEY^B@zm@)+3y3!9m+;d(#Yi0p zwti-h{ zq5pp-aYY5Fz+Wk#gT-nw$CI+Qb{=Q7w!qhL%elkNFn0c7o_bQ`6`Nzf VCbof2N8IT^{tTEdG%E0G1s?X~6^#G@ From 0440f46197026c508d87b13e817979597b920e19 Mon Sep 17 00:00:00 2001 From: TYueksel Date: Thu, 15 Jul 2021 20:58:08 +0200 Subject: [PATCH 15/68] rename folders to comply to github scheme --- .../github/patternatlas}/api/PatternPediaAPI.java | 0 .../github/patternatlas}/api/config/Authority.java | 0 .../github/patternatlas}/api/config/ResourceServerConfig.java | 0 .../github/patternatlas}/api/entities/DirectedEdge.java | 0 .../github/patternatlas}/api/entities/DirectedHyperedge.java | 0 .../github/patternatlas}/api/entities/EntityWithURI.java | 0 .../github/patternatlas}/api/entities/Pattern.java | 0 .../github/patternatlas}/api/entities/PatternGraph.java | 0 .../github/patternatlas}/api/entities/PatternGraphType.java | 0 .../github/patternatlas}/api/entities/PatternLanguage.java | 0 .../patternatlas}/api/entities/PatternRelationDescriptor.java | 0 .../github/patternatlas}/api/entities/PatternSchema.java | 0 .../github/patternatlas}/api/entities/PatternSection.java | 0 .../github/patternatlas}/api/entities/PatternSectionSchema.java | 0 .../github/patternatlas}/api/entities/PatternView.java | 0 .../patternatlas}/api/entities/PatternViewDirectedEdge.java | 0 .../patternatlas}/api/entities/PatternViewDirectedEdgeId.java | 0 .../github/patternatlas}/api/entities/PatternViewPattern.java | 0 .../github/patternatlas}/api/entities/PatternViewPatternId.java | 0 .../patternatlas}/api/entities/PatternViewUndirectedEdge.java | 0 .../patternatlas}/api/entities/PatternViewUndirectedEdgeId.java | 0 .../github/patternatlas}/api/entities/UndirectedEdge.java | 0 .../github/patternatlas}/api/entities/UndirectedHyperedge.java | 0 .../github/patternatlas}/api/entities/candidate/Candidate.java | 0 .../patternatlas}/api/entities/candidate/CandidateRating.java | 0 .../api/entities/candidate/author/CandidateAuthor.java | 0 .../api/entities/candidate/comment/CandidateComment.java | 0 .../api/entities/candidate/comment/CandidateCommentRating.java | 0 .../api/entities/candidate/evidence/CandidateEvidence.java | 0 .../api/entities/candidate/evidence/CandidateEvidenceRating.java | 0 .../github/patternatlas}/api/entities/issue/Issue.java | 0 .../github/patternatlas}/api/entities/issue/IssueRating.java | 0 .../patternatlas}/api/entities/issue/author/IssueAuthor.java | 0 .../patternatlas}/api/entities/issue/comment/IssueComment.java | 0 .../api/entities/issue/comment/IssueCommentRating.java | 0 .../patternatlas}/api/entities/issue/evidence/IssueEvidence.java | 0 .../api/entities/issue/evidence/IssueEvidenceRating.java | 0 .../github/patternatlas}/api/entities/shared/AuthorConstant.java | 0 .../github/patternatlas}/api/entities/shared/Comment.java | 0 .../github/patternatlas}/api/entities/shared/CompositeKey.java | 0 .../github/patternatlas}/api/entities/shared/Evidence.java | 0 .../github/patternatlas}/api/entities/user/UserEntity.java | 0 .../github/patternatlas}/api/entities/user/role/Privilege.java | 0 .../patternatlas}/api/entities/user/role/PrivilegeConstant.java | 0 .../github/patternatlas}/api/entities/user/role/Role.java | 0 .../github/patternatlas}/api/entities/user/role/RoleConstant.java | 0 .../api/exception/DirectedEdgeNotFoundException.java | 0 .../patternatlas}/api/exception/NullCandidateException.java | 0 .../github/patternatlas}/api/exception/NullCommentException.java | 0 .../github/patternatlas}/api/exception/NullPatternException.java | 0 .../patternatlas}/api/exception/NullPatternLanguageException.java | 0 .../patternatlas}/api/exception/NullPatternSchemaException.java | 0 .../patternatlas}/api/exception/NullPatternViewException.java | 0 .../github/patternatlas}/api/exception/NullRoleException.java | 0 .../github/patternatlas}/api/exception/NullUserException.java | 0 .../api/exception/PatternLanguageNotFoundException.java | 0 .../patternatlas}/api/exception/PatternNotFoundException.java | 0 .../api/exception/PatternSchemaNotFoundException.java | 0 .../patternatlas}/api/exception/PatternViewNotFoundException.java | 0 .../github/patternatlas}/api/exception/RoleNotFoundException.java | 0 .../api/exception/UndirectedEdgeNotFoundException.java | 0 .../github/patternatlas}/api/exception/UserNotFoundException.java | 0 .../patternatlas}/api/repositories/CandidateAuthorRepository.java | 0 .../api/repositories/CandidateCommentRatingRepository.java | 0 .../api/repositories/CandidateCommentRepository.java | 0 .../api/repositories/CandidateEvidenceRatingRepository.java | 0 .../api/repositories/CandidateEvidenceRepository.java | 0 .../patternatlas}/api/repositories/CandidateRatingRepository.java | 0 .../patternatlas}/api/repositories/CandidateRepository.java | 0 .../patternatlas}/api/repositories/DirectedEdgeRepository.java | 0 .../api/repositories/DirectedHyperedgeRepository.java | 0 .../patternatlas}/api/repositories/IssueAuthorRepository.java | 0 .../api/repositories/IssueCommentRatingRepository.java | 0 .../patternatlas}/api/repositories/IssueCommentRepository.java | 0 .../api/repositories/IssueEvidenceRatingRepository.java | 0 .../patternatlas}/api/repositories/IssueEvidenceRepository.java | 0 .../patternatlas}/api/repositories/IssueRatingRepository.java | 0 .../github/patternatlas}/api/repositories/IssueRepository.java | 0 .../patternatlas}/api/repositories/PatternGraphRepository.java | 0 .../patternatlas}/api/repositories/PatternLanguageRepository.java | 0 .../github/patternatlas}/api/repositories/PatternRepository.java | 0 .../patternatlas}/api/repositories/PatternSchemaRepository.java | 0 .../patternatlas}/api/repositories/PatternSectionRepository.java | 0 .../api/repositories/PatternSectionSchemaRepository.java | 0 .../api/repositories/PatternViewDirectedEdgeRepository.java | 0 .../api/repositories/PatternViewPatternRepository.java | 0 .../patternatlas}/api/repositories/PatternViewRepository.java | 0 .../api/repositories/PatternViewUndirectedEdgeRepository.java | 0 .../patternatlas}/api/repositories/PrivilegeRepository.java | 0 .../github/patternatlas}/api/repositories/RoleRepository.java | 0 .../patternatlas}/api/repositories/UndirectedEdgeReository.java | 0 .../api/repositories/UndirectedHyperedgeRepository.java | 0 .../github/patternatlas}/api/repositories/UserRepository.java | 0 .../patternatlas}/api/rest/controller/AuthorController.java | 0 .../patternatlas}/api/rest/controller/CandidateController.java | 0 .../github/patternatlas}/api/rest/controller/EdgeResult.java | 0 .../github/patternatlas}/api/rest/controller/IssueController.java | 0 .../patternatlas}/api/rest/controller/PatternController.java | 0 .../api/rest/controller/PatternLanguageController.java | 0 .../api/rest/controller/PatternRelationDescriptorController.java | 0 .../patternatlas}/api/rest/controller/PatternViewController.java | 0 .../github/patternatlas}/api/rest/controller/UserController.java | 0 .../api/rest/exception/RestResponseExceptionHandler.java | 0 .../api/rest/model/AddDirectedEdgeToViewRequest.java | 0 .../api/rest/model/AddUndirectedEdgeToViewRequest.java | 0 .../patternatlas}/api/rest/model/CreateDirectedEdgeRequest.java | 0 .../patternatlas}/api/rest/model/CreateUndirectedEdgeRequest.java | 0 .../github/patternatlas}/api/rest/model/DirectedEdgeModel.java | 0 .../github/patternatlas}/api/rest/model/PatternContentModel.java | 0 .../patternatlas}/api/rest/model/PatternLanguageGraphModel.java | 0 .../github/patternatlas}/api/rest/model/PatternLanguageModel.java | 0 .../github/patternatlas}/api/rest/model/PatternModel.java | 0 .../github/patternatlas}/api/rest/model/UndirectedEdgeModel.java | 0 .../patternatlas}/api/rest/model/UpdateDirectedEdgeRequest.java | 0 .../patternatlas}/api/rest/model/UpdateUndirectedEdgeRequest.java | 0 .../patternatlas}/api/rest/model/candidate/CandidateModel.java | 0 .../api/rest/model/candidate/CandidateModelRequest.java | 0 .../github/patternatlas}/api/rest/model/issue/IssueModel.java | 0 .../patternatlas}/api/rest/model/issue/IssueModelRequest.java | 0 .../github/patternatlas}/api/rest/model/shared/AuthorModel.java | 0 .../patternatlas}/api/rest/model/shared/AuthorModelRequest.java | 0 .../github/patternatlas}/api/rest/model/shared/CommentModel.java | 0 .../github/patternatlas}/api/rest/model/shared/EvidenceModel.java | 0 .../api/rest/model/shared/PatternLanguageSchemaModel.java | 0 .../patternatlas}/api/rest/model/shared/PatternSchemaModel.java | 0 .../github/patternatlas}/api/rest/model/shared/RatingModel.java | 0 .../api/rest/model/shared/RatingModelMultiRequest.java | 0 .../patternatlas}/api/rest/model/shared/RatingModelRequest.java | 0 .../github/patternatlas}/api/rest/model/shared/RatingType.java | 0 .../github/patternatlas}/api/rest/model/user/PrivilegeModel.java | 0 .../github/patternatlas}/api/rest/model/user/RoleModel.java | 0 .../patternatlas}/api/rest/model/user/RoleModelRequest.java | 0 .../github/patternatlas}/api/rest/model/user/UserModel.java | 0 .../patternatlas}/api/rest/model/user/UserModelRequest.java | 0 .../github/patternatlas}/api/service/CandidateService.java | 0 .../github/patternatlas}/api/service/CandidateServiceImpl.java | 0 .../github/patternatlas}/api/service/IssueService.java | 0 .../github/patternatlas}/api/service/IssueServiceImpl.java | 0 .../github/patternatlas}/api/service/PatternLanguageService.java | 0 .../patternatlas}/api/service/PatternLanguageServiceImpl.java | 0 .../api/service/PatternRelationDescriptorService.java | 0 .../api/service/PatternRelationDescriptorServiceImpl.java | 0 .../github/patternatlas}/api/service/PatternSchemaService.java | 0 .../patternatlas}/api/service/PatternSchemaServiceImpl.java | 0 .../github/patternatlas}/api/service/PatternService.java | 0 .../github/patternatlas}/api/service/PatternServiceImpl.java | 0 .../github/patternatlas}/api/service/PatternViewService.java | 0 .../github/patternatlas}/api/service/PatternViewServiceImpl.java | 0 .../github/patternatlas}/api/service/UserService.java | 0 .../github/patternatlas}/api/service/UserServiceImpl.java | 0 .../github/patternatlas}/api/util/RatingHelper.java | 0 .../github/patternatlas}/api/util/UriHelper.java | 0 .../patternatlas}/api/validator/PatternContentConstraint.java | 0 .../patternatlas}/api/validator/PatternContentValidator.java | 0 .../github/patternatlas}/api/integration/IntegrationTest.java | 0 .../github/patternatlas}/api/integration/IssueControllerTest.java | 0 .../patternatlas}/api/integration/PatternControllerTest.java | 0 .../api/integration/PatternLanguageControllerTest.java | 0 .../api/integration/PatternRelationDescriptorControllerTest.java | 0 .../github/patternatlas}/api/integration/PatternViewTest.java | 0 .../github/patternatlas}/api/util/IntegrationTestHelper.java | 0 .../github/patternatlas}/api/validator/ValidatorTest.java | 0 162 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/PatternPediaAPI.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/config/Authority.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/config/ResourceServerConfig.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/DirectedEdge.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/DirectedHyperedge.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/EntityWithURI.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/Pattern.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternGraph.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternGraphType.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternLanguage.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternRelationDescriptor.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternSchema.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternSection.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternSectionSchema.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternView.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternViewDirectedEdge.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternViewDirectedEdgeId.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternViewPattern.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternViewPatternId.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternViewUndirectedEdge.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/PatternViewUndirectedEdgeId.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/UndirectedEdge.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/UndirectedHyperedge.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/candidate/Candidate.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/candidate/CandidateRating.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/candidate/author/CandidateAuthor.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/candidate/comment/CandidateComment.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/candidate/comment/CandidateCommentRating.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/candidate/evidence/CandidateEvidence.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/candidate/evidence/CandidateEvidenceRating.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/issue/Issue.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/issue/IssueRating.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/issue/author/IssueAuthor.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/issue/comment/IssueComment.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/issue/comment/IssueCommentRating.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/issue/evidence/IssueEvidence.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/issue/evidence/IssueEvidenceRating.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/shared/AuthorConstant.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/shared/Comment.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/shared/CompositeKey.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/shared/Evidence.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/user/UserEntity.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/user/role/Privilege.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/user/role/PrivilegeConstant.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/user/role/Role.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/entities/user/role/RoleConstant.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/DirectedEdgeNotFoundException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/NullCandidateException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/NullCommentException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/NullPatternException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/NullPatternLanguageException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/NullPatternSchemaException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/NullPatternViewException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/NullRoleException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/NullUserException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/PatternLanguageNotFoundException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/PatternNotFoundException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/PatternSchemaNotFoundException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/PatternViewNotFoundException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/RoleNotFoundException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/UndirectedEdgeNotFoundException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/exception/UserNotFoundException.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/CandidateAuthorRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/CandidateCommentRatingRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/CandidateCommentRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/CandidateEvidenceRatingRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/CandidateEvidenceRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/CandidateRatingRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/CandidateRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/DirectedEdgeRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/DirectedHyperedgeRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/IssueAuthorRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/IssueCommentRatingRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/IssueCommentRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/IssueEvidenceRatingRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/IssueEvidenceRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/IssueRatingRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/IssueRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternGraphRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternLanguageRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternSchemaRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternSectionRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternSectionSchemaRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternViewDirectedEdgeRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternViewPatternRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternViewRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PatternViewUndirectedEdgeRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/PrivilegeRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/RoleRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/UndirectedEdgeReository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/UndirectedHyperedgeRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/repositories/UserRepository.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/AuthorController.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/CandidateController.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/EdgeResult.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/IssueController.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/PatternController.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/PatternLanguageController.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/PatternRelationDescriptorController.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/PatternViewController.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/controller/UserController.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/exception/RestResponseExceptionHandler.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/AddDirectedEdgeToViewRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/AddUndirectedEdgeToViewRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/CreateDirectedEdgeRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/CreateUndirectedEdgeRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/DirectedEdgeModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/PatternContentModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/PatternLanguageGraphModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/PatternLanguageModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/PatternModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/UndirectedEdgeModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/UpdateDirectedEdgeRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/UpdateUndirectedEdgeRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/candidate/CandidateModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/candidate/CandidateModelRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/issue/IssueModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/issue/IssueModelRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/AuthorModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/AuthorModelRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/CommentModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/EvidenceModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/PatternLanguageSchemaModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/PatternSchemaModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/RatingModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/RatingModelMultiRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/RatingModelRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/shared/RatingType.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/user/PrivilegeModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/user/RoleModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/user/RoleModelRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/user/UserModel.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/rest/model/user/UserModelRequest.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/CandidateService.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/CandidateServiceImpl.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/IssueService.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/IssueServiceImpl.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternLanguageService.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternLanguageServiceImpl.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternRelationDescriptorService.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternRelationDescriptorServiceImpl.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternSchemaService.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternSchemaServiceImpl.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternService.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternServiceImpl.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternViewService.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/PatternViewServiceImpl.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/UserService.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/service/UserServiceImpl.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/util/RatingHelper.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/util/UriHelper.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/validator/PatternContentConstraint.java (100%) rename src/main/java/{com/patternpedia => io/github/patternatlas}/api/validator/PatternContentValidator.java (100%) rename src/test/java/{com/patternpedia => io/github/patternatlas}/api/integration/IntegrationTest.java (100%) rename src/test/java/{com/patternpedia => io/github/patternatlas}/api/integration/IssueControllerTest.java (100%) rename src/test/java/{com/patternpedia => io/github/patternatlas}/api/integration/PatternControllerTest.java (100%) rename src/test/java/{com/patternpedia => io/github/patternatlas}/api/integration/PatternLanguageControllerTest.java (100%) rename src/test/java/{com/patternpedia => io/github/patternatlas}/api/integration/PatternRelationDescriptorControllerTest.java (100%) rename src/test/java/{com/patternpedia => io/github/patternatlas}/api/integration/PatternViewTest.java (100%) rename src/test/java/{com/patternpedia => io/github/patternatlas}/api/util/IntegrationTestHelper.java (100%) rename src/test/java/{com/patternpedia => io/github/patternatlas}/api/validator/ValidatorTest.java (100%) diff --git a/src/main/java/com/patternpedia/api/PatternPediaAPI.java b/src/main/java/io/github/patternatlas/api/PatternPediaAPI.java similarity index 100% rename from src/main/java/com/patternpedia/api/PatternPediaAPI.java rename to src/main/java/io/github/patternatlas/api/PatternPediaAPI.java diff --git a/src/main/java/com/patternpedia/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java similarity index 100% rename from src/main/java/com/patternpedia/api/config/Authority.java rename to src/main/java/io/github/patternatlas/api/config/Authority.java diff --git a/src/main/java/com/patternpedia/api/config/ResourceServerConfig.java b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java similarity index 100% rename from src/main/java/com/patternpedia/api/config/ResourceServerConfig.java rename to src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java diff --git a/src/main/java/com/patternpedia/api/entities/DirectedEdge.java b/src/main/java/io/github/patternatlas/api/entities/DirectedEdge.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/DirectedEdge.java rename to src/main/java/io/github/patternatlas/api/entities/DirectedEdge.java diff --git a/src/main/java/com/patternpedia/api/entities/DirectedHyperedge.java b/src/main/java/io/github/patternatlas/api/entities/DirectedHyperedge.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/DirectedHyperedge.java rename to src/main/java/io/github/patternatlas/api/entities/DirectedHyperedge.java diff --git a/src/main/java/com/patternpedia/api/entities/EntityWithURI.java b/src/main/java/io/github/patternatlas/api/entities/EntityWithURI.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/EntityWithURI.java rename to src/main/java/io/github/patternatlas/api/entities/EntityWithURI.java diff --git a/src/main/java/com/patternpedia/api/entities/Pattern.java b/src/main/java/io/github/patternatlas/api/entities/Pattern.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/Pattern.java rename to src/main/java/io/github/patternatlas/api/entities/Pattern.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternGraph.java b/src/main/java/io/github/patternatlas/api/entities/PatternGraph.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternGraph.java rename to src/main/java/io/github/patternatlas/api/entities/PatternGraph.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternGraphType.java b/src/main/java/io/github/patternatlas/api/entities/PatternGraphType.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternGraphType.java rename to src/main/java/io/github/patternatlas/api/entities/PatternGraphType.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternLanguage.java b/src/main/java/io/github/patternatlas/api/entities/PatternLanguage.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternLanguage.java rename to src/main/java/io/github/patternatlas/api/entities/PatternLanguage.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternRelationDescriptor.java b/src/main/java/io/github/patternatlas/api/entities/PatternRelationDescriptor.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternRelationDescriptor.java rename to src/main/java/io/github/patternatlas/api/entities/PatternRelationDescriptor.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternSchema.java b/src/main/java/io/github/patternatlas/api/entities/PatternSchema.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternSchema.java rename to src/main/java/io/github/patternatlas/api/entities/PatternSchema.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternSection.java b/src/main/java/io/github/patternatlas/api/entities/PatternSection.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternSection.java rename to src/main/java/io/github/patternatlas/api/entities/PatternSection.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternSectionSchema.java b/src/main/java/io/github/patternatlas/api/entities/PatternSectionSchema.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternSectionSchema.java rename to src/main/java/io/github/patternatlas/api/entities/PatternSectionSchema.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternView.java b/src/main/java/io/github/patternatlas/api/entities/PatternView.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternView.java rename to src/main/java/io/github/patternatlas/api/entities/PatternView.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternViewDirectedEdge.java b/src/main/java/io/github/patternatlas/api/entities/PatternViewDirectedEdge.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternViewDirectedEdge.java rename to src/main/java/io/github/patternatlas/api/entities/PatternViewDirectedEdge.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternViewDirectedEdgeId.java b/src/main/java/io/github/patternatlas/api/entities/PatternViewDirectedEdgeId.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternViewDirectedEdgeId.java rename to src/main/java/io/github/patternatlas/api/entities/PatternViewDirectedEdgeId.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternViewPattern.java b/src/main/java/io/github/patternatlas/api/entities/PatternViewPattern.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternViewPattern.java rename to src/main/java/io/github/patternatlas/api/entities/PatternViewPattern.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternViewPatternId.java b/src/main/java/io/github/patternatlas/api/entities/PatternViewPatternId.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternViewPatternId.java rename to src/main/java/io/github/patternatlas/api/entities/PatternViewPatternId.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternViewUndirectedEdge.java b/src/main/java/io/github/patternatlas/api/entities/PatternViewUndirectedEdge.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternViewUndirectedEdge.java rename to src/main/java/io/github/patternatlas/api/entities/PatternViewUndirectedEdge.java diff --git a/src/main/java/com/patternpedia/api/entities/PatternViewUndirectedEdgeId.java b/src/main/java/io/github/patternatlas/api/entities/PatternViewUndirectedEdgeId.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/PatternViewUndirectedEdgeId.java rename to src/main/java/io/github/patternatlas/api/entities/PatternViewUndirectedEdgeId.java diff --git a/src/main/java/com/patternpedia/api/entities/UndirectedEdge.java b/src/main/java/io/github/patternatlas/api/entities/UndirectedEdge.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/UndirectedEdge.java rename to src/main/java/io/github/patternatlas/api/entities/UndirectedEdge.java diff --git a/src/main/java/com/patternpedia/api/entities/UndirectedHyperedge.java b/src/main/java/io/github/patternatlas/api/entities/UndirectedHyperedge.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/UndirectedHyperedge.java rename to src/main/java/io/github/patternatlas/api/entities/UndirectedHyperedge.java diff --git a/src/main/java/com/patternpedia/api/entities/candidate/Candidate.java b/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/candidate/Candidate.java rename to src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java diff --git a/src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/candidate/CandidateRating.java rename to src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java diff --git a/src/main/java/com/patternpedia/api/entities/candidate/author/CandidateAuthor.java b/src/main/java/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/candidate/author/CandidateAuthor.java rename to src/main/java/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java diff --git a/src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateComment.java b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateComment.java rename to src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java diff --git a/src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateCommentRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/candidate/comment/CandidateCommentRating.java rename to src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java diff --git a/src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidence.java b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidence.java rename to src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java diff --git a/src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidenceRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/candidate/evidence/CandidateEvidenceRating.java rename to src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java diff --git a/src/main/java/com/patternpedia/api/entities/issue/Issue.java b/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/issue/Issue.java rename to src/main/java/io/github/patternatlas/api/entities/issue/Issue.java diff --git a/src/main/java/com/patternpedia/api/entities/issue/IssueRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/issue/IssueRating.java rename to src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java diff --git a/src/main/java/com/patternpedia/api/entities/issue/author/IssueAuthor.java b/src/main/java/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/issue/author/IssueAuthor.java rename to src/main/java/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java diff --git a/src/main/java/com/patternpedia/api/entities/issue/comment/IssueComment.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/issue/comment/IssueComment.java rename to src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java diff --git a/src/main/java/com/patternpedia/api/entities/issue/comment/IssueCommentRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/issue/comment/IssueCommentRating.java rename to src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java diff --git a/src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidence.java b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidence.java rename to src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java diff --git a/src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidenceRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/issue/evidence/IssueEvidenceRating.java rename to src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java diff --git a/src/main/java/com/patternpedia/api/entities/shared/AuthorConstant.java b/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/shared/AuthorConstant.java rename to src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java diff --git a/src/main/java/com/patternpedia/api/entities/shared/Comment.java b/src/main/java/io/github/patternatlas/api/entities/shared/Comment.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/shared/Comment.java rename to src/main/java/io/github/patternatlas/api/entities/shared/Comment.java diff --git a/src/main/java/com/patternpedia/api/entities/shared/CompositeKey.java b/src/main/java/io/github/patternatlas/api/entities/shared/CompositeKey.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/shared/CompositeKey.java rename to src/main/java/io/github/patternatlas/api/entities/shared/CompositeKey.java diff --git a/src/main/java/com/patternpedia/api/entities/shared/Evidence.java b/src/main/java/io/github/patternatlas/api/entities/shared/Evidence.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/shared/Evidence.java rename to src/main/java/io/github/patternatlas/api/entities/shared/Evidence.java diff --git a/src/main/java/com/patternpedia/api/entities/user/UserEntity.java b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/user/UserEntity.java rename to src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java diff --git a/src/main/java/com/patternpedia/api/entities/user/role/Privilege.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/user/role/Privilege.java rename to src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java diff --git a/src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/user/role/PrivilegeConstant.java rename to src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java diff --git a/src/main/java/com/patternpedia/api/entities/user/role/Role.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/user/role/Role.java rename to src/main/java/io/github/patternatlas/api/entities/user/role/Role.java diff --git a/src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java similarity index 100% rename from src/main/java/com/patternpedia/api/entities/user/role/RoleConstant.java rename to src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java diff --git a/src/main/java/com/patternpedia/api/exception/DirectedEdgeNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/DirectedEdgeNotFoundException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/DirectedEdgeNotFoundException.java rename to src/main/java/io/github/patternatlas/api/exception/DirectedEdgeNotFoundException.java diff --git a/src/main/java/com/patternpedia/api/exception/NullCandidateException.java b/src/main/java/io/github/patternatlas/api/exception/NullCandidateException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/NullCandidateException.java rename to src/main/java/io/github/patternatlas/api/exception/NullCandidateException.java diff --git a/src/main/java/com/patternpedia/api/exception/NullCommentException.java b/src/main/java/io/github/patternatlas/api/exception/NullCommentException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/NullCommentException.java rename to src/main/java/io/github/patternatlas/api/exception/NullCommentException.java diff --git a/src/main/java/com/patternpedia/api/exception/NullPatternException.java b/src/main/java/io/github/patternatlas/api/exception/NullPatternException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/NullPatternException.java rename to src/main/java/io/github/patternatlas/api/exception/NullPatternException.java diff --git a/src/main/java/com/patternpedia/api/exception/NullPatternLanguageException.java b/src/main/java/io/github/patternatlas/api/exception/NullPatternLanguageException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/NullPatternLanguageException.java rename to src/main/java/io/github/patternatlas/api/exception/NullPatternLanguageException.java diff --git a/src/main/java/com/patternpedia/api/exception/NullPatternSchemaException.java b/src/main/java/io/github/patternatlas/api/exception/NullPatternSchemaException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/NullPatternSchemaException.java rename to src/main/java/io/github/patternatlas/api/exception/NullPatternSchemaException.java diff --git a/src/main/java/com/patternpedia/api/exception/NullPatternViewException.java b/src/main/java/io/github/patternatlas/api/exception/NullPatternViewException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/NullPatternViewException.java rename to src/main/java/io/github/patternatlas/api/exception/NullPatternViewException.java diff --git a/src/main/java/com/patternpedia/api/exception/NullRoleException.java b/src/main/java/io/github/patternatlas/api/exception/NullRoleException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/NullRoleException.java rename to src/main/java/io/github/patternatlas/api/exception/NullRoleException.java diff --git a/src/main/java/com/patternpedia/api/exception/NullUserException.java b/src/main/java/io/github/patternatlas/api/exception/NullUserException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/NullUserException.java rename to src/main/java/io/github/patternatlas/api/exception/NullUserException.java diff --git a/src/main/java/com/patternpedia/api/exception/PatternLanguageNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/PatternLanguageNotFoundException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/PatternLanguageNotFoundException.java rename to src/main/java/io/github/patternatlas/api/exception/PatternLanguageNotFoundException.java diff --git a/src/main/java/com/patternpedia/api/exception/PatternNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/PatternNotFoundException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/PatternNotFoundException.java rename to src/main/java/io/github/patternatlas/api/exception/PatternNotFoundException.java diff --git a/src/main/java/com/patternpedia/api/exception/PatternSchemaNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/PatternSchemaNotFoundException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/PatternSchemaNotFoundException.java rename to src/main/java/io/github/patternatlas/api/exception/PatternSchemaNotFoundException.java diff --git a/src/main/java/com/patternpedia/api/exception/PatternViewNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/PatternViewNotFoundException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/PatternViewNotFoundException.java rename to src/main/java/io/github/patternatlas/api/exception/PatternViewNotFoundException.java diff --git a/src/main/java/com/patternpedia/api/exception/RoleNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/RoleNotFoundException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/RoleNotFoundException.java rename to src/main/java/io/github/patternatlas/api/exception/RoleNotFoundException.java diff --git a/src/main/java/com/patternpedia/api/exception/UndirectedEdgeNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/UndirectedEdgeNotFoundException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/UndirectedEdgeNotFoundException.java rename to src/main/java/io/github/patternatlas/api/exception/UndirectedEdgeNotFoundException.java diff --git a/src/main/java/com/patternpedia/api/exception/UserNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/UserNotFoundException.java similarity index 100% rename from src/main/java/com/patternpedia/api/exception/UserNotFoundException.java rename to src/main/java/io/github/patternatlas/api/exception/UserNotFoundException.java diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateAuthorRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/CandidateAuthorRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateCommentRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRatingRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/CandidateCommentRatingRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRatingRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateCommentRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/CandidateCommentRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRatingRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRatingRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRatingRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/CandidateEvidenceRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateRatingRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/CandidateRatingRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/CandidateRatingRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/CandidateRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/CandidateRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/CandidateRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/DirectedEdgeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/DirectedEdgeRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/DirectedEdgeRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/DirectedEdgeRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/DirectedHyperedgeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/DirectedHyperedgeRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/DirectedHyperedgeRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/DirectedHyperedgeRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/IssueAuthorRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueAuthorRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/IssueAuthorRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/IssueAuthorRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/IssueCommentRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueCommentRatingRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/IssueCommentRatingRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/IssueCommentRatingRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/IssueCommentRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueCommentRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/IssueCommentRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/IssueCommentRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/IssueEvidenceRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRatingRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/IssueEvidenceRatingRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRatingRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/IssueEvidenceRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/IssueEvidenceRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/IssueRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueRatingRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/IssueRatingRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/IssueRatingRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/IssueRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/IssueRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/IssueRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternGraphRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternGraphRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternGraphRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternGraphRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternLanguageRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternLanguageRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternLanguageRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternLanguageRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternSchemaRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternSchemaRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternSchemaRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternSchemaRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternSectionRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternSectionRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternSectionRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternSectionRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternSectionSchemaRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternSectionSchemaRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternSectionSchemaRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternSectionSchemaRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternViewDirectedEdgeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternViewDirectedEdgeRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternViewDirectedEdgeRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternViewDirectedEdgeRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternViewPatternRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternViewPatternRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternViewPatternRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternViewPatternRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternViewRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternViewRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternViewRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternViewRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PatternViewUndirectedEdgeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PatternViewUndirectedEdgeRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PatternViewUndirectedEdgeRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PatternViewUndirectedEdgeRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/PrivilegeRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/RoleRepository.java b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/RoleRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/UndirectedEdgeReository.java b/src/main/java/io/github/patternatlas/api/repositories/UndirectedEdgeReository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/UndirectedEdgeReository.java rename to src/main/java/io/github/patternatlas/api/repositories/UndirectedEdgeReository.java diff --git a/src/main/java/com/patternpedia/api/repositories/UndirectedHyperedgeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/UndirectedHyperedgeRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/UndirectedHyperedgeRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/UndirectedHyperedgeRepository.java diff --git a/src/main/java/com/patternpedia/api/repositories/UserRepository.java b/src/main/java/io/github/patternatlas/api/repositories/UserRepository.java similarity index 100% rename from src/main/java/com/patternpedia/api/repositories/UserRepository.java rename to src/main/java/io/github/patternatlas/api/repositories/UserRepository.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/AuthorController.java b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/AuthorController.java rename to src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/CandidateController.java b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/CandidateController.java rename to src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/EdgeResult.java b/src/main/java/io/github/patternatlas/api/rest/controller/EdgeResult.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/EdgeResult.java rename to src/main/java/io/github/patternatlas/api/rest/controller/EdgeResult.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/IssueController.java rename to src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/PatternController.java b/src/main/java/io/github/patternatlas/api/rest/controller/PatternController.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/PatternController.java rename to src/main/java/io/github/patternatlas/api/rest/controller/PatternController.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java b/src/main/java/io/github/patternatlas/api/rest/controller/PatternLanguageController.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/PatternLanguageController.java rename to src/main/java/io/github/patternatlas/api/rest/controller/PatternLanguageController.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/PatternRelationDescriptorController.java b/src/main/java/io/github/patternatlas/api/rest/controller/PatternRelationDescriptorController.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/PatternRelationDescriptorController.java rename to src/main/java/io/github/patternatlas/api/rest/controller/PatternRelationDescriptorController.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/PatternViewController.java b/src/main/java/io/github/patternatlas/api/rest/controller/PatternViewController.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/PatternViewController.java rename to src/main/java/io/github/patternatlas/api/rest/controller/PatternViewController.java diff --git a/src/main/java/com/patternpedia/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/controller/UserController.java rename to src/main/java/io/github/patternatlas/api/rest/controller/UserController.java diff --git a/src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java b/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/exception/RestResponseExceptionHandler.java rename to src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java diff --git a/src/main/java/com/patternpedia/api/rest/model/AddDirectedEdgeToViewRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/AddDirectedEdgeToViewRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/AddDirectedEdgeToViewRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/AddDirectedEdgeToViewRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/AddUndirectedEdgeToViewRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/AddUndirectedEdgeToViewRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/AddUndirectedEdgeToViewRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/AddUndirectedEdgeToViewRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/CreateDirectedEdgeRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/CreateDirectedEdgeRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/CreateDirectedEdgeRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/CreateDirectedEdgeRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/CreateUndirectedEdgeRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/CreateUndirectedEdgeRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/CreateUndirectedEdgeRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/CreateUndirectedEdgeRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/DirectedEdgeModel.java b/src/main/java/io/github/patternatlas/api/rest/model/DirectedEdgeModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/DirectedEdgeModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/DirectedEdgeModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/PatternContentModel.java b/src/main/java/io/github/patternatlas/api/rest/model/PatternContentModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/PatternContentModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/PatternContentModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/PatternLanguageGraphModel.java b/src/main/java/io/github/patternatlas/api/rest/model/PatternLanguageGraphModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/PatternLanguageGraphModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/PatternLanguageGraphModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/PatternLanguageModel.java b/src/main/java/io/github/patternatlas/api/rest/model/PatternLanguageModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/PatternLanguageModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/PatternLanguageModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/PatternModel.java b/src/main/java/io/github/patternatlas/api/rest/model/PatternModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/PatternModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/PatternModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/UndirectedEdgeModel.java b/src/main/java/io/github/patternatlas/api/rest/model/UndirectedEdgeModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/UndirectedEdgeModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/UndirectedEdgeModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/UpdateDirectedEdgeRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/UpdateDirectedEdgeRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/UpdateDirectedEdgeRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/UpdateDirectedEdgeRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/UpdateUndirectedEdgeRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/UpdateUndirectedEdgeRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/UpdateUndirectedEdgeRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/UpdateUndirectedEdgeRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java b/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModelRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/candidate/CandidateModelRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModelRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java b/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/issue/IssueModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/issue/IssueModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModelRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/issue/IssueModelRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModelRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/AuthorModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModelRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/AuthorModelRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModelRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/CommentModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/EvidenceModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/EvidenceModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/EvidenceModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/PatternLanguageSchemaModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/PatternLanguageSchemaModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/PatternSchemaModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternSchemaModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/PatternSchemaModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/PatternSchemaModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/RatingModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModelMultiRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelMultiRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/RatingModelMultiRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelMultiRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/RatingModelRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/shared/RatingType.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/shared/RatingType.java rename to src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java diff --git a/src/main/java/com/patternpedia/api/rest/model/user/PrivilegeModel.java b/src/main/java/io/github/patternatlas/api/rest/model/user/PrivilegeModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/user/PrivilegeModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/user/PrivilegeModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java b/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/user/RoleModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/user/RoleModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/user/RoleModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModelRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/user/RoleModelRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/user/RoleModelRequest.java diff --git a/src/main/java/com/patternpedia/api/rest/model/user/UserModel.java b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/user/UserModel.java rename to src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java diff --git a/src/main/java/com/patternpedia/api/rest/model/user/UserModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java similarity index 100% rename from src/main/java/com/patternpedia/api/rest/model/user/UserModelRequest.java rename to src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java diff --git a/src/main/java/com/patternpedia/api/service/CandidateService.java b/src/main/java/io/github/patternatlas/api/service/CandidateService.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/CandidateService.java rename to src/main/java/io/github/patternatlas/api/service/CandidateService.java diff --git a/src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/CandidateServiceImpl.java rename to src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/service/IssueService.java b/src/main/java/io/github/patternatlas/api/service/IssueService.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/IssueService.java rename to src/main/java/io/github/patternatlas/api/service/IssueService.java diff --git a/src/main/java/com/patternpedia/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/IssueServiceImpl.java rename to src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/service/PatternLanguageService.java b/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternLanguageService.java rename to src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java diff --git a/src/main/java/com/patternpedia/api/service/PatternLanguageServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternLanguageServiceImpl.java rename to src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/service/PatternRelationDescriptorService.java b/src/main/java/io/github/patternatlas/api/service/PatternRelationDescriptorService.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternRelationDescriptorService.java rename to src/main/java/io/github/patternatlas/api/service/PatternRelationDescriptorService.java diff --git a/src/main/java/com/patternpedia/api/service/PatternRelationDescriptorServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternRelationDescriptorServiceImpl.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternRelationDescriptorServiceImpl.java rename to src/main/java/io/github/patternatlas/api/service/PatternRelationDescriptorServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/service/PatternSchemaService.java b/src/main/java/io/github/patternatlas/api/service/PatternSchemaService.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternSchemaService.java rename to src/main/java/io/github/patternatlas/api/service/PatternSchemaService.java diff --git a/src/main/java/com/patternpedia/api/service/PatternSchemaServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternSchemaServiceImpl.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternSchemaServiceImpl.java rename to src/main/java/io/github/patternatlas/api/service/PatternSchemaServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/service/PatternService.java b/src/main/java/io/github/patternatlas/api/service/PatternService.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternService.java rename to src/main/java/io/github/patternatlas/api/service/PatternService.java diff --git a/src/main/java/com/patternpedia/api/service/PatternServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternServiceImpl.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternServiceImpl.java rename to src/main/java/io/github/patternatlas/api/service/PatternServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/service/PatternViewService.java b/src/main/java/io/github/patternatlas/api/service/PatternViewService.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternViewService.java rename to src/main/java/io/github/patternatlas/api/service/PatternViewService.java diff --git a/src/main/java/com/patternpedia/api/service/PatternViewServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternViewServiceImpl.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/PatternViewServiceImpl.java rename to src/main/java/io/github/patternatlas/api/service/PatternViewServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/UserService.java rename to src/main/java/io/github/patternatlas/api/service/UserService.java diff --git a/src/main/java/com/patternpedia/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java similarity index 100% rename from src/main/java/com/patternpedia/api/service/UserServiceImpl.java rename to src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java diff --git a/src/main/java/com/patternpedia/api/util/RatingHelper.java b/src/main/java/io/github/patternatlas/api/util/RatingHelper.java similarity index 100% rename from src/main/java/com/patternpedia/api/util/RatingHelper.java rename to src/main/java/io/github/patternatlas/api/util/RatingHelper.java diff --git a/src/main/java/com/patternpedia/api/util/UriHelper.java b/src/main/java/io/github/patternatlas/api/util/UriHelper.java similarity index 100% rename from src/main/java/com/patternpedia/api/util/UriHelper.java rename to src/main/java/io/github/patternatlas/api/util/UriHelper.java diff --git a/src/main/java/com/patternpedia/api/validator/PatternContentConstraint.java b/src/main/java/io/github/patternatlas/api/validator/PatternContentConstraint.java similarity index 100% rename from src/main/java/com/patternpedia/api/validator/PatternContentConstraint.java rename to src/main/java/io/github/patternatlas/api/validator/PatternContentConstraint.java diff --git a/src/main/java/com/patternpedia/api/validator/PatternContentValidator.java b/src/main/java/io/github/patternatlas/api/validator/PatternContentValidator.java similarity index 100% rename from src/main/java/com/patternpedia/api/validator/PatternContentValidator.java rename to src/main/java/io/github/patternatlas/api/validator/PatternContentValidator.java diff --git a/src/test/java/com/patternpedia/api/integration/IntegrationTest.java b/src/test/java/io/github/patternatlas/api/integration/IntegrationTest.java similarity index 100% rename from src/test/java/com/patternpedia/api/integration/IntegrationTest.java rename to src/test/java/io/github/patternatlas/api/integration/IntegrationTest.java diff --git a/src/test/java/com/patternpedia/api/integration/IssueControllerTest.java b/src/test/java/io/github/patternatlas/api/integration/IssueControllerTest.java similarity index 100% rename from src/test/java/com/patternpedia/api/integration/IssueControllerTest.java rename to src/test/java/io/github/patternatlas/api/integration/IssueControllerTest.java diff --git a/src/test/java/com/patternpedia/api/integration/PatternControllerTest.java b/src/test/java/io/github/patternatlas/api/integration/PatternControllerTest.java similarity index 100% rename from src/test/java/com/patternpedia/api/integration/PatternControllerTest.java rename to src/test/java/io/github/patternatlas/api/integration/PatternControllerTest.java diff --git a/src/test/java/com/patternpedia/api/integration/PatternLanguageControllerTest.java b/src/test/java/io/github/patternatlas/api/integration/PatternLanguageControllerTest.java similarity index 100% rename from src/test/java/com/patternpedia/api/integration/PatternLanguageControllerTest.java rename to src/test/java/io/github/patternatlas/api/integration/PatternLanguageControllerTest.java diff --git a/src/test/java/com/patternpedia/api/integration/PatternRelationDescriptorControllerTest.java b/src/test/java/io/github/patternatlas/api/integration/PatternRelationDescriptorControllerTest.java similarity index 100% rename from src/test/java/com/patternpedia/api/integration/PatternRelationDescriptorControllerTest.java rename to src/test/java/io/github/patternatlas/api/integration/PatternRelationDescriptorControllerTest.java diff --git a/src/test/java/com/patternpedia/api/integration/PatternViewTest.java b/src/test/java/io/github/patternatlas/api/integration/PatternViewTest.java similarity index 100% rename from src/test/java/com/patternpedia/api/integration/PatternViewTest.java rename to src/test/java/io/github/patternatlas/api/integration/PatternViewTest.java diff --git a/src/test/java/com/patternpedia/api/util/IntegrationTestHelper.java b/src/test/java/io/github/patternatlas/api/util/IntegrationTestHelper.java similarity index 100% rename from src/test/java/com/patternpedia/api/util/IntegrationTestHelper.java rename to src/test/java/io/github/patternatlas/api/util/IntegrationTestHelper.java diff --git a/src/test/java/com/patternpedia/api/validator/ValidatorTest.java b/src/test/java/io/github/patternatlas/api/validator/ValidatorTest.java similarity index 100% rename from src/test/java/com/patternpedia/api/validator/ValidatorTest.java rename to src/test/java/io/github/patternatlas/api/validator/ValidatorTest.java From acc68c6300f9028782c5ff9f6015f1869618a11c Mon Sep 17 00:00:00 2001 From: TYueksel Date: Sat, 17 Jul 2021 18:26:33 +0200 Subject: [PATCH 16/68] rename packages --- .../candidate/author/CandidateAuthor.java | 9 +++++---- .../candidate/evidence/CandidateEvidence.java | 12 +++++++----- .../evidence/CandidateEvidenceRating.java | 7 ++++--- .../entities/issue/author/IssueAuthor.java | 9 +++++---- .../issue/evidence/IssueEvidence.java | 10 ++++++---- .../issue/evidence/IssueEvidenceRating.java | 13 +++++++------ .../api/entities/shared/AuthorConstant.java | 2 +- .../api/entities/shared/Evidence.java | 2 +- .../api/exception/NullRoleException.java | 2 +- .../CandidateAuthorRepository.java | 7 ++++--- .../CandidateEvidenceRatingRepository.java | 7 ++++--- .../CandidateEvidenceRepository.java | 4 ++-- .../repositories/IssueAuthorRepository.java | 7 ++++--- .../IssueEvidenceRatingRepository.java | 7 ++++--- .../repositories/IssueEvidenceRepository.java | 7 ++++--- .../api/repositories/PrivilegeRepository.java | 5 +++-- .../api/repositories/RoleRepository.java | 5 +++-- .../api/rest/controller/AuthorController.java | 14 ++++++++------ .../candidate/CandidateModelRequest.java | 9 +++++---- .../rest/model/issue/IssueModelRequest.java | 5 +++-- .../api/rest/model/shared/AuthorModel.java | 9 +++++---- .../rest/model/shared/AuthorModelRequest.java | 2 +- .../api/rest/model/shared/CommentModel.java | 13 +++++++------ .../api/rest/model/shared/EvidenceModel.java | 19 ++++++++++--------- .../shared/PatternLanguageSchemaModel.java | 5 +++-- .../rest/model/shared/PatternSchemaModel.java | 7 ++++--- .../api/rest/model/shared/RatingModel.java | 17 +++++++++-------- .../model/shared/RatingModelMultiRequest.java | 2 +- .../rest/model/shared/RatingModelRequest.java | 2 +- .../api/rest/model/shared/RatingType.java | 2 +- .../api/rest/model/user/PrivilegeModel.java | 5 +++-- .../api/rest/model/user/RoleModel.java | 5 +++-- .../api/rest/model/user/RoleModelRequest.java | 2 +- .../api/rest/model/user/UserModel.java | 15 ++++++++------- .../api/rest/model/user/UserModelRequest.java | 2 +- .../api/integration/IssueControllerTest.java | 2 +- 36 files changed, 140 insertions(+), 112 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java b/src/main/java/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java index 24e989b..cacb72f 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java @@ -1,8 +1,9 @@ -package com.patternpedia.api.entities.candidate.author; +package io.github.patternatlas.api.entities.candidate.author; + +import io.github.patternatlas.api.entities.candidate.Candidate; +import io.github.patternatlas.api.entities.shared.CompositeKey; +import io.github.patternatlas.api.entities.user.UserEntity; -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.shared.CompositeKey; -import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java index 394bb43..11a38c5 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java @@ -1,11 +1,13 @@ -package com.patternpedia.api.entities.candidate.evidence; +package io.github.patternatlas.api.entities.candidate.evidence; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.entities.issue.evidence.IssueEvidence; -import com.patternpedia.api.entities.shared.Evidence; -import com.patternpedia.api.entities.user.UserEntity; + +import io.github.patternatlas.api.entities.candidate.Candidate; +import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence; +import io.github.patternatlas.api.entities.shared.Evidence; +import io.github.patternatlas.api.entities.user.UserEntity; + import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java index 0f803c0..7da3a26 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java @@ -1,7 +1,8 @@ -package com.patternpedia.api.entities.candidate.evidence; +package io.github.patternatlas.api.entities.candidate.evidence; + +import io.github.patternatlas.api.entities.shared.CompositeKey; +import io.github.patternatlas.api.entities.user.UserEntity; -import com.patternpedia.api.entities.shared.CompositeKey; -import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java b/src/main/java/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java index 1c7d2c2..26f2000 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java @@ -1,8 +1,9 @@ -package com.patternpedia.api.entities.issue.author; +package io.github.patternatlas.api.entities.issue.author; + +import io.github.patternatlas.api.entities.issue.Issue; +import io.github.patternatlas.api.entities.shared.CompositeKey; +import io.github.patternatlas.api.entities.user.UserEntity; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.shared.CompositeKey; -import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java index 52b2423..bd7ba6c 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java @@ -1,10 +1,12 @@ -package com.patternpedia.api.entities.issue.evidence; +package io.github.patternatlas.api.entities.issue.evidence; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.shared.Evidence; -import com.patternpedia.api.entities.user.UserEntity; + +import io.github.patternatlas.api.entities.issue.Issue; +import io.github.patternatlas.api.entities.shared.Evidence; +import io.github.patternatlas.api.entities.user.UserEntity; + import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java index f9300d9..5173acf 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java @@ -1,10 +1,11 @@ -package com.patternpedia.api.entities.issue.evidence; +package io.github.patternatlas.api.entities.issue.evidence; + +import io.github.patternatlas.api.entities.issue.Issue; +import io.github.patternatlas.api.entities.issue.comment.IssueComment; +import io.github.patternatlas.api.entities.issue.comment.IssueCommentRating; +import io.github.patternatlas.api.entities.shared.CompositeKey; +import io.github.patternatlas.api.entities.user.UserEntity; -import com.patternpedia.api.entities.issue.Issue; -import com.patternpedia.api.entities.issue.comment.IssueComment; -import com.patternpedia.api.entities.issue.comment.IssueCommentRating; -import com.patternpedia.api.entities.shared.CompositeKey; -import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java b/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java index 54ccad6..4d41a6e 100644 --- a/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.entities.shared; +package io.github.patternatlas.api.entities.shared; public interface AuthorConstant { String OWNER = "OWNER"; diff --git a/src/main/java/io/github/patternatlas/api/entities/shared/Evidence.java b/src/main/java/io/github/patternatlas/api/entities/shared/Evidence.java index 616aec9..8e5ae3d 100644 --- a/src/main/java/io/github/patternatlas/api/entities/shared/Evidence.java +++ b/src/main/java/io/github/patternatlas/api/entities/shared/Evidence.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.entities.shared; +package io.github.patternatlas.api.entities.shared; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/exception/NullRoleException.java b/src/main/java/io/github/patternatlas/api/exception/NullRoleException.java index a962484..48d00e9 100644 --- a/src/main/java/io/github/patternatlas/api/exception/NullRoleException.java +++ b/src/main/java/io/github/patternatlas/api/exception/NullRoleException.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.exception; +package io.github.patternatlas.api.exception; public class NullRoleException extends RuntimeException { diff --git a/src/main/java/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java index ce4b27c..e8a6eb2 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java @@ -1,7 +1,8 @@ -package com.patternpedia.api.repositories; +package io.github.patternatlas.api.repositories; + +import io.github.patternatlas.api.entities.candidate.author.CandidateAuthor; +import io.github.patternatlas.api.entities.shared.CompositeKey; -import com.patternpedia.api.entities.candidate.author.CandidateAuthor; -import com.patternpedia.api.entities.shared.CompositeKey; import org.springframework.data.jpa.repository.JpaRepository; public interface CandidateAuthorRepository extends JpaRepository { diff --git a/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRatingRepository.java index 7108f0e..772880b 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRatingRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRatingRepository.java @@ -1,7 +1,8 @@ -package com.patternpedia.api.repositories; +package io.github.patternatlas.api.repositories; + +import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidenceRating; +import io.github.patternatlas.api.entities.shared.CompositeKey; -import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; -import com.patternpedia.api.entities.shared.CompositeKey; import org.springframework.data.jpa.repository.JpaRepository; public interface CandidateEvidenceRatingRepository extends JpaRepository { diff --git a/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java index 9057e6e..256a265 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java @@ -1,6 +1,6 @@ -package com.patternpedia.api.repositories; +package io.github.patternatlas.api.repositories; -import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; +import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidence; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; diff --git a/src/main/java/io/github/patternatlas/api/repositories/IssueAuthorRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueAuthorRepository.java index 444668b..f26d18d 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/IssueAuthorRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/IssueAuthorRepository.java @@ -1,7 +1,8 @@ -package com.patternpedia.api.repositories; +package io.github.patternatlas.api.repositories; + +import io.github.patternatlas.api.entities.issue.author.IssueAuthor; +import io.github.patternatlas.api.entities.shared.CompositeKey; -import com.patternpedia.api.entities.issue.author.IssueAuthor; -import com.patternpedia.api.entities.shared.CompositeKey; import org.springframework.data.jpa.repository.JpaRepository; public interface IssueAuthorRepository extends JpaRepository { diff --git a/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRatingRepository.java index 7502584..0486604 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRatingRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRatingRepository.java @@ -1,7 +1,8 @@ -package com.patternpedia.api.repositories; +package io.github.patternatlas.api.repositories; + +import io.github.patternatlas.api.entities.issue.evidence.IssueEvidenceRating; +import io.github.patternatlas.api.entities.shared.CompositeKey; -import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; -import com.patternpedia.api.entities.shared.CompositeKey; import org.springframework.data.jpa.repository.JpaRepository; public interface IssueEvidenceRatingRepository extends JpaRepository { diff --git a/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java index da87bc1..9075312 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java @@ -1,7 +1,8 @@ -package com.patternpedia.api.repositories; +package io.github.patternatlas.api.repositories; + +import io.github.patternatlas.api.entities.issue.comment.IssueComment; +import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence; -import com.patternpedia.api.entities.issue.comment.IssueComment; -import com.patternpedia.api.entities.issue.evidence.IssueEvidence; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java index f079f79..8f5ad9f 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java @@ -1,6 +1,7 @@ -package com.patternpedia.api.repositories; +package io.github.patternatlas.api.repositories; + +import io.github.patternatlas.api.entities.user.role.Privilege; -import com.patternpedia.api.entities.user.role.Privilege; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; diff --git a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java index cd656d1..b620f74 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java @@ -1,6 +1,7 @@ -package com.patternpedia.api.repositories; +package io.github.patternatlas.api.repositories; + +import io.github.patternatlas.api.entities.user.role.Role; -import com.patternpedia.api.entities.user.role.Role; import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java index 311fcba..50a8098 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java @@ -1,12 +1,14 @@ -package com.patternpedia.api.rest.controller; +package io.github.patternatlas.api.rest.controller; + +import io.github.patternatlas.api.entities.shared.AuthorConstant; +import io.github.patternatlas.api.rest.model.candidate.CandidateModel; +import io.github.patternatlas.api.rest.model.issue.IssueModel; +import io.github.patternatlas.api.rest.model.shared.AuthorModel; +import io.github.patternatlas.api.service.UserService; -import com.patternpedia.api.entities.shared.AuthorConstant; -import com.patternpedia.api.rest.model.candidate.CandidateModel; -import com.patternpedia.api.rest.model.issue.IssueModel; -import com.patternpedia.api.rest.model.shared.AuthorModel; -import com.patternpedia.api.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; + import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpStatus; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModelRequest.java index 48902db..e11cdc0 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModelRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModelRequest.java @@ -1,8 +1,9 @@ -package com.patternpedia.api.rest.model.candidate; +package io.github.patternatlas.api.rest.model.candidate; + +import io.github.patternatlas.api.entities.candidate.Candidate; +import io.github.patternatlas.api.rest.model.shared.AuthorModel; +import io.github.patternatlas.api.rest.model.user.UserModel; -import com.patternpedia.api.entities.candidate.Candidate; -import com.patternpedia.api.rest.model.shared.AuthorModel; -import com.patternpedia.api.rest.model.user.UserModel; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModelRequest.java index 1131d7e..5719170 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModelRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModelRequest.java @@ -1,6 +1,7 @@ -package com.patternpedia.api.rest.model.issue; +package io.github.patternatlas.api.rest.model.issue; + +import io.github.patternatlas.api.rest.model.shared.AuthorModel; -import com.patternpedia.api.rest.model.shared.AuthorModel; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModel.java index fd102ac..f0a1f6d 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModel.java @@ -1,8 +1,9 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; + +import io.github.patternatlas.api.entities.candidate.author.CandidateAuthor; +import io.github.patternatlas.api.entities.issue.author.IssueAuthor; +import io.github.patternatlas.api.entities.user.UserEntity; -import com.patternpedia.api.entities.candidate.author.CandidateAuthor; -import com.patternpedia.api.entities.issue.author.IssueAuthor; -import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModelRequest.java index e8b636f..1283cc3 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModelRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/AuthorModelRequest.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java index 89771f8..06beeb9 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java @@ -1,10 +1,11 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; + +import io.github.patternatlas.api.entities.candidate.comment.CandidateComment; +import io.github.patternatlas.api.entities.candidate.comment.CandidateCommentRating; +import io.github.patternatlas.api.entities.issue.IssueRating; +import io.github.patternatlas.api.entities.issue.comment.IssueComment; +import io.github.patternatlas.api.entities.issue.comment.IssueCommentRating; -import com.patternpedia.api.entities.candidate.comment.CandidateComment; -import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; -import com.patternpedia.api.entities.issue.IssueRating; -import com.patternpedia.api.entities.issue.comment.IssueComment; -import com.patternpedia.api.entities.issue.comment.IssueCommentRating; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/EvidenceModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/EvidenceModel.java index c3bbf2f..3afe496 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/EvidenceModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/EvidenceModel.java @@ -1,13 +1,14 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; + +import io.github.patternatlas.api.entities.candidate.comment.CandidateComment; +import io.github.patternatlas.api.entities.candidate.comment.CandidateCommentRating; +import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidence; +import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidenceRating; +import io.github.patternatlas.api.entities.issue.comment.IssueComment; +import io.github.patternatlas.api.entities.issue.comment.IssueCommentRating; +import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence; +import io.github.patternatlas.api.entities.issue.evidence.IssueEvidenceRating; -import com.patternpedia.api.entities.candidate.comment.CandidateComment; -import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; -import com.patternpedia.api.entities.candidate.evidence.CandidateEvidence; -import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; -import com.patternpedia.api.entities.issue.comment.IssueComment; -import com.patternpedia.api.entities.issue.comment.IssueCommentRating; -import com.patternpedia.api.entities.issue.evidence.IssueEvidence; -import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java index d8f54db..ca57b1b 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java @@ -1,6 +1,7 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; + +import io.github.patternatlas.api.entities.PatternLanguage; -import com.patternpedia.api.entities.PatternLanguage; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternSchemaModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternSchemaModel.java index 59439b4..5e7f648 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternSchemaModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternSchemaModel.java @@ -1,7 +1,8 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; + +import io.github.patternatlas.api.entities.PatternSection; +import io.github.patternatlas.api.entities.PatternSectionSchema; -import com.patternpedia.api.entities.PatternSection; -import com.patternpedia.api.entities.PatternSectionSchema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModel.java index 6f72cc1..cf28557 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModel.java @@ -1,11 +1,12 @@ -package com.patternpedia.api.rest.model.shared; - -import com.patternpedia.api.entities.candidate.CandidateRating; -import com.patternpedia.api.entities.candidate.comment.CandidateCommentRating; -import com.patternpedia.api.entities.candidate.evidence.CandidateEvidenceRating; -import com.patternpedia.api.entities.issue.IssueRating; -import com.patternpedia.api.entities.issue.comment.IssueCommentRating; -import com.patternpedia.api.entities.issue.evidence.IssueEvidenceRating; +package io.github.patternatlas.api.rest.model.shared; + +import io.github.patternatlas.api.entities.candidate.CandidateRating; +import io.github.patternatlas.api.entities.candidate.comment.CandidateCommentRating; +import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidenceRating; +import io.github.patternatlas.api.entities.issue.IssueRating; +import io.github.patternatlas.api.entities.issue.comment.IssueCommentRating; +import io.github.patternatlas.api.entities.issue.evidence.IssueEvidenceRating; + import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelMultiRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelMultiRequest.java index a18f3e0..26d9846 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelMultiRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelMultiRequest.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelRequest.java index d8aeb06..f5badb8 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingModelRequest.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java index 97d9b7d..1e56281 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.rest.model.shared; +package io.github.patternatlas.api.rest.model.shared; public enum RatingType { READABILITY, diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/PrivilegeModel.java b/src/main/java/io/github/patternatlas/api/rest/model/user/PrivilegeModel.java index 0a3e3e0..cd5d05f 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/PrivilegeModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/PrivilegeModel.java @@ -1,6 +1,7 @@ -package com.patternpedia.api.rest.model.user; +package io.github.patternatlas.api.rest.model.user; + +import io.github.patternatlas.api.entities.user.role.Privilege; -import com.patternpedia.api.entities.user.role.Privilege; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModel.java b/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModel.java index cb89209..f9b1814 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModel.java @@ -1,6 +1,7 @@ -package com.patternpedia.api.rest.model.user; +package io.github.patternatlas.api.rest.model.user; + +import io.github.patternatlas.api.entities.user.role.Role; -import com.patternpedia.api.entities.user.role.Role; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModelRequest.java index f847d1c..6f32e86 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModelRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/RoleModelRequest.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.rest.model.user; +package io.github.patternatlas.api.rest.model.user; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java index 1011a89..78b8214 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java @@ -1,11 +1,12 @@ -package com.patternpedia.api.rest.model.user; +package io.github.patternatlas.api.rest.model.user; + +import io.github.patternatlas.api.entities.user.UserEntity; +import io.github.patternatlas.api.rest.model.candidate.CandidateModel; +import io.github.patternatlas.api.rest.model.issue.IssueModel; +import io.github.patternatlas.api.rest.model.shared.CommentModel; +import io.github.patternatlas.api.rest.model.shared.EvidenceModel; +import io.github.patternatlas.api.rest.model.shared.RatingModel; -import com.patternpedia.api.entities.user.UserEntity; -import com.patternpedia.api.rest.model.candidate.CandidateModel; -import com.patternpedia.api.rest.model.issue.IssueModel; -import com.patternpedia.api.rest.model.shared.CommentModel; -import com.patternpedia.api.rest.model.shared.EvidenceModel; -import com.patternpedia.api.rest.model.shared.RatingModel; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java index 5fa3f4b..6b5a643 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.rest.model.user; +package io.github.patternatlas.api.rest.model.user; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/test/java/io/github/patternatlas/api/integration/IssueControllerTest.java b/src/test/java/io/github/patternatlas/api/integration/IssueControllerTest.java index 5fa7108..5b52bdb 100644 --- a/src/test/java/io/github/patternatlas/api/integration/IssueControllerTest.java +++ b/src/test/java/io/github/patternatlas/api/integration/IssueControllerTest.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.integration; +package io.github.patternatlas.api.integration; public class IssueControllerTest { } From 158adb4724812a46eeb5b33ecd2e9e17cf66444e Mon Sep 17 00:00:00 2001 From: TYueksel Date: Sat, 17 Jul 2021 19:13:08 +0200 Subject: [PATCH 17/68] renamed packages --- .../java/io/github/patternatlas/api/config/Authority.java | 2 +- .../entities/candidate/comment/CandidateCommentRating.java | 2 +- .../api/entities/issue/comment/IssueComment.java | 2 +- .../api/entities/issue/comment/IssueCommentRating.java | 4 ++-- .../patternatlas/api/entities/user/role/Privilege.java | 2 +- .../api/entities/user/role/PrivilegeConstant.java | 2 +- .../io/github/patternatlas/api/entities/user/role/Role.java | 5 +++-- .../patternatlas/api/entities/user/role/RoleConstant.java | 2 +- .../patternatlas/api/rest/controller/UserController.java | 2 +- .../api/rest/model/PatternLanguageGraphModel.java | 2 +- 10 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java index 1393a27..6ba5017 100644 --- a/src/main/java/io/github/patternatlas/api/config/Authority.java +++ b/src/main/java/io/github/patternatlas/api/config/Authority.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.config; +package io.github.patternatlas.api.config; public interface Authority { /** ISSUE */ diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java index d3ef7b8..7f7ec77 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java @@ -6,7 +6,7 @@ import javax.persistence.ManyToOne; import javax.persistence.MapsId; -import io.github.patternatlas.api.entities.candidate.CandidateComment; +import io.github.patternatlas.api.entities.candidate.comment.CandidateComment; import io.github.patternatlas.api.entities.user.UserEntity; import io.github.patternatlas.api.entities.shared.CompositeKey; diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java index 4df3a93..64721a0 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java @@ -1,4 +1,4 @@ -package io.github.patternatlas.api.entities.issue; +package io.github.patternatlas.api.entities.issue.comment; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java index a13c946..f671a90 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java @@ -7,8 +7,8 @@ import javax.persistence.MapsId; import io.github.patternatlas.api.entities.user.UserEntity; -import io.github.patternatlas.api.entities.issue.IssueComment; -import com.patternpedia.api.entities.shared.CompositeKey; +import io.github.patternatlas.api.entities.issue.comment.IssueComment; +import io.github.patternatlas.api.entities.shared.CompositeKey; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java index fa3e730..939f403 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.entities.user.role; +package io.github.patternatlas.api.entities.user.role; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java index d913d18..65ed6ed 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.entities.user.role; +package io.github.patternatlas.api.entities.user.role; public class PrivilegeConstant { /** ISSUE */ diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java index 9c776ee..a5739e7 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java @@ -1,6 +1,7 @@ -package com.patternpedia.api.entities.user.role; +package io.github.patternatlas.api.entities.user.role; + +import io.github.patternatlas.api.entities.user.UserEntity; -import com.patternpedia.api.entities.user.UserEntity; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java index 4a8268f..aed35c3 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java @@ -1,4 +1,4 @@ -package com.patternpedia.api.entities.user.role; +package io.github.patternatlas.api.entities.user.role; public class RoleConstant { public static final String MEMBER = "MEMBER"; diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 1f56478..052ae2c 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -2,6 +2,7 @@ import io.github.patternatlas.api.config.Authority; import io.github.patternatlas.api.rest.model.user.*; +import io.github.patternatlas.api.service.UserService; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; @@ -16,7 +17,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import com.fasterxml.jackson.databind.ObjectMapper; -import com.patternpedia.api.service.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/PatternLanguageGraphModel.java b/src/main/java/io/github/patternatlas/api/rest/model/PatternLanguageGraphModel.java index d278a76..5411a23 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/PatternLanguageGraphModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/PatternLanguageGraphModel.java @@ -5,6 +5,6 @@ @NoArgsConstructor @Data -public class GraphModel { +public class PatternLanguageGraphModel { private Object graph; } From 4c2bf082aa4803b6b1fd6412c6ec252559821e9c Mon Sep 17 00:00:00 2001 From: TYueksel <44586433+TYueksel@users.noreply.github.com> Date: Sat, 17 Jul 2021 19:32:25 +0200 Subject: [PATCH 18/68] Deleted duplicate import --- .../io/github/patternatlas/api/entities/user/UserEntity.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java index 2cb2eb9..ae27dac 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java @@ -26,8 +26,6 @@ import lombok.NoArgsConstructor; import lombok.ToString; -import org.hibernate.annotations.NaturalId; - @Entity @Data @NoArgsConstructor From 9e5bc3e676c323a07fde27b09ba58357782de362 Mon Sep 17 00:00:00 2001 From: TYueksel Date: Thu, 9 Sep 2021 16:40:57 +0200 Subject: [PATCH 19/68] Added rating att to match data model with db shema --- .../api/entities/candidate/Candidate.java | 4 ++++ .../entities/candidate/CandidateRating.java | 2 ++ .../candidate/comment/CandidateComment.java | 2 ++ .../api/entities/issue/Issue.java | 4 ++++ .../entities/issue/comment/IssueComment.java | 2 ++ .../rest/controller/CandidateController.java | 24 +++++++++---------- .../api/rest/controller/IssueController.java | 22 ++++++++--------- .../rest/model/candidate/CandidateModel.java | 1 + src/main/resources/application.properties | 2 +- 9 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java b/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java index 8bd0186..de43876 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java @@ -42,6 +42,8 @@ public class Candidate extends EntityWithURI { private String version = "0.1.0"; + private int rating; + @JsonIgnore @OneToMany(mappedBy = "candidate", cascade = CascadeType.ALL, orphanRemoval = true) private List authors = new ArrayList<>(); @@ -65,6 +67,7 @@ public Candidate (CandidateModelRequest candidateModelRequest) { this.setIconUrl(candidateModelRequest.getIconUrl()); this.setContent(candidateModelRequest.getContent()); this.setVersion(candidateModelRequest.getVersion()); + this.setRating(candidateModelRequest.getRating()); } public void updateCandidate(CandidateModelRequest candidateModelRequest) { @@ -74,6 +77,7 @@ public void updateCandidate(CandidateModelRequest candidateModelRequest) { this.setIconUrl(candidateModelRequest.getIconUrl()); this.setContent(candidateModelRequest.getContent()); this.setVersion(candidateModelRequest.getVersion()); + this.setRating(candidateModelRequest.getRating()); } public String toString() { diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java index 50b03ae..09199f3 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java @@ -34,6 +34,8 @@ public class CandidateRating { @EqualsAndHashCode.Include private UserEntity user; + private int rating; + private int readability; private int understandability; private int appropriateness; diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java index 2bd9bca..59aff9e 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java @@ -41,6 +41,8 @@ public class CandidateComment extends Comment implements Serializable { @OneToMany(mappedBy = "candidateComment", cascade = CascadeType.ALL, orphanRemoval = true) private Set userRating = new HashSet<>(); + private int rating = 0; + public CandidateComment(String text, Candidate candidate, UserEntity user) { super(text); this.candidate = candidate; diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java b/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java index c2d52b1..bd73e2c 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java @@ -24,6 +24,8 @@ public class Issue extends EntityWithURI { private String version = "0.1.0"; + private int rating; + @JsonIgnore @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true) private List authors = new ArrayList<>(); @@ -45,6 +47,7 @@ public Issue (IssueModelRequest issueModelRequest) { this.setName(issueModelRequest.getName()); this.setDescription(issueModelRequest.getDescription()); this.setVersion(issueModelRequest.getVersion()); + this.setRating(issueModelRequest.getRating()); } public void updateIssue(IssueModelRequest issueModelRequest) { @@ -52,6 +55,7 @@ public void updateIssue(IssueModelRequest issueModelRequest) { this.setName(issueModelRequest.getName()); this.setDescription(issueModelRequest.getDescription()); this.setVersion(issueModelRequest.getVersion()); + this.setRating(issueModelRequest.getRating()); } public String toString() { diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java index 64721a0..2f47075 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java @@ -37,6 +37,8 @@ public class IssueComment extends Comment implements Serializable { @OneToMany(mappedBy = "issueComment", cascade = CascadeType.ALL, orphanRemoval = true) private List userRating = new ArrayList<>(); + private int rating = 0; + public IssueComment(String text, Issue issue, UserEntity user) { super(text); this.issue = issue; diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java index 219cb03..e1aa3d5 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java @@ -87,7 +87,7 @@ ResponseEntity> getCandidateByUri(@PathVariable Stri @Operation(operationId = "createCandidate", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate") @PostMapping(value = "") @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newCandidate(@RequestBody CandidateModelRequest candidateModelRequest, @AuthenticationPrincipal Principal principal) { + ResponseEntity> newCandidate(@RequestBody CandidateModelRequest candidateModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createCandidate(candidateModelRequest, UUID.fromString(principal.getName()))))); } @@ -95,7 +95,7 @@ ResponseEntity> newCandidate(@RequestBody CandidateM @PostMapping(value = "/{candidateId}/comments") @PreAuthorize(value = Authority.COMMENT) @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createComment(candidateId, UUID.fromString(principal.getName()), commentModel)))); } @@ -103,7 +103,7 @@ ResponseEntity> newCandidateComment(@PathVariable UU @PostMapping(value = "/{candidateId}/evidences") @PreAuthorize(value = Authority.EVIDENCE) @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newIssueEvidence(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + ResponseEntity> newIssueEvidence(@PathVariable UUID candidateId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createEvidence(candidateId, UUID.fromString(principal.getName()), evidenceModel)))); } @@ -113,13 +113,13 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID @Operation(operationId = "updateCandidate", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate") @PutMapping(value = "/{candidateId}") @ResponseStatus(HttpStatus.ACCEPTED) - ResponseEntity> putCandidate(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody CandidateModelRequest candidateModelRequest) { + ResponseEntity> putCandidate(@PathVariable UUID candidateId, Principal principal, @RequestBody CandidateModelRequest candidateModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidate(candidateId, UUID.fromString(principal.getName()), candidateModelRequest)))); } @Operation(operationId = "updateCandidateRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate rating") @PutMapping(value = "/{candidateId}/ratings") - ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { + ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); } @@ -133,13 +133,13 @@ ResponseEntity> putCandidateAuthor(@PathVariable UUI @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}") @PreAuthorize(value = Authority.COMMENT) @ResponseStatus(HttpStatus.ACCEPTED) - ResponseEntity> putCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + ResponseEntity> putCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()), commentModel)))); } @Operation(operationId = "updateCandidateCommentRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment rating") @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}/ratings") - ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateCommentRating(candidateId, candidateCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -147,13 +147,13 @@ ResponseEntity> putCandidateCommentRating(@PathVaria @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") @PreAuthorize(value = Authority.EVIDENCE) @ResponseStatus(HttpStatus.ACCEPTED) - ResponseEntity> putIssueEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + ResponseEntity> putIssueEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); } @Operation(operationId = "updateCandidateEvidenceRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence rating") @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}/ratings") - ResponseEntity> putCandidateEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + ResponseEntity> putCandidateEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateEvidenceRating(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -163,7 +163,7 @@ ResponseEntity> putCandidateEvidenceRating(@PathVari @Operation(operationId = "deleteCandidateById", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate by id") @DeleteMapping(value = "/{candidateId}") @ResponseStatus(HttpStatus.OK) - ResponseEntity deleteCandidate(@PathVariable UUID candidateId, @AuthenticationPrincipal Principal principal) { + ResponseEntity deleteCandidate(@PathVariable UUID candidateId, Principal principal) { this.candidateService.deleteCandidate(candidateId, UUID.fromString(principal.getName())); return ResponseEntity.noContent().build(); } @@ -178,7 +178,7 @@ ResponseEntity> deleteCandidateAuthor(@PathVariable @DeleteMapping(value = "/{candidateId}/comments/{candidateCommentId}") @PreAuthorize(value = Authority.COMMENT) @ResponseStatus(HttpStatus.OK) - ResponseEntity> deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, @AuthenticationPrincipal Principal principal) { + ResponseEntity> deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()))))); } @@ -186,7 +186,7 @@ ResponseEntity> deleteComment(@PathVariable UUID can @DeleteMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") @PreAuthorize(value = Authority.EVIDENCE) @ResponseStatus(HttpStatus.OK) - ResponseEntity> deleteEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, @AuthenticationPrincipal Principal principal) { + ResponseEntity> deleteEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()))))); } } \ No newline at end of file diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index d71c5df..c7daa31 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -82,21 +82,21 @@ ResponseEntity> getIssueByUri(@PathVariable String issue @PostMapping(value = "") @PreAuthorize(value = "#oauth2.hasScope('write')") @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newIssue(@RequestBody IssueModelRequest issueModelRequest, @AuthenticationPrincipal Principal principal) { + ResponseEntity> newIssue(@RequestBody IssueModelRequest issueModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createIssue(issueModelRequest, UUID.fromString(principal.getName()))))); } @Operation(operationId = "createIssueComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue comment") @PostMapping(value = "/{issueId}/comments") @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newIssueComment(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + ResponseEntity> newIssueComment(@PathVariable UUID issueId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); } @Operation(operationId = "createIssueEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue evidence") @PostMapping(value = "/{issueId}/evidences") @ResponseStatus(HttpStatus.CREATED) - ResponseEntity> newIssueEvidence(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + ResponseEntity> newIssueEvidence(@PathVariable UUID issueId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createEvidence(issueId, UUID.fromString(principal.getName()), evidenceModel)))); } @@ -105,13 +105,13 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID issu */ @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue") @PutMapping(value = "/{issueId}") - ResponseEntity> putIssue(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody IssueModelRequest issueModelRequest) { + ResponseEntity> putIssue(@PathVariable UUID issueId, Principal principal, @RequestBody IssueModelRequest issueModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssue(issueId, UUID.fromString(principal.getName()), issueModelRequest)))); } @Operation(operationId = "updateIssueRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue ratings") @PutMapping(value = "/{issueId}/ratings") - ResponseEntity> putIssueRating(@PathVariable UUID issueId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + ResponseEntity> putIssueRating(@PathVariable UUID issueId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueRating(issueId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -123,25 +123,25 @@ ResponseEntity> putIssueAuthor(@PathVariable UUID issueI @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment") @PutMapping(value = "/{issueId}/comments/{issueCommentId}") - ResponseEntity> putIssueComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal, @RequestBody CommentModel commentModel) { + ResponseEntity> putIssueComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateComment(issueId, issueCommentId, UUID.fromString(principal.getName()), commentModel)))); } @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment rating") @PutMapping(value = "/{issueId}/comments/{issueCommentId}/ratings") - ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}") - ResponseEntity> putIssueEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody EvidenceModel evidenceModel) { + ResponseEntity> putIssueEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); } @Operation(operationId = "updateIssueEvidenceRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence rating") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}/ratings") - ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { + ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueEvidenceRating(issueId, issueEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -163,13 +163,13 @@ ResponseEntity> deleteIssueAuthor(@PathVariable UUID iss @Operation(operationId = "deleteIssueComment", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue comment") @DeleteMapping(value = "/{issueId}/comments/{issueCommentId}") - ResponseEntity> deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, @AuthenticationPrincipal Principal principal) { + ResponseEntity> deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName()))))); } @Operation(operationId = "deleteIssueEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue evidence") @DeleteMapping(value = "/{issueId}/evidences/{issueEvidenceId}") - ResponseEntity> deleteEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, @AuthenticationPrincipal Principal principal) { + ResponseEntity> deleteEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()))))); } } \ No newline at end of file diff --git a/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModel.java b/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModel.java index a27d1ff..c9637b9 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/candidate/CandidateModel.java @@ -30,6 +30,7 @@ public class CandidateModel { private String patternLanguageName; private Object content; private String version; + private int rating; // RESPONSE private double ratingReadability = 0; private double ratingUnderstandability = 0; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 129e911..1be40be 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,5 +1,5 @@ server.port=1977 -spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.url=jdbc:postgresql://localhost:5060/postgres spring.datasource.username=postgres spring.datasource.password=postgres spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect From 3752aa2a3e7e45e4a00844f57f7c8d3b884c3df3 Mon Sep 17 00:00:00 2001 From: TYueksel Date: Mon, 20 Sep 2021 18:18:08 +0200 Subject: [PATCH 20/68] change postgres role to patternatlas --- src/main/resources/application-docker.properties | 6 +++--- src/main/resources/application.properties | 6 +++--- src/main/resources/applicationYML.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/resources/application-docker.properties b/src/main/resources/application-docker.properties index 667ed35..9fb2721 100644 --- a/src/main/resources/application-docker.properties +++ b/src/main/resources/application-docker.properties @@ -1,7 +1,7 @@ server.port=1977 -spring.datasource.url=jdbc:postgresql://localhost:5432/postgres -spring.datasource.username=postgres -spring.datasource.password=postgres +spring.datasource.url=jdbc:postgresql://localhost:5060/patternatlas +spring.datasource.username=patternatlas +spring.datasource.password=patternatlas spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true spring.jpa.hibernate.ddl-auto=update diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1be40be..0a91769 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,7 +1,7 @@ server.port=1977 -spring.datasource.url=jdbc:postgresql://localhost:5060/postgres -spring.datasource.username=postgres -spring.datasource.password=postgres +spring.datasource.url=jdbc:postgresql://localhost:5060/patternatlas +spring.datasource.username=patternatlas +spring.datasource.password=patternatlas spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true spring.jpa.hibernate.ddl-auto=update diff --git a/src/main/resources/applicationYML.yml b/src/main/resources/applicationYML.yml index 6e715a7..dc4a697 100644 --- a/src/main/resources/applicationYML.yml +++ b/src/main/resources/applicationYML.yml @@ -3,9 +3,9 @@ server: spring: datasource: - url: jdbc:postgresql://localhost:5432/postgres - username: postgres - password: postgres + url: jdbc:postgresql://localhost:5060/patternatlas + username: patternatlas + password: patternatlas initialization-mode: always jpa: hibernate: From d388e9021900056507bc93ff5eda5bc08904c171 Mon Sep 17 00:00:00 2001 From: TYueksel Date: Tue, 19 Oct 2021 21:22:24 +0200 Subject: [PATCH 21/68] Added candidates to languages tab --- .../api/repositories/CandidateRepository.java | 6 ++++++ .../rest/controller/CandidateController.java | 18 +++++++++++++----- .../api/service/CandidateService.java | 2 ++ .../api/service/CandidateServiceImpl.java | 6 ++++++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/repositories/CandidateRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateRepository.java index 952800c..5c3f78a 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/CandidateRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateRepository.java @@ -2,8 +2,11 @@ import java.util.Optional; import java.util.UUID; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.data.rest.core.annotation.RepositoryRestResource; import io.github.patternatlas.api.entities.candidate.Candidate; @@ -14,4 +17,7 @@ public interface CandidateRepository extends JpaRepository { public Optional findByUri(String uri); public boolean existsByUri(String uri); public boolean existsByName(String name); + + @Query(value = "SELECT * FROM candidate c WHERE c.pattern_language_id = :languageId", nativeQuery = true) + public List findAllByLanguageId(@Param("languageId") UUID languageId); } diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java index e1aa3d5..a5209ba 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java @@ -57,14 +57,22 @@ public CandidateController( /** * GET Methods */ - @Operation(operationId = "getAllCandiates", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all candidates") + @Operation(operationId = "getAllCandidates", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all candidates") @GetMapping(value = "") - CollectionModel> all() { - - List> candidates = this.candidateService.getAllCandidates() + CollectionModel> all(@RequestParam(value = "lid", required = false) UUID languageId) { + + List> candidates; + if (languageId == null) { + candidates = this.candidateService.getAllCandidates() + .stream() + .map(candidate -> new EntityModel<>(new CandidateModel(candidate))) + .collect(Collectors.toList()); + } else { + candidates = this.candidateService.getAllCandidatesByLanguageId(languageId) .stream() .map(candidate -> new EntityModel<>(new CandidateModel(candidate))) .collect(Collectors.toList()); + } return new CollectionModel<>(candidates); } @@ -77,7 +85,7 @@ ResponseEntity> getCandidateById(@PathVariable UUID @Operation(operationId = "getCandidateByURI", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by URI") @GetMapping(value = "/?uri={candidateUri}") - ResponseEntity> getCandidateByUri(@PathVariable String candidateUri) { + ResponseEntity> getCandidateByUri(@RequestParam("uri") String candidateUri) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateByURI(candidateUri)))); } diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateService.java b/src/main/java/io/github/patternatlas/api/service/CandidateService.java index 218847d..eab59fa 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateService.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateService.java @@ -21,6 +21,8 @@ public interface CandidateService { List getAllCandidates(); + List getAllCandidatesByLanguageId(UUID languageId); + Candidate getCandidateById(UUID candidateId); Candidate getCandidateByURI(String uri); diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index b31e6a8..ebdb38c 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -129,6 +129,12 @@ public List getAllCandidates() { return this.candidateRepository.findAll(); } + @Override + @Transactional + public List getAllCandidatesByLanguageId(UUID languageId) { + return this.candidateRepository.findAllByLanguageId(languageId); + } + @Override @Transactional public Candidate getCandidateById(UUID candidateId) { From e648926aaf45daf3633aa228f26c7853d44e61ee Mon Sep 17 00:00:00 2001 From: TYueksel <44586433+TYueksel@users.noreply.github.com> Date: Sat, 30 Oct 2021 15:07:51 +0200 Subject: [PATCH 22/68] Fixed typo --- .../github/patternatlas/api/rest/model/shared/RatingType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java index 1e56281..c4ac5db 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/RatingType.java @@ -3,5 +3,5 @@ public enum RatingType { READABILITY, UNDERSTANDABILITY, - APPROPIATENESS; + APPROPRIATENESS; } From caf6c3439102c6c80b2153d71abedeacc358899b Mon Sep 17 00:00:00 2001 From: TYueksel <44586433+TYueksel@users.noreply.github.com> Date: Sat, 30 Oct 2021 15:14:55 +0200 Subject: [PATCH 23/68] Fixed typo --- .../github/patternatlas/api/service/CandidateServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index ebdb38c..d45d6a5 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -195,7 +195,7 @@ public Candidate updateCandidateRating(UUID candidateId, UUID userId, RatingMode } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.UNDERSTANDABILITY)) { candidateRating.setUnderstandability(ratingModelMultiRequest.getRating()); - } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.APPROPIATENESS)) { + } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.APPROPRIATENESS)) { candidateRating.setAppropriateness(ratingModelMultiRequest.getRating()); } else { @@ -405,4 +405,4 @@ private CandidateEvidence existsCandidateEvidence(UUID candidateId, UUID evidenc throw new EntityNotFoundException(String.format("Candidate comment with id %s does not belong to user with id %s", evidenceId, userId)); return candidateEvidence; } -} \ No newline at end of file +} From ab97109f98edbab6954d1db4de2e4a8884970ce6 Mon Sep 17 00:00:00 2001 From: TYueksel Date: Sat, 30 Oct 2021 15:25:56 +0200 Subject: [PATCH 24/68] Fixed typo --- .../java/io/github/patternatlas/api/config/Authority.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java index 6ba5017..d32d0a0 100644 --- a/src/main/java/io/github/patternatlas/api/config/Authority.java +++ b/src/main/java/io/github/patternatlas/api/config/Authority.java @@ -3,7 +3,7 @@ public interface Authority { /** ISSUE */ String ISSUE_READ = "hasAuthority('ISSUE_READ')"; - String ISSUE_CREATE = "hasAuthority(ISSUE_CREATE')"; + String ISSUE_CREATE = "hasAuthority('ISSUE_CREATE')"; String ISSUE_EDIT = "hasAuthority('ISSUE_EDIT')"; String ISSUE_DELETE = "hasAuthority('ISSUE_DELETE')"; String ISSUE_READ_ALL = "hasAuthority('ISSUE_READ_ALL')"; @@ -20,7 +20,7 @@ public interface Authority { String PATTERN_CANDIDATE_DELETE_ALL = "hasAuthority('PATTERN_CANDIDATE_DELETE_ALL')"; String PATTERN_CANDIDATE_TO_PATTERN = "hasAuthority('PATTERN_CANDIDATE_TO_PATTERN')"; /** Pattern */ - String APPROVED_PATTERN_READ = "hasAuthority(APPROVED_PATTERN_READ')"; + String APPROVED_PATTERN_READ = "hasAuthority('APPROVED_PATTERN_READ')"; String APPROVED_PATTERN_CREATE = "hasAuthority('APPROVED_PATTERN_CREATE')"; String APPROVED_PATTERN_EDIT = "hasAuthority('APPROVED_PATTERN_EDIT')"; String APPROVED_PATTERN_DELETE = "hasAuthority('APPROVED_PATTERN_DELETE')"; From df6c97addc98bfa7a1da427fdc34d11d85d4ee9a Mon Sep 17 00:00:00 2001 From: TYueksel Date: Sun, 20 Feb 2022 15:01:00 +0100 Subject: [PATCH 25/68] Resource privs for candidates & issues --- .../api/entities/shared/AuthorConstant.java | 2 +- .../api/entities/user/UserEntity.java | 22 +++++-- .../entities/user/role/PrivilegeConstant.java | 36 ++++++++-- .../api/entities/user/role/Role.java | 17 ++++- .../api/repositories/PrivilegeRepository.java | 12 +++- .../api/repositories/RoleRepository.java | 9 +++ .../api/rest/controller/AuthorController.java | 2 +- .../api/rest/model/user/UserModel.java | 4 +- .../api/service/CandidateServiceImpl.java | 66 +++++++++++++++++-- .../api/service/IssueServiceImpl.java | 45 +++++++++++-- .../api/service/PatternServiceImpl.java | 4 ++ .../api/service/PrivilegeService.java | 13 ++++ .../api/service/PrivilegeServiceImpl.java | 51 ++++++++++++++ .../patternatlas/api/service/RoleService.java | 16 +++++ .../api/service/RoleServiceImpl.java | 53 +++++++++++++++ .../patternatlas/api/service/UserService.java | 3 +- .../api/service/UserServiceImpl.java | 35 +++++++--- 17 files changed, 347 insertions(+), 43 deletions(-) create mode 100644 src/main/java/io/github/patternatlas/api/service/PrivilegeService.java create mode 100644 src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java create mode 100644 src/main/java/io/github/patternatlas/api/service/RoleService.java create mode 100644 src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java diff --git a/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java b/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java index 4d41a6e..683ab33 100644 --- a/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java @@ -3,5 +3,5 @@ public interface AuthorConstant { String OWNER = "OWNER"; String MAINTAINER = "MAINTAINER"; - String MEMBER = "MEMBER"; + String HELPER = "HELPER"; } diff --git a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java index ae27dac..72c9229 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java @@ -40,8 +40,13 @@ public class UserEntity implements Serializable{ @JsonIgnore @ToString.Exclude - @ManyToOne() - private Role role; + @ManyToMany() + /*@JoinTable( + name = "user_entity_roles", + joinColumns = { @JoinColumn(name = "users_id") }, + inverseJoinColumns = { @JoinColumn(name = "roles_id") } + )*/ + private Set roles; @NaturalId(mutable = true) @Column(nullable = false, unique = true) @@ -106,11 +111,11 @@ public UserEntity(UserModel userModel, String password) { this.password = password; } - public UserEntity(String name, String email, String password, Role role) { + public UserEntity(String name, String email, String password, Set roles) { this.name = name; this.email = email; this.password = password; - this.role = role; + this.roles = roles; } public void updateUserEntity(UserModel userModel) { @@ -137,4 +142,13 @@ public int hashCode() { public String toString() { return "User: " + this.name; } + + public void removeRole(String roleName) { + for (Role role : this.roles) { + if (role.getName().contains(roleName)) { + this.roles.remove(role); + return; + } + } + } } diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java index 65ed6ed..3253253 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java @@ -3,37 +3,59 @@ public class PrivilegeConstant { /** ISSUE */ public static final String ISSUE_READ = "ISSUE_READ"; - public static final String ISSUE_CREATE = "ISSUE_CREATE"; public static final String ISSUE_EDIT = "ISSUE_EDIT"; public static final String ISSUE_DELETE = "ISSUE_DELETE"; + public static final String ISSUE_COMMENT = "ISSUE_COMMENT"; + public static final String ISSUE_VOTE = "ISSUE_VOTE"; + public static final String ISSUE_EVIDENCE = "ISSUE_EVIDENCE"; + public static final String ISSUE_TO_PATTERN_CANDIDATE = "ISSUE_TO_PATTERN_CANDIDATE"; + public static final String ISSUE_CREATE = "ISSUE_CREATE"; public static final String ISSUE_READ_ALL = "ISSUE_READ_ALL"; public static final String ISSUE_EDIT_ALL = "ISSUE_EDIT_ALL"; public static final String ISSUE_DELETE_ALL = "ISSUE_DELETE_ALL"; - public static final String ISSUE_TO_PATTERN_CANDIDATE = "ISSUE_TO_PATTERN_CANDIDATE"; + public static final String ISSUE_COMMENT_ALL = "ISSUE_COMMENT_ALL"; + public static final String ISSUE_VOTE_ALL = "ISSUE_VOTE_ALL"; + public static final String ISSUE_EVIDENCE_ALL = "ISSUE_EVIDENCE_ALL"; + public static final String ISSUE_TO_PATTERN_CANDIDATE_ALL = "ISSUE_TO_PATTERN_CANDIDATE_ALL"; /** CANDIDATE */ public static final String PATTERN_CANDIDATE_READ = "PATTERN_CANDIDATE_READ"; - public static final String PATTERN_CANDIDATE_CREATE = "PATTERN_CANDIDATE_CREATE"; public static final String PATTERN_CANDIDATE_EDIT = "PATTERN_CANDIDATE_EDIT"; public static final String PATTERN_CANDIDATE_DELETE = "PATTERN_CANDIDATE_DELETE"; + public static final String PATTERN_CANDIDATE_COMMENT = "PATTERN_CANDIDATE_COMMENT"; + public static final String PATTERN_CANDIDATE_VOTE = "PATTERN_CANDIDATE_VOTE"; + public static final String PATTERN_CANDIDATE_EVIDENCE = "PATTERN_CANDIDATE_EVIDENCE"; + public static final String PATTERN_CANDIDATE_TO_PATTERN = "PATTERN_CANDIDATE_TO_PATTERN"; + public static final String PATTERN_CANDIDATE_CREATE = "PATTERN_CANDIDATE_CREATE"; public static final String PATTERN_CANDIDATE_READ_ALL = "PATTERN_CANDIDATE_READ_ALL"; public static final String PATTERN_CANDIDATE_EDIT_ALL = "PATTERN_CANDIDATE_EDIT_ALL"; public static final String PATTERN_CANDIDATE_DELETE_ALL = "PATTERN_CANDIDATE_DELETE_ALL"; - public static final String PATTERN_CANDIDATE_TO_PATTERN = "PATTERN_CANDIDATE_TO_PATTERN"; + public static final String PATTERN_CANDIDATE_COMMENT_ALL = "PATTERN_CANDIDATE_COMMENT_ALL"; + public static final String PATTERN_CANDIDATE_VOTE_ALL = "PATTERN_CANDIDATE_VOTE_ALL"; + public static final String PATTERN_CANDIDATE_EVIDENCE_ALL = "PATTERN_CANDIDATE_EVIDENCE_ALL"; + public static final String PATTERN_CANDIDATE_TO_PATTERN_ALL = "PATTERN_CANDIDATE_TO_PATTERN_ALL"; + /** Pattern Language */ + public static final String PATTERN_LANGUAGE_READ = "PATTERN_LANGUAGE_READ"; + public static final String PATTERN_LANGUAGE_EDIT = "PATTERN_LANGUAGE_EDIT"; + public static final String PATTERN_LANGUAGE_DELETE = "PATTERN_LANGUAGE_DELETE"; + public static final String PATTERN_LANGUAGE_CREATE = "PATTERN_LANGUAGE_CREATE"; + public static final String PATTERN_LANGUAGE_READ_ALL = "PATTERN_LANGUAGE_READ_ALL"; + public static final String PATTERN_LANGUAGE_EDIT_ALL = "PATTERN_LANGUAGE_EDIT_ALL"; + public static final String PATTERN_LANGUAGE_DELETE_ALL = "PATTERN_LANGUAGE_DELETE_ALL"; /** Pattern */ public static final String APPROVED_PATTERN_READ = "APPROVED_PATTERN_READ"; - public static final String APPROVED_PATTERN_CREATE = "APPROVED_PATTERN_CREATE"; public static final String APPROVED_PATTERN_EDIT = "APPROVED_PATTERN_EDIT"; public static final String APPROVED_PATTERN_DELETE = "APPROVED_PATTERN_DELETE"; + public static final String APPROVED_PATTERN_CREATE = "APPROVED_PATTERN_CREATE"; public static final String APPROVED_PATTERN_READ_ALL = "APPROVED_PATTERN_READ_ALL"; public static final String APPROVED_PATTERN_EDIT_ALL = "APPROVED_PATTERN_EDIT_ALL"; public static final String APPROVED_PATTERN_DELETE_ALL = "APPROVED_PATTERN_DELETE_ALL"; /** USER */ public static final String USER_READ = "USER_READ"; - public static final String USER_CREATE = "USER_CREATE"; public static final String USER_EDIT = "USER_EDIT"; public static final String USER_DELETE = "USER_DELETE"; + public static final String USER_CREATE = "USER_CREATE"; public static final String USER_READ_ALL = "USER_READ_ALL"; - public static final String USER_EDIT_ALL = "USER_EDIT_ALL"; + public static final String USER_EDIT_ALL = "USER_EDIT_ALL"; public static final String USER_DELETE_ALL = "USER_DELETE_ALL"; public static final String USER_ALL = "USER_ALL"; /** GENERAL */ diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java index a5739e7..5c886a4 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java @@ -6,8 +6,9 @@ import lombok.NoArgsConstructor; import javax.persistence.*; -import java.util.Collection; +import java.util.Set; import java.util.UUID; +import java.util.Collection; @Entity @Data @@ -21,10 +22,15 @@ public class Role { @Column(unique = true) private String name; - @OneToMany(mappedBy = "role", cascade = CascadeType.ALL, orphanRemoval = true) - private Collection users; + @ManyToMany(mappedBy = "roles") + private Set users; @ManyToMany(cascade = CascadeType.ALL) + /*@JoinTable( + name = "role_privileges", + joinColumns = { @JoinColumn(name = "roles_id") }, + inverseJoinColumns = { @JoinColumn(name = "privileges_id") } + )*/ private Collection privileges; public Role(String name) { @@ -40,4 +46,9 @@ public boolean checkPrivilege(String privilege) { return false; } + public void removePrivilege(Privilege privilege) { + this.privileges.remove(privilege); + privilege.getRoles().remove(this); + } + } diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java index 8f5ad9f..9ff2652 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java @@ -3,10 +3,20 @@ import io.github.patternatlas.api.entities.user.role.Privilege; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import java.util.Optional; import java.util.UUID; +import java.util.List; public interface PrivilegeRepository extends JpaRepository { - Privilege findByName(String name); + public Optional findByName(String name); + + @Modifying + @Query(value = "DELETE FROM privilege p WHERE p.name like %:resourceId", nativeQuery = true) + public void deleteAllByResourceId(@Param("resourceId") UUID resourceId); } diff --git a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java index b620f74..b25dd37 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java @@ -3,6 +3,10 @@ import io.github.patternatlas.api.entities.user.role.Role; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; import java.util.UUID; @@ -10,4 +14,9 @@ public interface RoleRepository extends JpaRepository { boolean existsByName(String name); Role findByName(String name); + + @Modifying + @Query(value = "DELETE FROM role r WHERE r.name like %:resourceId", nativeQuery = true) + public void deleteAllByResourceId(@Param("resourceId") UUID resourceId); + } diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java index 50a8098..349f537 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java @@ -48,6 +48,6 @@ CollectionModel> getAll() { @Operation(operationId = "getAllAuthorRoles", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all author roles") @GetMapping(value = "/roles") String[] getAllRoles() { - return new String[]{AuthorConstant.MEMBER, AuthorConstant.MAINTAINER, AuthorConstant.OWNER}; + return new String[]{AuthorConstant.HELPER, AuthorConstant.MAINTAINER, AuthorConstant.OWNER}; } } diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java index 78b8214..e2e0ac9 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java @@ -22,7 +22,7 @@ public class UserModel { private UUID id; - private String role; + private List roles; private String email; private String name; private List issues; @@ -40,7 +40,7 @@ public class UserModel { public UserModel(UserEntity user) { this.id = user.getId(); - this.role = user.getRole().getName(); + this.roles = user.getRoles().stream().map(role -> role.getName()).collect(Collectors.toList()); this.email = user.getEmail(); this.name = user.getName(); // ISSUE diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index d45d6a5..31ec5ab 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -12,7 +12,10 @@ import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence; import io.github.patternatlas.api.entities.shared.AuthorConstant; import io.github.patternatlas.api.entities.user.UserEntity; +import io.github.patternatlas.api.entities.user.role.Privilege; import io.github.patternatlas.api.entities.user.role.PrivilegeConstant; +import io.github.patternatlas.api.entities.user.role.Role; +import io.github.patternatlas.api.entities.user.role.RoleConstant; import io.github.patternatlas.api.repositories.*; import io.github.patternatlas.api.rest.model.candidate.CandidateModelRequest; import io.github.patternatlas.api.rest.model.shared.*; @@ -27,8 +30,7 @@ import javax.persistence.EntityExistsException; import javax.persistence.EntityNotFoundException; -import java.util.List; -import java.util.UUID; +import java.util.*; @Service @Transactional @@ -43,9 +45,11 @@ public class CandidateServiceImpl implements CandidateService { private CandidateEvidenceRatingRepository candidateEvidenceRatingRepository; private PatternLanguageService patternLanguageService; private UserService userService; + private RoleService roleService; + private PrivilegeService privilegeService; private IssueService issueService; - Logger logger = LoggerFactory.getLogger(IssueServiceImpl.class); + Logger logger = LoggerFactory.getLogger(CandidateServiceImpl.class); public CandidateServiceImpl( CandidateRepository candidateRepository, @@ -57,6 +61,8 @@ public CandidateServiceImpl( CandidateEvidenceRatingRepository candidateEvidenceRatingRepository, PatternLanguageService patternLanguageService, UserService userService, + RoleService roleService, + PrivilegeService privilegeService, IssueService issueService ) { this.candidateRepository = candidateRepository; @@ -68,6 +74,8 @@ public CandidateServiceImpl( this.candidateEvidenceRatingRepository = candidateEvidenceRatingRepository; this.patternLanguageService = patternLanguageService; this.userService = userService; + this.roleService = roleService; + this.privilegeService = privilegeService; this.issueService = issueService; } @@ -93,8 +101,27 @@ public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UU throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); // ISSUE TO PATTERN - if (user.getRole().checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_CREATE) || this.issueService.authorPermissions(candidateModelRequest.getIssueId(), userId)) { + if (user.getRoles().stream().anyMatch(role -> role.checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_CREATE)) || this.issueService.authorPermissions(candidateModelRequest.getIssueId(), userId)) { Candidate newCandidate = this.candidateRepository.save(candidate); + + Privilege readCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_READ + '_' + newCandidate.getId()); + Privilege updateCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EDIT + '_' + newCandidate.getId()); + Privilege deleteCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_DELETE + '_' + newCandidate.getId()); + Privilege commentCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_COMMENT + '_' + newCandidate.getId()); + Privilege voteCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_VOTE + '_' + newCandidate.getId()); + Privilege evidenceCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EVIDENCE + '_' + newCandidate.getId()); + Privilege toApprovedPattern = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_TO_PATTERN + '_' + newCandidate.getId()); + + Role helper = this.roleService.createRole(RoleConstant.HELPER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( + readCandidatePrivilege, updateCandidatePrivilege + )); + Role maintainer = this.roleService.createRole(RoleConstant.MAINTAINER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( + readCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege + )); + Role owner = this.roleService.createRole(RoleConstant.OWNER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( + readCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege + )); + if (candidateModelRequest.getIssueId() != null) { logger.info("Issue to Candidate request"); Issue issue = this.issueService.getIssueById(candidateModelRequest.getIssueId()); @@ -107,10 +134,32 @@ public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UU // ADD author if (candidateModelRequest.getAuthors() != null) { for (AuthorModel authorModel : candidateModelRequest.getAuthors()) { - newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(authorModel.getUserId()), authorModel.getAuthorRole())); + newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(authorModel.getUserId()), authorModel.getAuthorRole() + "_PATTERN_CANDIDATE_" + newCandidate.getId())); + UserEntity u = this.userService.getUserById(authorModel.getUserId()); + switch (authorModel.getAuthorRole()) { + case AuthorConstant.HELPER: + user.getRoles().add(helper); + this.userService.saveUser(u); + break; + case AuthorConstant.MAINTAINER: + user.getRoles().add(maintainer); + this.userService.saveUser(u); + break; + case AuthorConstant.OWNER: + if (null != u.getRoles()) { + u.getRoles().add(owner); + } else { + u.setRoles(new HashSet<>(Arrays.asList(owner))); + } + this.userService.saveUser(u); + break; + default: + throw new IllegalArgumentException("Invalid author role: " + authorModel.getAuthorRole()); + } } } else { newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(userId), AuthorConstant.OWNER)); + user.getRoles().add(owner); } // ADD pattern language @@ -158,7 +207,7 @@ public Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRe Candidate candidate = this.getCandidateById(candidateId); UserEntity user = this.userService.getUserById(userId); - if (user.getRole().checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EDIT_ALL) || this.authorPermissions(candidateModelRequest.getId(), userId)) { + if (user.getRoles().stream().anyMatch(role -> role.checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EDIT_ALL)) || this.authorPermissions(candidateModelRequest.getId(), userId)) { // UPDATE issue fields if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) { Candidate candidateByURI = this.getCandidateByURI(candidateModelRequest.getUri()); @@ -219,7 +268,10 @@ public Candidate updateCandidateRating(UUID candidateId, UUID userId, RatingMode public void deleteCandidate(UUID candidateId, UUID userId) { UserEntity user = this.userService.getUserById(userId); - if (user.getRole().checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_DELETE_ALL) || this.authorPermissions(candidateId, userId)) { + if (user.getRoles().stream().anyMatch(role -> role.checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_DELETE_ALL)) || this.authorPermissions(candidateId, userId)) { + this.roleService.deleteAllRolesByResourceId(candidateId); + this.privilegeService.deleteAllPrivilegesByResourceId(candidateId); + user.removeRole(candidateId.toString()); this.candidateRepository.deleteById(candidateId); } else { throw new RuntimeException("You don't have the permission"); diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index 7cb23c8..d61f45e 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -9,6 +9,10 @@ import io.github.patternatlas.api.entities.issue.evidence.IssueEvidenceRating; import io.github.patternatlas.api.entities.shared.AuthorConstant; import io.github.patternatlas.api.entities.user.UserEntity; +import io.github.patternatlas.api.entities.user.role.Privilege; +import io.github.patternatlas.api.entities.user.role.PrivilegeConstant; +import io.github.patternatlas.api.entities.user.role.Role; +import io.github.patternatlas.api.entities.user.role.RoleConstant; import io.github.patternatlas.api.repositories.*; import io.github.patternatlas.api.rest.model.issue.IssueModelRequest; import io.github.patternatlas.api.rest.model.shared.AuthorModelRequest; @@ -39,6 +43,8 @@ public class IssueServiceImpl implements IssueService { private IssueEvidenceRepository issueEvidenceRepository; private IssueEvidenceRatingRepository issueEvidenceRatingRepository; private UserService userService; + private RoleService roleService; + private PrivilegeService privilegeService; Logger logger = LoggerFactory.getLogger(IssueServiceImpl.class); @@ -50,7 +56,9 @@ public IssueServiceImpl( IssueCommentRatingRepository issueCommentRatingRepository, IssueEvidenceRepository issueEvidenceRepository, IssueEvidenceRatingRepository issueEvidenceRatingRepository, - UserService userService + UserService userService, + RoleService roleService, + PrivilegeService privilegeService ) { this.issueRepository = issueRepository; this.issueRatingRepository = issueRatingRepository; @@ -60,6 +68,8 @@ public IssueServiceImpl( this.issueEvidenceRepository = issueEvidenceRepository; this.issueEvidenceRatingRepository = issueEvidenceRatingRepository; this.userService = userService; + this.roleService = roleService; + this.privilegeService = privilegeService; } @Override @@ -83,7 +93,28 @@ public Issue createIssue(IssueModelRequest issueModelRequest, UUID userId) { throw new EntityExistsException(String.format("Issue uri %s already exist!", issueModelRequest.getUri())); Issue newIssue = this.issueRepository.save(issue); - newIssue.getAuthors().add(new IssueAuthor(newIssue, this.userService.getUserById(userId), AuthorConstant.OWNER)); + UserEntity user = this.userService.getUserById(userId); + + Privilege readIssuePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.ISSUE_READ + '_' + newIssue.getId()); + Privilege updateIssuePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.ISSUE_EDIT + '_' + newIssue.getId()); + Privilege deleteIssuePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.ISSUE_DELETE + '_' + newIssue.getId()); + Privilege commentIssuePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.ISSUE_COMMENT + '_' + newIssue.getId()); + Privilege voteIssuePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.ISSUE_VOTE + '_' + newIssue.getId()); + Privilege evidenceIssuePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.ISSUE_EVIDENCE + '_' + newIssue.getId()); + Privilege toPatternCandidate = this.privilegeService.createPrivilege(PrivilegeConstant.ISSUE_TO_PATTERN_CANDIDATE + '_' + newIssue.getId()); + + Role helper = this.roleService.createRole(RoleConstant.HELPER + "_ISSUE_" + newIssue.getId(), Arrays.asList( + readIssuePrivilege, updateIssuePrivilege + )); + Role maintainer = this.roleService.createRole(RoleConstant.MAINTAINER + "_ISSUE_" + newIssue.getId(), Arrays.asList( + readIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege + )); + Role owner = this.roleService.createRole(RoleConstant.OWNER + "_ISSUE_" + newIssue.getId(), Arrays.asList( + readIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege + )); + + newIssue.getAuthors().add(new IssueAuthor(newIssue, user, AuthorConstant.OWNER)); + user.getRoles().add(owner); return this.issueRepository.save(newIssue); } @@ -142,9 +173,11 @@ public Issue updateIssueRating(UUID issueId, UUID userId, RatingModelRequest rat @Override @Transactional - public void deleteIssue(UUID IssueId) { - this.getIssueById(IssueId); - this.issueRepository.deleteById(IssueId); + public void deleteIssue(UUID issueId) { + this.roleService.deleteAllRolesByResourceId(issueId); + this.privilegeService.deleteAllPrivilegesByResourceId(issueId); + //this.getIssueById(issueId); + this.issueRepository.deleteById(issueId); } public boolean authorPermissions(UUID issueId, UUID userId) { @@ -153,7 +186,7 @@ public boolean authorPermissions(UUID issueId, UUID userId) { Issue issue = this.getIssueById(issueId); for (IssueAuthor author : issue.getAuthors()) { if (author.getUser().getId() == userId) { - if (author.getRole().equals(AuthorConstant.OWNER) || author.getRole().equals(AuthorConstant.MAINTAINER) ) { + if (author.getRole().equals(AuthorConstant.OWNER) || author.getRole().equals(AuthorConstant.MAINTAINER) ) { return true; } } diff --git a/src/main/java/io/github/patternatlas/api/service/PatternServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternServiceImpl.java index ab051df..e440509 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternServiceImpl.java @@ -3,6 +3,8 @@ import java.util.UUID; import javax.validation.Valid; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -21,6 +23,8 @@ public class PatternServiceImpl implements PatternService { private final PatternRepository patternRepository; + Logger logger = LoggerFactory.getLogger(PatternServiceImpl.class); + public PatternServiceImpl(PatternRepository patternRepository) { this.patternRepository = patternRepository; } diff --git a/src/main/java/io/github/patternatlas/api/service/PrivilegeService.java b/src/main/java/io/github/patternatlas/api/service/PrivilegeService.java new file mode 100644 index 0000000..2c56b7d --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/service/PrivilegeService.java @@ -0,0 +1,13 @@ +package io.github.patternatlas.api.service; + +import io.github.patternatlas.api.entities.user.role.Privilege; + +import java.util.List; +import java.util.UUID; + +public interface PrivilegeService { + /** CRUD */ + Privilege createPrivilege(String name); + + void deleteAllPrivilegesByResourceId(UUID resourceId); +} diff --git a/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java new file mode 100644 index 0000000..c194ba7 --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java @@ -0,0 +1,51 @@ +package io.github.patternatlas.api.service; + +import io.github.patternatlas.api.entities.user.role.Privilege; +import io.github.patternatlas.api.repositories.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import io.github.patternatlas.api.service.PrivilegeService; + +import javax.persistence.EntityExistsException; +import javax.persistence.EntityNotFoundException; +import java.util.List; +import java.util.UUID; + +@Service +@Transactional +public class PrivilegeServiceImpl implements PrivilegeService { + + private PrivilegeRepository privilegeRepository; + + Logger logger = LoggerFactory.getLogger(PrivilegeServiceImpl.class); + + public PrivilegeServiceImpl( + PrivilegeRepository privilegeRepository + ) { + this.privilegeRepository = privilegeRepository; + } + + /** + * CRUD Privilege + */ + @Override + @Transactional + public Privilege createPrivilege(String name) { + Privilege privilege = new Privilege(name); + + return this.privilegeRepository.save(privilege); + } + + @Override + @Transactional + public void deleteAllPrivilegesByResourceId(UUID resourceId) { + this.privilegeRepository.deleteAllByResourceId(resourceId); + } + +} diff --git a/src/main/java/io/github/patternatlas/api/service/RoleService.java b/src/main/java/io/github/patternatlas/api/service/RoleService.java new file mode 100644 index 0000000..265a8bc --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/service/RoleService.java @@ -0,0 +1,16 @@ +package io.github.patternatlas.api.service; + +import io.github.patternatlas.api.entities.user.role.Role; +import io.github.patternatlas.api.entities.user.role.Privilege; + +import java.util.List; +import java.util.UUID; +import java.util.Collection; + +public interface RoleService { + /** CRUD */ + Role createRole(String name, Collection privileges); + + void deleteAllRolesByResourceId(UUID resourceId); + +} diff --git a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java new file mode 100644 index 0000000..4adca49 --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java @@ -0,0 +1,53 @@ +package io.github.patternatlas.api.service; + +import io.github.patternatlas.api.entities.user.role.Role; +import io.github.patternatlas.api.entities.user.role.Privilege; +import io.github.patternatlas.api.repositories.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import io.github.patternatlas.api.service.RoleService; + +import java.util.List; +import java.util.UUID; +import java.util.Collection; + +@Service +@Transactional +public class RoleServiceImpl implements RoleService { + + private RoleRepository roleRepository; + + Logger logger = LoggerFactory.getLogger(RoleServiceImpl.class); + + public RoleServiceImpl( + RoleRepository roleRepository + ) { + this.roleRepository = roleRepository; + } + + /** + * CRUD Role + */ + @Override + @Transactional + public Role createRole(String name, Collection privileges) { + Role role = roleRepository.findByName(name); + if (role == null) { + role = new Role(name); + role.setPrivileges(privileges); + roleRepository.save(role); + } + return role; + } + + @Override + @Transactional + public void deleteAllRolesByResourceId(UUID resourceId) { + this.roleRepository.deleteAllByResourceId(resourceId); + } + +} diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index 6a4abc8..6f65d9e 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -1,5 +1,6 @@ package io.github.patternatlas.api.service; +import io.github.patternatlas.api.entities.candidate.Candidate; import io.github.patternatlas.api.entities.user.role.Privilege; import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.entities.user.UserEntity; @@ -12,7 +13,7 @@ import java.util.UUID; public interface UserService { - + UserEntity saveUser(UserEntity user); UserEntity createUser(UserModelRequest userModelRequest); List getAllUsers(); UserEntity getUserById(UUID UserId); diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 7cbc93a..183ee02 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -1,5 +1,6 @@ package io.github.patternatlas.api.service; +import io.github.patternatlas.api.entities.candidate.Candidate; import io.github.patternatlas.api.entities.user.role.RoleConstant; import io.github.patternatlas.api.entities.user.role.Privilege; import io.github.patternatlas.api.entities.user.role.Role; @@ -18,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.stream.Collectors; @Service @Transactional @@ -41,6 +43,12 @@ public UserServiceImpl( this.passwordEncoder = passwordEncoder; } + @Override + @Transactional + public UserEntity saveUser(UserEntity user) { + return this.userRepository.save(user); + } + @Override @Transactional public UserEntity createUser(UserModelRequest userModelRequest) { @@ -51,11 +59,14 @@ public UserEntity createUser(UserModelRequest userModelRequest) { throw new RuntimeException("Password is null"); UserEntity user = new UserEntity(userModelRequest, passwordEncoder.encode(userModelRequest.getPassword())); - if (this.roleRepository.findByName(userModelRequest.getRole()) != null) { - user.setRole(this.roleRepository.findByName(userModelRequest.getRole())); - } else { - user.setRole(this.roleRepository.findByName(RoleConstant.MEMBER)); - } + userModelRequest.getRoles().stream().forEach(role -> { + if (this.roleRepository.findByName(role) != null) { + user.getRoles().add(this.roleRepository.findByName(role)); + } else { + user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); + } + }); + return this.userRepository.save(user); } @@ -77,14 +88,18 @@ public UserEntity getUserById(UUID userId) { public UserEntity updateUser(UUID userId, UserModelRequest userModelRequest) { if (userModelRequest == null) throw new RuntimeException("User to update is null!"); - if (!this.roleRepository.existsByName(userModelRequest.getRole())) - throw new ResourceNotFoundException(String.format("User Role %s not found!", userModelRequest.getRole())); + userModelRequest.getRoles().stream().forEach(role -> { + if (!this.roleRepository.existsByName(role)) + throw new ResourceNotFoundException(String.format("User Role %s not found!", role)); + }); UserEntity user = this.getUserById(userId); - if (!user.getRole().getName().equals(userModelRequest.getRole())) - user.setRole(this.roleRepository.findByName(userModelRequest.getRole())); + userModelRequest.getRoles().stream().forEach(role -> { + if (!user.getRoles().stream().map(r -> r.getName()).collect(Collectors.toList()).contains(role)) + user.getRoles().add(this.roleRepository.findByName(role)); + }); if (userModelRequest.getOldPassword() != null || userModelRequest.getPassword() != null) { - if (!passwordEncoder.matches(userModelRequest.getOldPassword(), user.getPassword()) && !user.getRole().getName().equals(RoleConstant.ADMIN)) + if (!passwordEncoder.matches(userModelRequest.getOldPassword(), user.getPassword()) && !user.getRoles().stream().map(role -> role.getName()).collect(Collectors.toList()).contains(RoleConstant.ADMIN)) throw new ResourceNotFoundException(String.format("Password ERROR")); user.setPassword(passwordEncoder.encode(userModelRequest.getPassword())); } From 8804b5e4b8ed86cecc8cdd28c0448f37c203446a Mon Sep 17 00:00:00 2001 From: TYueksel <44586433+TYueksel@users.noreply.github.com> Date: Sun, 20 Feb 2022 15:08:52 +0100 Subject: [PATCH 26/68] Updated DB port --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3b5bbf4..145af1e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ ENV JDBC_DATABASE_URL localhost ENV JDBC_DATABASE_USERNAME postgres ENV JDBC_DATABASE_PASSWORD postgres ENV JDBC_DATABASE_NAME postgres -ENV JDBC_DATABASE_PORT 5432 +ENV JDBC_DATABASE_PORT 5060 RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ From f44446da3f44c325bb05818656a6f66441d19dd7 Mon Sep 17 00:00:00 2001 From: TYueksel Date: Fri, 4 Mar 2022 16:29:26 +0100 Subject: [PATCH 27/68] Added Priv Management UI and Admin UI bug fix --- .../entities/user/role/PrivilegeConstant.java | 4 -- .../api/repositories/PrivilegeRepository.java | 10 ++++- .../api/repositories/RoleRepository.java | 11 ++++- .../api/rest/controller/UserController.java | 42 +++++++++++++++++-- .../api/service/CandidateServiceImpl.java | 9 ++-- .../api/service/IssueServiceImpl.java | 9 ++-- .../api/service/PrivilegeService.java | 2 +- .../api/service/PrivilegeServiceImpl.java | 4 +- .../patternatlas/api/service/RoleService.java | 2 +- .../api/service/RoleServiceImpl.java | 4 +- .../patternatlas/api/service/UserService.java | 6 ++- .../api/service/UserServiceImpl.java | 28 ++++++++++++- 12 files changed, 105 insertions(+), 26 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java index 3253253..1c011be 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java @@ -58,8 +58,4 @@ public class PrivilegeConstant { public static final String USER_EDIT_ALL = "USER_EDIT_ALL"; public static final String USER_DELETE_ALL = "USER_DELETE_ALL"; public static final String USER_ALL = "USER_ALL"; - /** GENERAL */ - public static final String COMMENT = "COMMENT"; - public static final String VOTE = "VOTE"; - public static final String EVIDENCE = "EVIDENCE"; } diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java index 9ff2652..bb93d95 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java @@ -16,7 +16,13 @@ public interface PrivilegeRepository extends JpaRepository { public Optional findByName(String name); + @Query(value = "SELECT * FROM privilege p WHERE p.name like '%ALL' OR p.name like '%CREATE'", nativeQuery = true) + public List findAllPlatformPrivileges(); + + @Query(value = "SELECT * FROM privilege p WHERE p.name like %:entityId", nativeQuery = true) + public List findAllFromEntity(@Param("entityId") UUID entityId); + @Modifying - @Query(value = "DELETE FROM privilege p WHERE p.name like %:resourceId", nativeQuery = true) - public void deleteAllByResourceId(@Param("resourceId") UUID resourceId); + @Query(value = "DELETE FROM privilege p WHERE p.name like %:entityId", nativeQuery = true) + public void deleteAllFromEntity(@Param("entityId") UUID entityId); } diff --git a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java index b25dd37..ced7250 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java @@ -9,14 +9,21 @@ import org.springframework.data.rest.core.annotation.RepositoryRestResource; import java.util.UUID; +import java.util.List; public interface RoleRepository extends JpaRepository { boolean existsByName(String name); Role findByName(String name); + @Query(value = "SELECT * FROM role r WHERE r.name IN (:names)", nativeQuery = true) + public List findAllRolesByNames(@Param("names") List names); + + @Query(value = "SELECT * FROM role r WHERE r.name like %:entityId", nativeQuery = true) + public List findAllFromEntity(@Param("entityId") UUID entityId); + @Modifying - @Query(value = "DELETE FROM role r WHERE r.name like %:resourceId", nativeQuery = true) - public void deleteAllByResourceId(@Param("resourceId") UUID resourceId); + @Query(value = "DELETE FROM role r WHERE r.name like %:entityId", nativeQuery = true) + public void deleteAllFromEntity(@Param("entityId") UUID entityId); } diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 052ae2c..e10074c 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -73,13 +73,49 @@ CollectionModel> getAllRoles() { return new CollectionModel<>(roles); } + @GetMapping(value = "/roles/platform") + CollectionModel> getAllPlatformRoles() { + List> roles = this.userService.getAllPlatformRoles() + .stream() + .map(role -> new EntityModel<>(new RoleModel(role))) + .collect(Collectors.toList()); + return new CollectionModel<>(roles); + } + + @GetMapping(value = "/roles/authors") + CollectionModel> getAllAuthorRoles() { + List> roles = this.userService.getAllAuthorRoles() + .stream() + .map(role -> new EntityModel<>(new RoleModel(role))) + .collect(Collectors.toList()); + return new CollectionModel<>(roles); + } + + @GetMapping(value = "/roles/{entityId}") + CollectionModel> getAllRolesFromEntity(@PathVariable UUID entityId) { + List> roles = this.userService.getAllRolesFromEntity(entityId) + .stream() + .map(role -> new EntityModel<>(new RoleModel(role))) + .collect(Collectors.toList()); + return new CollectionModel<>(roles); + } + @GetMapping(value = "/roles/privileges") - CollectionModel> getAllPrivileges() { - List> roles = this.userService.getAllPrivileges() + CollectionModel> getAllPlatformPrivileges() { + List> privileges = this.userService.getAllPlatformPrivileges() .stream() .map(privilege -> new EntityModel<>(new PrivilegeModel(privilege))) .collect(Collectors.toList()); - return new CollectionModel<>(roles); + return new CollectionModel<>(privileges); + } + + @GetMapping(value = "/roles/privileges/{entityId}") + CollectionModel> getAllPrivilegesFromEntity(@PathVariable UUID entityId) { + List> privileges = this.userService.getAllPrivilegesFromEntity(entityId) + .stream() + .map(privilege -> new EntityModel<>(new PrivilegeModel(privilege))) + .collect(Collectors.toList()); + return new CollectionModel<>(privileges); } /** diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index 31ec5ab..ac02cf7 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -113,13 +113,16 @@ public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UU Privilege toApprovedPattern = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_TO_PATTERN + '_' + newCandidate.getId()); Role helper = this.roleService.createRole(RoleConstant.HELPER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( - readCandidatePrivilege, updateCandidatePrivilege + readCandidatePrivilege, + commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege )); Role maintainer = this.roleService.createRole(RoleConstant.MAINTAINER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( - readCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege + readCandidatePrivilege, updateCandidatePrivilege, + commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege )); Role owner = this.roleService.createRole(RoleConstant.OWNER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( - readCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege + readCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege, toApprovedPattern, + commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege )); if (candidateModelRequest.getIssueId() != null) { diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index d61f45e..3606d9b 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -104,13 +104,16 @@ public Issue createIssue(IssueModelRequest issueModelRequest, UUID userId) { Privilege toPatternCandidate = this.privilegeService.createPrivilege(PrivilegeConstant.ISSUE_TO_PATTERN_CANDIDATE + '_' + newIssue.getId()); Role helper = this.roleService.createRole(RoleConstant.HELPER + "_ISSUE_" + newIssue.getId(), Arrays.asList( - readIssuePrivilege, updateIssuePrivilege + readIssuePrivilege, + commentIssuePrivilege, voteIssuePrivilege, evidenceIssuePrivilege )); Role maintainer = this.roleService.createRole(RoleConstant.MAINTAINER + "_ISSUE_" + newIssue.getId(), Arrays.asList( - readIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege + readIssuePrivilege, updateIssuePrivilege, + commentIssuePrivilege, voteIssuePrivilege, evidenceIssuePrivilege )); Role owner = this.roleService.createRole(RoleConstant.OWNER + "_ISSUE_" + newIssue.getId(), Arrays.asList( - readIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege + readIssuePrivilege, updateIssuePrivilege, deleteIssuePrivilege, toPatternCandidate, + commentIssuePrivilege, voteIssuePrivilege, evidenceIssuePrivilege )); newIssue.getAuthors().add(new IssueAuthor(newIssue, user, AuthorConstant.OWNER)); diff --git a/src/main/java/io/github/patternatlas/api/service/PrivilegeService.java b/src/main/java/io/github/patternatlas/api/service/PrivilegeService.java index 2c56b7d..a8bbbc6 100644 --- a/src/main/java/io/github/patternatlas/api/service/PrivilegeService.java +++ b/src/main/java/io/github/patternatlas/api/service/PrivilegeService.java @@ -9,5 +9,5 @@ public interface PrivilegeService { /** CRUD */ Privilege createPrivilege(String name); - void deleteAllPrivilegesByResourceId(UUID resourceId); + void deleteAllPrivilegesByResourceId(UUID entityId); } diff --git a/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java index c194ba7..0b42c2e 100644 --- a/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java @@ -44,8 +44,8 @@ public Privilege createPrivilege(String name) { @Override @Transactional - public void deleteAllPrivilegesByResourceId(UUID resourceId) { - this.privilegeRepository.deleteAllByResourceId(resourceId); + public void deleteAllPrivilegesByResourceId(UUID entityId) { + this.privilegeRepository.deleteAllFromEntity(entityId); } } diff --git a/src/main/java/io/github/patternatlas/api/service/RoleService.java b/src/main/java/io/github/patternatlas/api/service/RoleService.java index 265a8bc..dd87de7 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleService.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleService.java @@ -11,6 +11,6 @@ public interface RoleService { /** CRUD */ Role createRole(String name, Collection privileges); - void deleteAllRolesByResourceId(UUID resourceId); + void deleteAllRolesByResourceId(UUID entityId); } diff --git a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java index 4adca49..0919959 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java @@ -46,8 +46,8 @@ public Role createRole(String name, Collection privileges) { @Override @Transactional - public void deleteAllRolesByResourceId(UUID resourceId) { - this.roleRepository.deleteAllByResourceId(resourceId); + public void deleteAllRolesByResourceId(UUID entityId) { + this.roleRepository.deleteAllFromEntity(entityId); } } diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index 6f65d9e..66b43a3 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -22,6 +22,10 @@ public interface UserService { /** Role */ List getAllRoles(); - List getAllPrivileges(); + List getAllPlatformRoles(); + List getAllAuthorRoles(); + List getAllRolesFromEntity(UUID entityId); + List getAllPlatformPrivileges(); + List getAllPrivilegesFromEntity(UUID entityId); Role updateRole(UUID roleId, UUID privilegeId, RoleModelRequest roleModelRequest); } \ No newline at end of file diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 183ee02..179f293 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -126,8 +126,32 @@ public List getAllRoles() { @Override @Transactional(readOnly = true) - public List getAllPrivileges() { - return this.privilegeRepository.findAll(); + public List getAllPlatformRoles() { + return this.roleRepository.findAllRolesByNames(Arrays.asList("ADMIN", "MEMBER", "EXPERT", "LIBRARIAN")); + } + + @Override + @Transactional(readOnly = true) + public List getAllAuthorRoles() { + return this.roleRepository.findAllRolesByNames(Arrays.asList("HELPER", "MAINTAINER", "OWNER")); + } + + @Override + @Transactional(readOnly = true) + public List getAllRolesFromEntity(UUID entityId) { + return this.roleRepository.findAllFromEntity(entityId); + } + + @Override + @Transactional(readOnly = true) + public List getAllPlatformPrivileges() { + return this.privilegeRepository.findAllPlatformPrivileges(); + } + + @Override + @Transactional(readOnly = true) + public List getAllPrivilegesFromEntity(UUID entityId) { + return this.privilegeRepository.findAllFromEntity(entityId); } @Override From 51ba047caaf2ed23263fccafbbc2a83cbc08efdc Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 11 Mar 2022 10:35:56 +0100 Subject: [PATCH 28/68] changed spring-boot path --- src/main/resources/application.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 400ffe5..053127c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,5 +1,5 @@ server.port=1977 -spring.datasource.url=jdbc:postgresql://localhost:5060/patternatlas +spring.datasource.url=jdbc:postgresql://localhost:5432/patternatlas spring.datasource.username=patternatlas spring.datasource.password=patternatlas spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect @@ -24,4 +24,4 @@ io.github.patternatlas.api.latexrenderer.port=5030 # Embedded Tomcat server.servlet.contextPath=/patternatlas # liquibase file -spring.liquibase.change-log=file:patternatlas.xml +spring.liquibase.change-log=patternatlas.xml From e40393025266f5baa8e1edf6531b8da5710c344a Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 15 Mar 2022 10:37:46 +0100 Subject: [PATCH 29/68] fixed user creation from UI (added possibility for singular roles) --- .../api/entities/user/UserEntity.java | 8 ++++--- .../api/rest/model/user/UserModelRequest.java | 1 + .../api/service/UserServiceImpl.java | 21 +++++++++++++------ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java index 72c9229..8558c81 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java @@ -105,10 +105,8 @@ public class UserEntity implements Serializable{ // private List candidateComments = new ArrayList<>(); public UserEntity(UserModel userModel, String password) { + this(userModel.getName(), userModel.getEmail(), password, null); this.id = userModel.getId(); - this.name = userModel.getName(); - this.email = userModel.getEmail(); - this.password = password; } public UserEntity(String name, String email, String password, Set roles) { @@ -116,6 +114,10 @@ public UserEntity(String name, String email, String password, Set roles) { this.email = email; this.password = password; this.roles = roles; + + if(this.roles == null) { + this.roles = new HashSet<>(); + } } public void updateUserEntity(UserModel userModel) { diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java index 6b5a643..330e408 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java @@ -11,4 +11,5 @@ public class UserModelRequest extends UserModel { private String oldPassword; private String password; + private String role; } diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 179f293..5f234fd 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -58,14 +58,23 @@ public UserEntity createUser(UserModelRequest userModelRequest) { if (userModelRequest.getPassword() == null) throw new RuntimeException("Password is null"); + UserEntity user = new UserEntity(userModelRequest, passwordEncoder.encode(userModelRequest.getPassword())); - userModelRequest.getRoles().stream().forEach(role -> { - if (this.roleRepository.findByName(role) != null) { - user.getRoles().add(this.roleRepository.findByName(role)); - } else { - user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); + if(userModelRequest.getRoles() != null) { + userModelRequest.getRoles().stream().forEach(role -> { + if (this.roleRepository.findByName(role) != null) { + user.getRoles().add(this.roleRepository.findByName(role)); + } + }); + } else { + // It could be that the UI only sends one singular role (not a set): + if(userModelRequest.getRole() != null) { + user.getRoles().add(this.roleRepository.findByName(userModelRequest.getRole())); } - }); + } + + // Default: Add member role + user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); return this.userRepository.save(user); } From 4c12e74ae8c6daf39f17a14d9e8e9f75db53bd0c Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 15 Mar 2022 10:45:46 +0100 Subject: [PATCH 30/68] changed role handling to mimic old behavior with single roles --- .../patternatlas/api/service/UserServiceImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 5f234fd..b3bc423 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -64,17 +64,21 @@ public UserEntity createUser(UserModelRequest userModelRequest) { userModelRequest.getRoles().stream().forEach(role -> { if (this.roleRepository.findByName(role) != null) { user.getRoles().add(this.roleRepository.findByName(role)); + } else { + user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); } }); } else { // It could be that the UI only sends one singular role (not a set): if(userModelRequest.getRole() != null) { - user.getRoles().add(this.roleRepository.findByName(userModelRequest.getRole())); + if (this.roleRepository.findByName(userModelRequest.getRole()) != null) { + user.getRoles().add(this.roleRepository.findByName(userModelRequest.getRole())); + } else { + user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); + } } } - // Default: Add member role - user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); return this.userRepository.save(user); } From ba37f57a700b2f765e4aa55bbaac3fe149fe3fb4 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 28 Mar 2022 11:04:15 +0200 Subject: [PATCH 31/68] disabled swagger --- pom.xml | 4 ++-- src/main/resources/application-docker.properties | 8 ++++---- src/main/resources/application.properties | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 0c4906d..183efa2 100644 --- a/pom.xml +++ b/pom.xml @@ -137,7 +137,7 @@ - + diff --git a/src/main/resources/application-docker.properties b/src/main/resources/application-docker.properties index 9fb2721..ef71205 100644 --- a/src/main/resources/application-docker.properties +++ b/src/main/resources/application-docker.properties @@ -8,10 +8,10 @@ spring.jpa.hibernate.ddl-auto=update logging.level.io.github.patternatlas.api=debug spring.datasource.initialization-mode=always spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true -springdoc.swagger-ui.url=/patternpedia/v3/api-docs -springdoc.swagger-ui.path=/swagger-ui -springdoc.swagger-ui.config-url=/patternpedia/v3/api-docs/swagger-config -springdoc.swagger-ui.operationsSorter=alpha +#springdoc.swagger-ui.url=/patternpedia/v3/api-docs +#springdoc.swagger-ui.path=/swagger-ui +#springdoc.swagger-ui.config-url=/patternpedia/v3/api-docs/swagger-config +#springdoc.swagger-ui.operationsSorter=alpha springdoc.default-produces-media-type=application/hal+json security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json #okta.oauth2.issuer=https://dev-918271.okta.com/oauth2/default diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 053127c..8d52214 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -8,10 +8,10 @@ spring.jpa.hibernate.ddl-auto=update logging.level.io.github.patternatlas.api=debug spring.datasource.initialization-mode=always spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true -springdoc.swagger-ui.url=/patternatlas/v3/api-docs -springdoc.swagger-ui.path=/swagger-ui -springdoc.swagger-ui.config-url=/patternatlas/v3/api-docs/swagger-config -springdoc.swagger-ui.operationsSorter=alpha +#springdoc.swagger-ui.url=/patternatlas/v3/api-docs +#springdoc.swagger-ui.path=/swagger-ui +#springdoc.swagger-ui.config-url=/patternatlas/v3/api-docs/swagger-config +#springdoc.swagger-ui.operationsSorter=alpha springdoc.default-produces-media-type=application/hal+json security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json #okta.oauth2.issuer=https://dev-918271.okta.com/oauth2/default From 2c3d1b200921b68e9d34a03d96b238f17620e75b Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 28 Mar 2022 11:33:51 +0200 Subject: [PATCH 32/68] fixed serialisation error in exception handlers --- pom.xml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 183efa2..20d0393 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ 1.8 1.5.9 2.5.0 + 2.13.2 @@ -137,7 +138,7 @@ - + @@ -169,7 +170,17 @@ com.fasterxml.jackson.core jackson-databind - 2.10.0 + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} From fcc63b6a6f26c179be0a6c4a60e6bf124554e76c Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 29 Mar 2022 15:59:50 +0200 Subject: [PATCH 33/68] added preauthorize checks for issues --- .../patternatlas/api/config/Authority.java | 9 +++++++ .../api/config/ResourceServerConfig.java | 3 ++- .../api/rest/controller/IssueController.java | 25 ++++++++++++++++--- .../api/service/AuthorityService.java | 24 ++++++++++++++++++ 4 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/github/patternatlas/api/service/AuthorityService.java diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java index d32d0a0..c19659d 100644 --- a/src/main/java/io/github/patternatlas/api/config/Authority.java +++ b/src/main/java/io/github/patternatlas/api/config/Authority.java @@ -1,6 +1,7 @@ package io.github.patternatlas.api.config; public interface Authority { + /** ISSUE */ String ISSUE_READ = "hasAuthority('ISSUE_READ')"; String ISSUE_CREATE = "hasAuthority('ISSUE_CREATE')"; @@ -10,6 +11,14 @@ public interface Authority { String ISSUE_EDIT_ALL = "hasAuthority('ISSUE_EDIT_ALL')"; String ISSUE_DELETE_ALL = "hasAuthority('ISSUE_DELETE_ALL')"; String ISSUE_TO_PATTERN_CANDIDATE = "hasAuthority('ISSUE_TO_PATTERN_CANDIDATE')"; + String ISSUE_EDIT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_EDIT', #issueId))"; + String ISSUE_EVIDENCE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_EVIDENCE', #issueId))"; + String ISSUE_COMMENT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_COMMENT', #issueId))"; + String ISSUE_VOTE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_VOTE', #issueId))"; + String ISSUE_DELETE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_DELETE', #issueId))"; + String ISSUE_READ_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_READ', #issueId))"; + String ISSUE_READ_COMBINED_URI = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_READ', " + + "@issueService.getIssueByURI(#issueUri).id)"; /** CANDIDATE */ String PATTERN_CANDIDATE_READ = "hasAuthority('PATTERN_CANDIDATE_READ')"; String PATTERN_CANDIDATE_CREATE = "hasAuthority('PATTERN_CANDIDATE_CREATE')"; diff --git a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java index aabe5f7..28e96f3 100644 --- a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java +++ b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java @@ -4,6 +4,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -18,7 +19,7 @@ @Configuration @EnableResourceServer // START::Comment for local development without authorization -//@EnableGlobalMethodSecurity(prePostEnabled = true) +@EnableGlobalMethodSecurity(prePostEnabled = true) // END::Comment for local development without authorization class ResourceServerConfig extends ResourceServerConfigurerAdapter { diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index c7daa31..2589efe 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.patternatlas.api.config.Authority; import io.github.patternatlas.api.rest.model.issue.IssueModelRequest; import io.github.patternatlas.api.rest.model.shared.*; import io.github.patternatlas.api.rest.model.issue.IssueModel; @@ -10,6 +11,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; +import liquibase.pro.packaged.P; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,6 +19,8 @@ import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PostAuthorize; +import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @@ -52,6 +56,7 @@ public IssueController( */ @Operation(operationId = "getAllIssues", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all issues") @GetMapping(value = "") + // TODO: Filter for read permissions CollectionModel> getAll() { List> issues = this.issueService.getAllIssues() .stream() @@ -59,18 +64,19 @@ CollectionModel> getAll() { // .sorted(Comparator.comparingInt(i -> i.getContent().getRating())) .sorted((i1, i2) -> Integer.compare(i2.getContent().getRating(), i1.getContent().getRating())) .collect(Collectors.toList()); - return new CollectionModel<>(issues); + return CollectionModel.of(issues); } @Operation(operationId = "getIssueById", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by id") @GetMapping(value = "/{issueId}") - @PreAuthorize(value = "#oauth2.hasScope('read')") + @PreAuthorize(value = Authority.ISSUE_READ_COMBINED) ResponseEntity> getIssueById(@PathVariable UUID issueId) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueById(issueId)))); } @Operation(operationId = "getIssueByURI", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by URI") @GetMapping(value = "/?uri={issueUri}") + @PreAuthorize(value = Authority.ISSUE_READ_COMBINED_URI) ResponseEntity> getIssueByUri(@PathVariable String issueUri) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueByURI(issueUri)))); } @@ -80,7 +86,7 @@ ResponseEntity> getIssueByUri(@PathVariable String issue */ @Operation(operationId = "createIssue", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue") @PostMapping(value = "") - @PreAuthorize(value = "#oauth2.hasScope('write')") + @PreAuthorize(value = Authority.ISSUE_CREATE) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssue(@RequestBody IssueModelRequest issueModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createIssue(issueModelRequest, UUID.fromString(principal.getName()))))); @@ -88,6 +94,7 @@ ResponseEntity> newIssue(@RequestBody IssueModelRequest @Operation(operationId = "createIssueComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue comment") @PostMapping(value = "/{issueId}/comments") + @PreAuthorize(value = Authority.ISSUE_COMMENT_COMBINED) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueComment(@PathVariable UUID issueId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); @@ -95,6 +102,7 @@ ResponseEntity> newIssueComment(@PathVariable UUID issue @Operation(operationId = "createIssueEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue evidence") @PostMapping(value = "/{issueId}/evidences") + @PreAuthorize(value = Authority.ISSUE_EVIDENCE_COMBINED) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueEvidence(@PathVariable UUID issueId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createEvidence(issueId, UUID.fromString(principal.getName()), evidenceModel)))); @@ -104,6 +112,7 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID issu * UPDATE Methods */ @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue") + @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) @PutMapping(value = "/{issueId}") ResponseEntity> putIssue(@PathVariable UUID issueId, Principal principal, @RequestBody IssueModelRequest issueModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssue(issueId, UUID.fromString(principal.getName()), issueModelRequest)))); @@ -111,11 +120,13 @@ ResponseEntity> putIssue(@PathVariable UUID issueId, Pri @Operation(operationId = "updateIssueRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue ratings") @PutMapping(value = "/{issueId}/ratings") + @PreAuthorize(value = Authority.ISSUE_VOTE_COMBINED) ResponseEntity> putIssueRating(@PathVariable UUID issueId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueRating(issueId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateIssueAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue authors") + @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) @PutMapping(value = "{issueId}/authors") ResponseEntity> putIssueAuthor(@PathVariable UUID issueId, @RequestBody AuthorModelRequest authorModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.saveIssueAuthor(issueId, authorModelRequest)))); @@ -123,24 +134,28 @@ ResponseEntity> putIssueAuthor(@PathVariable UUID issueI @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment") @PutMapping(value = "/{issueId}/comments/{issueCommentId}") + @PreAuthorize(value = Authority.ISSUE_COMMENT_COMBINED) ResponseEntity> putIssueComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateComment(issueId, issueCommentId, UUID.fromString(principal.getName()), commentModel)))); } @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment rating") @PutMapping(value = "/{issueId}/comments/{issueCommentId}/ratings") + @PreAuthorize(value = Authority.ISSUE_VOTE_COMBINED) ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}") + @PreAuthorize(value = Authority.ISSUE_EVIDENCE_COMBINED) ResponseEntity> putIssueEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); } @Operation(operationId = "updateIssueEvidenceRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence rating") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}/ratings") + @PreAuthorize(value = Authority.ISSUE_VOTE_COMBINED) ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueEvidenceRating(issueId, issueEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -150,24 +165,28 @@ ResponseEntity> putIssueEvidenceRating(@PathVariable UUI */ @Operation(operationId = "deleteIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue") @DeleteMapping(value = "/{issueId}") + @PreAuthorize(value = Authority.ISSUE_DELETE_COMBINED) ResponseEntity deleteIssue(@PathVariable UUID issueId) { this.issueService.deleteIssue(issueId); return ResponseEntity.noContent().build(); } @Operation(operationId = "deleteIssueAuthor", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue") + @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) @DeleteMapping(value = "{issueId}/authors/{userId}") ResponseEntity> deleteIssueAuthor(@PathVariable UUID issueId, @PathVariable UUID userId) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteIssueAuthor(issueId, userId)))); } @Operation(operationId = "deleteIssueComment", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue comment") + @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) @DeleteMapping(value = "/{issueId}/comments/{issueCommentId}") ResponseEntity> deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName()))))); } @Operation(operationId = "deleteIssueEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue evidence") + @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) @DeleteMapping(value = "/{issueId}/evidences/{issueEvidenceId}") ResponseEntity> deleteEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()))))); diff --git a/src/main/java/io/github/patternatlas/api/service/AuthorityService.java b/src/main/java/io/github/patternatlas/api/service/AuthorityService.java new file mode 100644 index 0000000..3e10465 --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/service/AuthorityService.java @@ -0,0 +1,24 @@ +package io.github.patternatlas.api.service; + +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +@Service("authorityService") +public class AuthorityService { + + + + /** + * @param baseAuthority base authority e.g. ISSUE_EDIT + * @param resource Resource for creating resource specific authority + * @return List of authorities allowing to perform action on resource (e.g. ISSUE_EDIT_ALL, ISSUE_EDIT_[uuid]) + */ + public List formatResourceAuthorities(String baseAuthority, UUID resource){ + List authorities = Arrays.asList(baseAuthority + "_ALL", baseAuthority + "_" + resource.toString()); + System.out.println("Returning auth. list: " + authorities.toString()); + return authorities; + } +} From 8601aa4035021405790984acc34df53c94cf0ce1 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 29 Mar 2022 16:33:16 +0200 Subject: [PATCH 34/68] removed debug output --- .../io/github/patternatlas/api/service/AuthorityService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/io/github/patternatlas/api/service/AuthorityService.java b/src/main/java/io/github/patternatlas/api/service/AuthorityService.java index 3e10465..161a64e 100644 --- a/src/main/java/io/github/patternatlas/api/service/AuthorityService.java +++ b/src/main/java/io/github/patternatlas/api/service/AuthorityService.java @@ -18,7 +18,6 @@ public class AuthorityService { */ public List formatResourceAuthorities(String baseAuthority, UUID resource){ List authorities = Arrays.asList(baseAuthority + "_ALL", baseAuthority + "_" + resource.toString()); - System.out.println("Returning auth. list: " + authorities.toString()); return authorities; } } From aeb8e6064d751b63956190c4647e97cc1d04403e Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 29 Mar 2022 17:43:27 +0200 Subject: [PATCH 35/68] author roles are now updated when issue authors are changed --- .../java/io/github/patternatlas/api/config/Authority.java | 2 +- .../patternatlas/api/repositories/RoleRepository.java | 3 +++ .../github/patternatlas/api/service/IssueServiceImpl.java | 8 ++++++++ .../io/github/patternatlas/api/service/RoleService.java | 3 ++- .../github/patternatlas/api/service/RoleServiceImpl.java | 5 +++++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java index c19659d..b9ef603 100644 --- a/src/main/java/io/github/patternatlas/api/config/Authority.java +++ b/src/main/java/io/github/patternatlas/api/config/Authority.java @@ -18,7 +18,7 @@ public interface Authority { String ISSUE_DELETE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_DELETE', #issueId))"; String ISSUE_READ_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_READ', #issueId))"; String ISSUE_READ_COMBINED_URI = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_READ', " + - "@issueService.getIssueByURI(#issueUri).id)"; + "@issueService.getIssueByURI(#issueUri).id))"; /** CANDIDATE */ String PATTERN_CANDIDATE_READ = "hasAuthority('PATTERN_CANDIDATE_READ')"; String PATTERN_CANDIDATE_CREATE = "hasAuthority('PATTERN_CANDIDATE_CREATE')"; diff --git a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java index ced7250..11370fc 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java @@ -22,6 +22,9 @@ public interface RoleRepository extends JpaRepository { @Query(value = "SELECT * FROM role r WHERE r.name like %:entityId", nativeQuery = true) public List findAllFromEntity(@Param("entityId") UUID entityId); + @Query(value = "SELECT * from role r where r.name like %:entityId and r.name like :authorRole%", nativeQuery = true) + public List findAllFromEntityForAuthorType(@Param("entityId") UUID entityId, @Param("authorRole") String authorRole); + @Modifying @Query(value = "DELETE FROM role r WHERE r.name like %:entityId", nativeQuery = true) public void deleteAllFromEntity(@Param("entityId") UUID entityId); diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index 3606d9b..29522db 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -207,6 +207,14 @@ public Issue saveIssueAuthor(UUID issueId, AuthorModelRequest authorModelRequest UserEntity user = userService.getUserById(authorModelRequest.getUserId()); IssueAuthor issueAuthor = new IssueAuthor(issue, user, authorModelRequest.getAuthorRole()); issueAuthor = this.issueAuthorRepository.save(issueAuthor); + + // Save roles associated with the author + // Get requested role + List authorRoles = this.roleService.findAllFromEntityForAuthorType(issue.getId(), authorModelRequest.getAuthorRole()); + user.getRoles().addAll(authorRoles); + this.userService.saveUser(user); + + return issueAuthor.getIssue(); } diff --git a/src/main/java/io/github/patternatlas/api/service/RoleService.java b/src/main/java/io/github/patternatlas/api/service/RoleService.java index dd87de7..7fccc07 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleService.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleService.java @@ -12,5 +12,6 @@ public interface RoleService { Role createRole(String name, Collection privileges); void deleteAllRolesByResourceId(UUID entityId); - + + List findAllFromEntityForAuthorType(UUID entityId, String authorRole); } diff --git a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java index 0919959..c95aed1 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java @@ -6,6 +6,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -50,4 +51,8 @@ public void deleteAllRolesByResourceId(UUID entityId) { this.roleRepository.deleteAllFromEntity(entityId); } + @Override + public List findAllFromEntityForAuthorType(UUID entityId, String authorRole) { + return this.roleRepository.findAllFromEntityForAuthorType(entityId, authorRole); + } } From ee5ef1ac8cedee3fd2149614b0a9eb37afc6c36c Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 31 Mar 2022 10:39:12 +0200 Subject: [PATCH 36/68] added privilege checks for pattern candidate --- .../patternatlas/api/config/Authority.java | 13 +++++++---- .../rest/controller/CandidateController.java | 23 ++++++++++++++----- .../api/service/CandidateServiceImpl.java | 7 ++++++ .../api/service/IssueServiceImpl.java | 3 ++- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java index b9ef603..ab43cd3 100644 --- a/src/main/java/io/github/patternatlas/api/config/Authority.java +++ b/src/main/java/io/github/patternatlas/api/config/Authority.java @@ -5,11 +5,6 @@ public interface Authority { /** ISSUE */ String ISSUE_READ = "hasAuthority('ISSUE_READ')"; String ISSUE_CREATE = "hasAuthority('ISSUE_CREATE')"; - String ISSUE_EDIT = "hasAuthority('ISSUE_EDIT')"; - String ISSUE_DELETE = "hasAuthority('ISSUE_DELETE')"; - String ISSUE_READ_ALL = "hasAuthority('ISSUE_READ_ALL')"; - String ISSUE_EDIT_ALL = "hasAuthority('ISSUE_EDIT_ALL')"; - String ISSUE_DELETE_ALL = "hasAuthority('ISSUE_DELETE_ALL')"; String ISSUE_TO_PATTERN_CANDIDATE = "hasAuthority('ISSUE_TO_PATTERN_CANDIDATE')"; String ISSUE_EDIT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_EDIT', #issueId))"; String ISSUE_EVIDENCE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_EVIDENCE', #issueId))"; @@ -28,6 +23,14 @@ public interface Authority { String PATTERN_CANDIDATE_EDIT_ALL = "hasAuthority('PATTERN_CANDIDATE_EDIT_ALL')"; String PATTERN_CANDIDATE_DELETE_ALL = "hasAuthority('PATTERN_CANDIDATE_DELETE_ALL')"; String PATTERN_CANDIDATE_TO_PATTERN = "hasAuthority('PATTERN_CANDIDATE_TO_PATTERN')"; + String PATTERN_CANDIDATE_EDIT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_EDIT', #issueId))"; + String PATTERN_CANDIDATE_EDIT_DELETE = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_DELETE', #issueId))"; + String PATTERN_CANDIDATE_EVIDENCE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_EVIDENCE', #issueId))"; + String PATTERN_CANDIDATE_VOTE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_VOTE', #issueId))"; + String PATTERN_CANDIDATE_COMMENT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_COMMENT', #issueId))"; + String PATTERN_CANDIDATE_READ_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_READ', #issueId))"; + String PATTERN_CANDIDATE_READ_COMBINED_URI = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_READ', " + + "@issueService.getIssueByURI(#candidateUri).id))"; /** Pattern */ String APPROVED_PATTERN_READ = "hasAuthority('APPROVED_PATTERN_READ')"; String APPROVED_PATTERN_CREATE = "hasAuthority('APPROVED_PATTERN_CREATE')"; diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java index a5209ba..555f8b8 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java @@ -59,6 +59,7 @@ public CandidateController( */ @Operation(operationId = "getAllCandidates", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all candidates") @GetMapping(value = "") + // TODO: Filter for read permissions CollectionModel> all(@RequestParam(value = "lid", required = false) UUID languageId) { List> candidates; @@ -79,12 +80,14 @@ CollectionModel> all(@RequestParam(value = "lid", re @Operation(operationId = "getCandidateById", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by id") @GetMapping(value = "/{candidateId}") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_READ_COMBINED) ResponseEntity> getCandidateById(@PathVariable UUID candidateId) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateById(candidateId)))); } @Operation(operationId = "getCandidateByURI", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by URI") @GetMapping(value = "/?uri={candidateUri}") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_READ_COMBINED_URI) ResponseEntity> getCandidateByUri(@RequestParam("uri") String candidateUri) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateByURI(candidateUri)))); } @@ -94,6 +97,7 @@ ResponseEntity> getCandidateByUri(@RequestParam("uri */ @Operation(operationId = "createCandidate", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate") @PostMapping(value = "") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_CREATE) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newCandidate(@RequestBody CandidateModelRequest candidateModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createCandidate(candidateModelRequest, UUID.fromString(principal.getName()))))); @@ -101,7 +105,7 @@ ResponseEntity> newCandidate(@RequestBody CandidateM @Operation(operationId = "createCandidateComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate comment") @PostMapping(value = "/{candidateId}/comments") - @PreAuthorize(value = Authority.COMMENT) + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_COMMENT_COMBINED) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createComment(candidateId, UUID.fromString(principal.getName()), commentModel)))); @@ -109,7 +113,7 @@ ResponseEntity> newCandidateComment(@PathVariable UU @Operation(operationId = "createCandidateEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate evidence") @PostMapping(value = "/{candidateId}/evidences") - @PreAuthorize(value = Authority.EVIDENCE) + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EVIDENCE_COMBINED) @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueEvidence(@PathVariable UUID candidateId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createEvidence(candidateId, UUID.fromString(principal.getName()), evidenceModel)))); @@ -120,6 +124,7 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID */ @Operation(operationId = "updateCandidate", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate") @PutMapping(value = "/{candidateId}") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidate(@PathVariable UUID candidateId, Principal principal, @RequestBody CandidateModelRequest candidateModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidate(candidateId, UUID.fromString(principal.getName()), candidateModelRequest)))); @@ -127,19 +132,21 @@ ResponseEntity> putCandidate(@PathVariable UUID cand @Operation(operationId = "updateCandidateRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate rating") @PutMapping(value = "/{candidateId}/ratings") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_VOTE_COMBINED) ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); } @Operation(operationId = "updateCandidateAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate authors") @PutMapping(value = "{candidateId}/authors") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) ResponseEntity> putCandidateAuthor(@PathVariable UUID candidateId, @RequestBody AuthorModelRequest authorModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.saveCandidateAuthor(candidateId, authorModelRequest)))); } @Operation(operationId = "updateCandidateComment", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment") @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}") - @PreAuthorize(value = Authority.COMMENT) + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_COMMENT_COMBINED) @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()), commentModel)))); @@ -147,13 +154,14 @@ ResponseEntity> putCandidateComment(@PathVariable UU @Operation(operationId = "updateCandidateCommentRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment rating") @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}/ratings") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_VOTE_COMBINED) ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateCommentRating(candidateId, candidateCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateCandidateEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence") @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") - @PreAuthorize(value = Authority.EVIDENCE) + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_VOTE_COMBINED) @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putIssueEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); @@ -161,6 +169,7 @@ ResponseEntity> putIssueEvidenceRating(@PathVariable @Operation(operationId = "updateCandidateEvidenceRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence rating") @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}/ratings") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_VOTE_COMBINED) ResponseEntity> putCandidateEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateEvidenceRating(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -170,6 +179,7 @@ ResponseEntity> putCandidateEvidenceRating(@PathVari */ @Operation(operationId = "deleteCandidateById", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate by id") @DeleteMapping(value = "/{candidateId}") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_DELETE) @ResponseStatus(HttpStatus.OK) ResponseEntity deleteCandidate(@PathVariable UUID candidateId, Principal principal) { this.candidateService.deleteCandidate(candidateId, UUID.fromString(principal.getName())); @@ -178,13 +188,14 @@ ResponseEntity deleteCandidate(@PathVariable UUID candidateId, Principal prin @Operation(operationId = "deleteCandidateAuthor", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate author") @DeleteMapping(value = "{candidateId}/authors/{userId}") + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) ResponseEntity> deleteCandidateAuthor(@PathVariable UUID candidateId, @PathVariable UUID userId) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteCandidateAuthor(candidateId, userId)))); } @Operation(operationId = "deleteCandidateComment", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate comment") @DeleteMapping(value = "/{candidateId}/comments/{candidateCommentId}") - @PreAuthorize(value = Authority.COMMENT) + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) @ResponseStatus(HttpStatus.OK) ResponseEntity> deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()))))); @@ -192,7 +203,7 @@ ResponseEntity> deleteComment(@PathVariable UUID can @Operation(operationId = "deleteCandidateEvidence", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate evidence") @DeleteMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") - @PreAuthorize(value = Authority.EVIDENCE) + @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) @ResponseStatus(HttpStatus.OK) ResponseEntity> deleteEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()))))); diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index ac02cf7..dc04244 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -306,6 +306,13 @@ public Candidate saveCandidateAuthor(UUID candidateId, AuthorModelRequest author UserEntity user = this.userService.getUserById(authorModelRequest.getUserId()); CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user, authorModelRequest.getAuthorRole()); candidateAuthor = this.candidateAuthorRepository.save(candidateAuthor); + + // Save roles associated with author + List authorRoles = this.roleService.findAllFromEntityForAuthorType(candidate.getId(), + authorModelRequest.getAuthorRole()); + user.getRoles().addAll(authorRoles); + this.userService.saveUser(user); + return candidateAuthor.getCandidate(); } diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index 29522db..ee3b909 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -210,7 +210,8 @@ public Issue saveIssueAuthor(UUID issueId, AuthorModelRequest authorModelRequest // Save roles associated with the author // Get requested role - List authorRoles = this.roleService.findAllFromEntityForAuthorType(issue.getId(), authorModelRequest.getAuthorRole()); + List authorRoles = this.roleService.findAllFromEntityForAuthorType(issue.getId(), + authorModelRequest.getAuthorRole()); user.getRoles().addAll(authorRoles); this.userService.saveUser(user); From a2143ef504e10487da7b7f0a802f577cc9062d20 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Apr 2022 14:24:19 +0200 Subject: [PATCH 37/68] added framework for privilege checks without JWT supplied authorities --- .../patternatlas/api/config/Authority.java | 3 + .../api/config/ResourceSecurityConfig.java | 24 +++++ .../api/config/ResourceServerConfig.java | 3 - .../entities/user/role/PrivilegeConstant.java | 3 + .../api/repositories/PrivilegeRepository.java | 7 ++ .../api/rest/controller/IssueController.java | 2 +- .../api/rest/controller/UserController.java | 7 ++ ...sourceMethodSecurityExpressionHandler.java | 34 +++++++ .../ResourceSecurityExpressionRoot.java | 93 +++++++++++++++++++ .../patternatlas/api/service/UserService.java | 9 ++ .../api/service/UserServiceImpl.java | 10 ++ 11 files changed, 191 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/github/patternatlas/api/config/ResourceSecurityConfig.java create mode 100644 src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java create mode 100644 src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java index ab43cd3..f93a5e9 100644 --- a/src/main/java/io/github/patternatlas/api/config/Authority.java +++ b/src/main/java/io/github/patternatlas/api/config/Authority.java @@ -2,6 +2,9 @@ public interface Authority { + // TODO will be phased out - after all authority checks are changed to hasResourcePermission, this file should not be + // needed anymore + /** ISSUE */ String ISSUE_READ = "hasAuthority('ISSUE_READ')"; String ISSUE_CREATE = "hasAuthority('ISSUE_CREATE')"; diff --git a/src/main/java/io/github/patternatlas/api/config/ResourceSecurityConfig.java b/src/main/java/io/github/patternatlas/api/config/ResourceSecurityConfig.java new file mode 100644 index 0000000..6eaf368 --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/config/ResourceSecurityConfig.java @@ -0,0 +1,24 @@ +package io.github.patternatlas.api.config; + +import io.github.patternatlas.api.security.ResourceMethodSecurityExpressionHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; + +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class ResourceSecurityConfig extends GlobalMethodSecurityConfiguration { + + @Autowired + private ApplicationContext applicationContext; + + @Override + protected MethodSecurityExpressionHandler createExpressionHandler() { + ResourceMethodSecurityExpressionHandler handler = new ResourceMethodSecurityExpressionHandler(); + handler.setApplicationContext(applicationContext); + return handler; + } +} diff --git a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java index 28e96f3..de3ea1f 100644 --- a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java +++ b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java @@ -18,9 +18,6 @@ @Configuration @EnableResourceServer -// START::Comment for local development without authorization -@EnableGlobalMethodSecurity(prePostEnabled = true) -// END::Comment for local development without authorization class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java index 1c011be..09946ce 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java @@ -1,5 +1,8 @@ package io.github.patternatlas.api.entities.user.role; +import org.springframework.stereotype.Component; + +@Component("PC") public class PrivilegeConstant { /** ISSUE */ public static final String ISSUE_READ = "ISSUE_READ"; diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java index bb93d95..2a6b3ac 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java @@ -25,4 +25,11 @@ public interface PrivilegeRepository extends JpaRepository { @Modifying @Query(value = "DELETE FROM privilege p WHERE p.name like %:entityId", nativeQuery = true) public void deleteAllFromEntity(@Param("entityId") UUID entityId); + + @Query(value = "SELECT case when (count(priv) > 0) then true else false end from Privilege priv " + + "LEFT JOIN priv.roles r " + + "LEFT JOIN r.users u " + + "WHERE u.id = :userId " + + "AND priv.name = :privilegeName") + boolean existsPrivilegeForUser(@Param("privilegeName") String privilegeName, @Param("userId") UUID userId); } diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index 2589efe..d73e8d7 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -94,7 +94,7 @@ ResponseEntity> newIssue(@RequestBody IssueModelRequest @Operation(operationId = "createIssueComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue comment") @PostMapping(value = "/{issueId}/comments") - @PreAuthorize(value = Authority.ISSUE_COMMENT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_COMMENT)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueComment(@PathVariable UUID issueId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index e10074c..ee53cf5 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -21,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.security.Principal; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -45,6 +46,12 @@ public UserController( this.objectMapper = objectMapper; } + // TODO ENTFERNEN + @GetMapping(value="/echo") + String echo(Principal user) { + return user.toString(); + } + /** * GET Methods */ diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java new file mode 100644 index 0000000..f04ac83 --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java @@ -0,0 +1,34 @@ +package io.github.patternatlas.api.security; + +import io.github.patternatlas.api.service.UserService; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.context.ApplicationContext; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; +import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; +import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.authentication.AuthenticationTrustResolverImpl; +import org.springframework.security.core.Authentication; + +public class ResourceMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { + private ApplicationContext applicationContext; + private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); + + @Override + protected MethodSecurityExpressionOperations createSecurityExpressionRoot( + Authentication authentication, MethodInvocation invocation) { + ResourceSecurityExpressionRoot root = new ResourceSecurityExpressionRoot( + authentication, + this.applicationContext.getBean(UserService.class)); + + root.setPermissionEvaluator(getPermissionEvaluator()); + root.setTrustResolver(this.trustResolver); + root.setRoleHierarchy(getRoleHierarchy()); + return root; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + super.setApplicationContext(applicationContext); + this.applicationContext = applicationContext; + } +} diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java new file mode 100644 index 0000000..6eb804e --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java @@ -0,0 +1,93 @@ +package io.github.patternatlas.api.security; + + +import io.github.patternatlas.api.entities.user.UserEntity; +import io.github.patternatlas.api.entities.user.role.Privilege; +import io.github.patternatlas.api.entities.user.role.Role; +import io.github.patternatlas.api.service.UserService; +import org.apache.catalina.User; +import org.springframework.security.access.expression.SecurityExpressionRoot; +import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +public class ResourceSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations { + + private Object filterObject; + private Object returnObject; + private UserService userService; + + public ResourceSecurityExpressionRoot(Authentication authentication, + UserService userService) { + super(authentication); + this.userService = userService; + } + + + private boolean checkAuthority(Collection userRoles, String authority) { + for(Role role : userRoles) { + for(Privilege privilege : role.getPrivileges()) { + if(privilege.getName().equals(authority)) { + return true; + } + } + } + return false; + } + + /** + * Checks permission given the objects UUID. + * Will check for general version of the permission (e.g. ISSUE_READ_ALL) + * and for resource specific version (e.g. ISSUE_READ_[uuid]) + * @param resource resource uuid + * @param permissionType type of the permission (ISSUE_READ) + * @return true if user has permission + */ + public boolean hasResourcePermission(UUID resource, String permissionType) { + UUID userId = UUID.fromString(this.getAuthentication().getName()); // Supplied through JWT id field + + System.out.println("Checking: " + permissionType); + System.out.println("for: " + resource); + System.out.println("given user: " + this.getAuthentication()); + + return this.userService.hasAnyPrivilege( + userId, + permissionType + "_ALL", + permissionType + "_" + resource.toString()); + } + + public void setUserService(UserService userService) { + this.userService = userService; + } + + @Override + public void setFilterObject(Object o) { + this.filterObject = o; + } + + @Override + public Object getFilterObject() { + return this.filterObject; + } + + @Override + public void setReturnObject(Object o) { + this.returnObject = o; + } + + @Override + public Object getReturnObject() { + return this.returnObject; + } + + @Override + public Object getThis() { + return this; + } +} diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index 66b43a3..3be35ad 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -20,6 +20,15 @@ public interface UserService { UserEntity updateUser(UUID userId, UserModelRequest userModelRequest); void deleteUser(UUID UserId); + /** + * Checks if a user has one of the supplied privileges, without querying all + * available roles and privileges + * @param userId + * @param privileges + * @return true if one of the privileges is present for the user + */ + boolean hasAnyPrivilege(UUID userId, String ... privileges); + /** Role */ List getAllRoles(); List getAllPlatformRoles(); diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index b3bc423..3450ad0 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -128,6 +128,16 @@ public void deleteUser(UUID userId) { this.userRepository.deleteById(userId); } + @Override + public boolean hasAnyPrivilege(UUID userId, String... permissions) { + for(String permission : permissions) { + if(this.privilegeRepository.existsPrivilegeForUser(permission, userId)) { + return true; + } + } + return false; + } + /** * Role && Permission */ From 29b8a6fafe5bf88c6a9a3ab57e06ab5f33ef3ad3 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Apr 2022 14:29:58 +0200 Subject: [PATCH 38/68] changed access control handling for issue --- .../patternatlas/api/config/Authority.java | 12 -------- .../api/rest/controller/IssueController.java | 30 +++++++++---------- .../ResourceSecurityExpressionRoot.java | 4 --- 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java index f93a5e9..9e48990 100644 --- a/src/main/java/io/github/patternatlas/api/config/Authority.java +++ b/src/main/java/io/github/patternatlas/api/config/Authority.java @@ -5,18 +5,6 @@ public interface Authority { // TODO will be phased out - after all authority checks are changed to hasResourcePermission, this file should not be // needed anymore - /** ISSUE */ - String ISSUE_READ = "hasAuthority('ISSUE_READ')"; - String ISSUE_CREATE = "hasAuthority('ISSUE_CREATE')"; - String ISSUE_TO_PATTERN_CANDIDATE = "hasAuthority('ISSUE_TO_PATTERN_CANDIDATE')"; - String ISSUE_EDIT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_EDIT', #issueId))"; - String ISSUE_EVIDENCE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_EVIDENCE', #issueId))"; - String ISSUE_COMMENT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_COMMENT', #issueId))"; - String ISSUE_VOTE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_VOTE', #issueId))"; - String ISSUE_DELETE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_DELETE', #issueId))"; - String ISSUE_READ_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_READ', #issueId))"; - String ISSUE_READ_COMBINED_URI = "hasAnyAuthority(@authorityService.formatResourceAuthorities('ISSUE_READ', " + - "@issueService.getIssueByURI(#issueUri).id))"; /** CANDIDATE */ String PATTERN_CANDIDATE_READ = "hasAuthority('PATTERN_CANDIDATE_READ')"; String PATTERN_CANDIDATE_CREATE = "hasAuthority('PATTERN_CANDIDATE_CREATE')"; diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index d73e8d7..af50577 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -69,14 +69,14 @@ CollectionModel> getAll() { @Operation(operationId = "getIssueById", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by id") @GetMapping(value = "/{issueId}") - @PreAuthorize(value = Authority.ISSUE_READ_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_READ)") ResponseEntity> getIssueById(@PathVariable UUID issueId) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueById(issueId)))); } @Operation(operationId = "getIssueByURI", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by URI") @GetMapping(value = "/?uri={issueUri}") - @PreAuthorize(value = Authority.ISSUE_READ_COMBINED_URI) + @PreAuthorize(value = "hasResourcePermission(@issueService.getIssueByURI(#issueUri).id, @PC.ISSUE_READ)") ResponseEntity> getIssueByUri(@PathVariable String issueUri) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueByURI(issueUri)))); } @@ -86,7 +86,7 @@ ResponseEntity> getIssueByUri(@PathVariable String issue */ @Operation(operationId = "createIssue", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue") @PostMapping(value = "") - @PreAuthorize(value = Authority.ISSUE_CREATE) + @PreAuthorize(value = "hasAuthority(@PC.ISSUE_CREATE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssue(@RequestBody IssueModelRequest issueModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createIssue(issueModelRequest, UUID.fromString(principal.getName()))))); @@ -102,7 +102,7 @@ ResponseEntity> newIssueComment(@PathVariable UUID issue @Operation(operationId = "createIssueEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue evidence") @PostMapping(value = "/{issueId}/evidences") - @PreAuthorize(value = Authority.ISSUE_EVIDENCE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EVIDENCE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueEvidence(@PathVariable UUID issueId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createEvidence(issueId, UUID.fromString(principal.getName()), evidenceModel)))); @@ -112,7 +112,7 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID issu * UPDATE Methods */ @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue") - @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @PutMapping(value = "/{issueId}") ResponseEntity> putIssue(@PathVariable UUID issueId, Principal principal, @RequestBody IssueModelRequest issueModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssue(issueId, UUID.fromString(principal.getName()), issueModelRequest)))); @@ -120,13 +120,13 @@ ResponseEntity> putIssue(@PathVariable UUID issueId, Pri @Operation(operationId = "updateIssueRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue ratings") @PutMapping(value = "/{issueId}/ratings") - @PreAuthorize(value = Authority.ISSUE_VOTE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") ResponseEntity> putIssueRating(@PathVariable UUID issueId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueRating(issueId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateIssueAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue authors") - @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @PutMapping(value = "{issueId}/authors") ResponseEntity> putIssueAuthor(@PathVariable UUID issueId, @RequestBody AuthorModelRequest authorModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.saveIssueAuthor(issueId, authorModelRequest)))); @@ -134,28 +134,28 @@ ResponseEntity> putIssueAuthor(@PathVariable UUID issueI @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment") @PutMapping(value = "/{issueId}/comments/{issueCommentId}") - @PreAuthorize(value = Authority.ISSUE_COMMENT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_COMMENT)") ResponseEntity> putIssueComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateComment(issueId, issueCommentId, UUID.fromString(principal.getName()), commentModel)))); } @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment rating") @PutMapping(value = "/{issueId}/comments/{issueCommentId}/ratings") - @PreAuthorize(value = Authority.ISSUE_VOTE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}") - @PreAuthorize(value = Authority.ISSUE_EVIDENCE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EVIDENCE)") ResponseEntity> putIssueEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); } @Operation(operationId = "updateIssueEvidenceRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence rating") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}/ratings") - @PreAuthorize(value = Authority.ISSUE_VOTE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueEvidenceRating(issueId, issueEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -165,28 +165,28 @@ ResponseEntity> putIssueEvidenceRating(@PathVariable UUI */ @Operation(operationId = "deleteIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue") @DeleteMapping(value = "/{issueId}") - @PreAuthorize(value = Authority.ISSUE_DELETE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_DELETE)") ResponseEntity deleteIssue(@PathVariable UUID issueId) { this.issueService.deleteIssue(issueId); return ResponseEntity.noContent().build(); } @Operation(operationId = "deleteIssueAuthor", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue") - @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @DeleteMapping(value = "{issueId}/authors/{userId}") ResponseEntity> deleteIssueAuthor(@PathVariable UUID issueId, @PathVariable UUID userId) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteIssueAuthor(issueId, userId)))); } @Operation(operationId = "deleteIssueComment", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue comment") - @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @DeleteMapping(value = "/{issueId}/comments/{issueCommentId}") ResponseEntity> deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName()))))); } @Operation(operationId = "deleteIssueEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue evidence") - @PreAuthorize(value = Authority.ISSUE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @DeleteMapping(value = "/{issueId}/evidences/{issueEvidenceId}") ResponseEntity> deleteEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()))))); diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java index 6eb804e..e00ca46 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java @@ -52,10 +52,6 @@ private boolean checkAuthority(Collection userRoles, String authority) { public boolean hasResourcePermission(UUID resource, String permissionType) { UUID userId = UUID.fromString(this.getAuthentication().getName()); // Supplied through JWT id field - System.out.println("Checking: " + permissionType); - System.out.println("for: " + resource); - System.out.println("given user: " + this.getAuthentication()); - return this.userService.hasAnyPrivilege( userId, permissionType + "_ALL", From 2271b558cbdbe692b2e185fffe99b62d50e7db5d Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Apr 2022 14:40:36 +0200 Subject: [PATCH 39/68] updated permission checks for candidate --- .../patternatlas/api/config/Authority.java | 17 ---------- .../rest/controller/CandidateController.java | 32 +++++++++---------- .../api/rest/controller/IssueController.java | 2 +- .../ResourceSecurityExpressionRoot.java | 20 ++++++------ 4 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java index 9e48990..4c5c109 100644 --- a/src/main/java/io/github/patternatlas/api/config/Authority.java +++ b/src/main/java/io/github/patternatlas/api/config/Authority.java @@ -5,23 +5,6 @@ public interface Authority { // TODO will be phased out - after all authority checks are changed to hasResourcePermission, this file should not be // needed anymore - /** CANDIDATE */ - String PATTERN_CANDIDATE_READ = "hasAuthority('PATTERN_CANDIDATE_READ')"; - String PATTERN_CANDIDATE_CREATE = "hasAuthority('PATTERN_CANDIDATE_CREATE')"; - String PATTERN_CANDIDATE_EDIT = "hasAuthority('PATTERN_CANDIDATE_EDIT')"; - String PATTERN_CANDIDATE_DELETE = "hasAuthority('PATTERN_CANDIDATE_DELETE')"; - String PATTERN_CANDIDATE_READ_ALL = "hasAuthority('PATTERN_CANDIDATE_READ_ALL')"; - String PATTERN_CANDIDATE_EDIT_ALL = "hasAuthority('PATTERN_CANDIDATE_EDIT_ALL')"; - String PATTERN_CANDIDATE_DELETE_ALL = "hasAuthority('PATTERN_CANDIDATE_DELETE_ALL')"; - String PATTERN_CANDIDATE_TO_PATTERN = "hasAuthority('PATTERN_CANDIDATE_TO_PATTERN')"; - String PATTERN_CANDIDATE_EDIT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_EDIT', #issueId))"; - String PATTERN_CANDIDATE_EDIT_DELETE = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_DELETE', #issueId))"; - String PATTERN_CANDIDATE_EVIDENCE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_EVIDENCE', #issueId))"; - String PATTERN_CANDIDATE_VOTE_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_VOTE', #issueId))"; - String PATTERN_CANDIDATE_COMMENT_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_COMMENT', #issueId))"; - String PATTERN_CANDIDATE_READ_COMBINED = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_READ', #issueId))"; - String PATTERN_CANDIDATE_READ_COMBINED_URI = "hasAnyAuthority(@authorityService.formatResourceAuthorities('PATTERN_CANDIDATE_READ', " + - "@issueService.getIssueByURI(#candidateUri).id))"; /** Pattern */ String APPROVED_PATTERN_READ = "hasAuthority('APPROVED_PATTERN_READ')"; String APPROVED_PATTERN_CREATE = "hasAuthority('APPROVED_PATTERN_CREATE')"; diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java index 555f8b8..373cd83 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java @@ -80,14 +80,14 @@ CollectionModel> all(@RequestParam(value = "lid", re @Operation(operationId = "getCandidateById", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by id") @GetMapping(value = "/{candidateId}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_READ_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_READ)") ResponseEntity> getCandidateById(@PathVariable UUID candidateId) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateById(candidateId)))); } @Operation(operationId = "getCandidateByURI", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by URI") @GetMapping(value = "/?uri={candidateUri}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_READ_COMBINED_URI) + @PreAuthorize(value = "hasResourcePermission(@candidateService.getCandidateByURI(#candidateUri).id, @PC.PATTERN_CANDIDATE_READ)") ResponseEntity> getCandidateByUri(@RequestParam("uri") String candidateUri) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateByURI(candidateUri)))); } @@ -97,7 +97,7 @@ ResponseEntity> getCandidateByUri(@RequestParam("uri */ @Operation(operationId = "createCandidate", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate") @PostMapping(value = "") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_CREATE) + @PreAuthorize(value = "hasGlobalPermission(@PC.PATTERN_CANDIDATE_CREATE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newCandidate(@RequestBody CandidateModelRequest candidateModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createCandidate(candidateModelRequest, UUID.fromString(principal.getName()))))); @@ -105,7 +105,7 @@ ResponseEntity> newCandidate(@RequestBody CandidateM @Operation(operationId = "createCandidateComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate comment") @PostMapping(value = "/{candidateId}/comments") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_COMMENT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_COMMENT)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createComment(candidateId, UUID.fromString(principal.getName()), commentModel)))); @@ -113,7 +113,7 @@ ResponseEntity> newCandidateComment(@PathVariable UU @Operation(operationId = "createCandidateEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate evidence") @PostMapping(value = "/{candidateId}/evidences") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EVIDENCE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EVIDENCE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueEvidence(@PathVariable UUID candidateId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createEvidence(candidateId, UUID.fromString(principal.getName()), evidenceModel)))); @@ -124,7 +124,7 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID */ @Operation(operationId = "updateCandidate", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate") @PutMapping(value = "/{candidateId}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidate(@PathVariable UUID candidateId, Principal principal, @RequestBody CandidateModelRequest candidateModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidate(candidateId, UUID.fromString(principal.getName()), candidateModelRequest)))); @@ -132,21 +132,21 @@ ResponseEntity> putCandidate(@PathVariable UUID cand @Operation(operationId = "updateCandidateRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate rating") @PutMapping(value = "/{candidateId}/ratings") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_VOTE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); } @Operation(operationId = "updateCandidateAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate authors") @PutMapping(value = "{candidateId}/authors") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") ResponseEntity> putCandidateAuthor(@PathVariable UUID candidateId, @RequestBody AuthorModelRequest authorModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.saveCandidateAuthor(candidateId, authorModelRequest)))); } @Operation(operationId = "updateCandidateComment", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment") @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_COMMENT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_COMMENT)") @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()), commentModel)))); @@ -154,14 +154,14 @@ ResponseEntity> putCandidateComment(@PathVariable UU @Operation(operationId = "updateCandidateCommentRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment rating") @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}/ratings") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_VOTE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateCommentRating(candidateId, candidateCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateCandidateEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence") @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_VOTE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putIssueEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); @@ -169,7 +169,7 @@ ResponseEntity> putIssueEvidenceRating(@PathVariable @Operation(operationId = "updateCandidateEvidenceRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence rating") @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}/ratings") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_VOTE_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") ResponseEntity> putCandidateEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateEvidenceRating(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -179,7 +179,7 @@ ResponseEntity> putCandidateEvidenceRating(@PathVari */ @Operation(operationId = "deleteCandidateById", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate by id") @DeleteMapping(value = "/{candidateId}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_DELETE) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_DELETE)") @ResponseStatus(HttpStatus.OK) ResponseEntity deleteCandidate(@PathVariable UUID candidateId, Principal principal) { this.candidateService.deleteCandidate(candidateId, UUID.fromString(principal.getName())); @@ -188,14 +188,14 @@ ResponseEntity deleteCandidate(@PathVariable UUID candidateId, Principal prin @Operation(operationId = "deleteCandidateAuthor", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate author") @DeleteMapping(value = "{candidateId}/authors/{userId}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") ResponseEntity> deleteCandidateAuthor(@PathVariable UUID candidateId, @PathVariable UUID userId) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteCandidateAuthor(candidateId, userId)))); } @Operation(operationId = "deleteCandidateComment", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate comment") @DeleteMapping(value = "/{candidateId}/comments/{candidateCommentId}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") @ResponseStatus(HttpStatus.OK) ResponseEntity> deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()))))); @@ -203,7 +203,7 @@ ResponseEntity> deleteComment(@PathVariable UUID can @Operation(operationId = "deleteCandidateEvidence", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate evidence") @DeleteMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") - @PreAuthorize(value = Authority.PATTERN_CANDIDATE_EDIT_COMBINED) + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") @ResponseStatus(HttpStatus.OK) ResponseEntity> deleteEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()))))); diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index af50577..050a5ea 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -86,7 +86,7 @@ ResponseEntity> getIssueByUri(@PathVariable String issue */ @Operation(operationId = "createIssue", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue") @PostMapping(value = "") - @PreAuthorize(value = "hasAuthority(@PC.ISSUE_CREATE)") + @PreAuthorize(value = "hasGlobalPermission(@PC.ISSUE_CREATE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssue(@RequestBody IssueModelRequest issueModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createIssue(issueModelRequest, UUID.fromString(principal.getName()))))); diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java index e00ca46..39a20df 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java @@ -29,16 +29,18 @@ public ResourceSecurityExpressionRoot(Authentication authentication, this.userService = userService; } + /** + * Checks global permission for user. + * Will only check for the exact permission (e.g. ISSUE_CREATE) + * @param permissionType type of the permission (ISSUE_CREATE) + * @return true if user has permission + */ + public boolean hasGlobalPermission(String permissionType) { + UUID userId = UUID.fromString(this.getAuthentication().getName()); // Supplied through JWT id field - private boolean checkAuthority(Collection userRoles, String authority) { - for(Role role : userRoles) { - for(Privilege privilege : role.getPrivileges()) { - if(privilege.getName().equals(authority)) { - return true; - } - } - } - return false; + return this.userService.hasAnyPrivilege( + userId, + permissionType); } /** From ae97f15f8a7357af740e801dfede1dc06a1100c3 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Apr 2022 10:02:05 +0200 Subject: [PATCH 40/68] added filter functionality for collectionmodel --- .../api/rest/controller/IssueController.java | 2 +- ...sourceMethodSecurityExpressionHandler.java | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index 050a5ea..46aad40 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -56,7 +56,7 @@ public IssueController( */ @Operation(operationId = "getAllIssues", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all issues") @GetMapping(value = "") - // TODO: Filter for read permissions + @PostFilter("hasResourcePermission(filterObject.getContent().id, @PC.ISSUE_READ)") CollectionModel> getAll() { List> issues = this.issueService.getAllIssues() .stream() diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java index f04ac83..b37fc8c 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java @@ -1,18 +1,47 @@ package io.github.patternatlas.api.security; import io.github.patternatlas.api.service.UserService; +import lombok.extern.slf4j.Slf4j; import org.aopalliance.intercept.MethodInvocation; import org.springframework.context.ApplicationContext; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.hateoas.CollectionModel; import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.Authentication; +import java.util.Collection; +import java.util.LinkedList; + +@Slf4j public class ResourceMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { private ApplicationContext applicationContext; private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); + /** Overrides filter to support filtering CollectionModel as it is used in API */ + @Override + public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) { + if(filterTarget instanceof CollectionModel) { + // The collection has to be extracted so filter can work appropriately + /* From the Spring-Documentation + "If a Collection or Map is used, the original instance will be modified + to contain the elements for which the permission expression evaluates to true." + => super.filter should return a collection again, which can be added to + CollectionModel + */ + CollectionModel filterCollectionModel = (CollectionModel)filterTarget; + // Since the Collection obtained from getContent() is immutable, + // a new List has to be created to be filtered + Object filterResult = super.filter(new LinkedList<>(filterCollectionModel.getContent()), filterExpression, ctx); + return CollectionModel.of(filterResult); + } + // Default case - proceed as usual + return super.filter(filterTarget, filterExpression, ctx); + } + @Override protected MethodSecurityExpressionOperations createSecurityExpressionRoot( Authentication authentication, MethodInvocation invocation) { From 923919f9b63d9e8e24c8503a6abf8d672acc59ef Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Apr 2022 12:40:41 +0200 Subject: [PATCH 41/68] added privilege checks for usercontroller --- .../api/rest/controller/UserController.java | 72 +++++++++++-------- .../ResourceSecurityExpressionRoot.java | 7 ++ 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index ee53cf5..6b5bc57 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -1,12 +1,16 @@ package io.github.patternatlas.api.rest.controller; import io.github.patternatlas.api.config.Authority; +import io.github.patternatlas.api.entities.user.UserEntity; +import io.github.patternatlas.api.entities.user.role.Privilege; +import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.rest.model.user.*; import io.github.patternatlas.api.service.UserService; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.http.HttpStatus; @@ -22,8 +26,7 @@ import org.slf4j.LoggerFactory; import java.security.Principal; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; @RestController @@ -46,83 +49,95 @@ public UserController( this.objectMapper = objectMapper; } - // TODO ENTFERNEN - @GetMapping(value="/echo") - String echo(Principal user) { - return user.toString(); + // TODO Entfernen (only for debug) + @GetMapping(value="/whoami") + String whoami(Principal user) { + UserEntity userEntity = this.userService.getUserById(UUID.fromString(user.getName())); + Map> privs = new HashMap<>(); + userEntity.getRoles().forEach( + role -> privs.put(role, role.getPrivileges()) + ); + return user.toString() + + " maps to: " + userEntity.toString() + "\n" + + "privileges" + privs.toString(); } + /** * GET Methods */ @Operation(operationId = "getAllUsers", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all users") @GetMapping(value = "") - @PreAuthorize(value = Authority.USER_READ_ALL) + @PostFilter(value = "hasGlobalPermission(@PC.USER_READ_ALL) " + + "or (hasGlobalPermission(@PC.USER_READ) and filterObject.getContent().id.equals(loggedInUUID()))") CollectionModel> getAll() { List> users = this.userService.getAllUsers() .stream() .map(user -> new EntityModel<>(new UserModel(user))) .collect(Collectors.toList()); - return new CollectionModel<>(users); + // and ) + return CollectionModel.of(users); } @GetMapping(value = "/{userId}") + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_READ_ALL)" + + "or (hasGlobalPermission(@PC.USER_READ) and #userId.equals(loggedInUUID()))") ResponseEntity> getUserById(@PathVariable UUID userId) { - return ResponseEntity.ok(new EntityModel<>(new UserModel(this.userService.getUserById(userId)))); + return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.getUserById(userId)))); } @GetMapping(value = "/roles") CollectionModel> getAllRoles() { List> roles = this.userService.getAllRoles() .stream() - .map(role -> new EntityModel<>(new RoleModel(role))) + .map(role -> EntityModel.of(new RoleModel(role))) .collect(Collectors.toList()); - return new CollectionModel<>(roles); + return CollectionModel.of(roles); } @GetMapping(value = "/roles/platform") CollectionModel> getAllPlatformRoles() { List> roles = this.userService.getAllPlatformRoles() .stream() - .map(role -> new EntityModel<>(new RoleModel(role))) + .map(role -> EntityModel.of(new RoleModel(role))) .collect(Collectors.toList()); - return new CollectionModel<>(roles); + return CollectionModel.of(roles); } @GetMapping(value = "/roles/authors") CollectionModel> getAllAuthorRoles() { List> roles = this.userService.getAllAuthorRoles() .stream() - .map(role -> new EntityModel<>(new RoleModel(role))) + .map(role -> EntityModel.of(new RoleModel(role))) .collect(Collectors.toList()); - return new CollectionModel<>(roles); + return CollectionModel.of(roles); } @GetMapping(value = "/roles/{entityId}") CollectionModel> getAllRolesFromEntity(@PathVariable UUID entityId) { List> roles = this.userService.getAllRolesFromEntity(entityId) .stream() - .map(role -> new EntityModel<>(new RoleModel(role))) + .map(role -> EntityModel.of(new RoleModel(role))) .collect(Collectors.toList()); - return new CollectionModel<>(roles); + return CollectionModel.of(roles); } @GetMapping(value = "/roles/privileges") CollectionModel> getAllPlatformPrivileges() { List> privileges = this.userService.getAllPlatformPrivileges() .stream() - .map(privilege -> new EntityModel<>(new PrivilegeModel(privilege))) + .map(privilege -> EntityModel.of(new PrivilegeModel(privilege))) .collect(Collectors.toList()); - return new CollectionModel<>(privileges); + return CollectionModel.of(privileges); } @GetMapping(value = "/roles/privileges/{entityId}") CollectionModel> getAllPrivilegesFromEntity(@PathVariable UUID entityId) { List> privileges = this.userService.getAllPrivilegesFromEntity(entityId) .stream() - .map(privilege -> new EntityModel<>(new PrivilegeModel(privilege))) + .map(privilege -> EntityModel.of(new PrivilegeModel(privilege))) .collect(Collectors.toList()); - return new CollectionModel<>(privileges); + return CollectionModel.of(privileges); } /** @@ -130,10 +145,10 @@ CollectionModel> getAllPrivilegesFromEntity(@PathVa */ @Operation(operationId = "createUser", responses = {@ApiResponse(responseCode = "200")}, description = "Create a user") @PostMapping(value = "") - @PreAuthorize(value = Authority.USER_CREATE) @ResponseStatus(HttpStatus.CREATED) + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_CREATE)") ResponseEntity> newUser(@RequestBody UserModelRequest userModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new UserModel(this.userService.createUser(userModelRequest)))); + return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.createUser(userModelRequest)))); } /** @@ -141,17 +156,17 @@ ResponseEntity> newUser(@RequestBody UserModelRequest use */ @Operation(operationId = "updateUser", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Update a user") @PutMapping(value = "/{userId}") - @PreAuthorize(value = Authority.USER_EDIT) @ResponseStatus(HttpStatus.ACCEPTED) + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") ResponseEntity> updateUser(@PathVariable UUID userId, @RequestBody UserModelRequest userModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new UserModel(this.userService.updateUser(userId, userModelRequest)))); + return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.updateUser(userId, userModelRequest)))); } @PutMapping(value = "/roles/{roleId}/privileges/{privilegeId}") - @PreAuthorize(value = Authority.USER_READ_ALL) @ResponseStatus(HttpStatus.ACCEPTED) + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") ResponseEntity> updateUserRole(@PathVariable UUID roleId, @PathVariable UUID privilegeId, @RequestBody RoleModelRequest roleModelRequest) { - return ResponseEntity.ok(new EntityModel<>(new RoleModel(this.userService.updateRole(roleId, privilegeId, roleModelRequest)))); + return ResponseEntity.ok(EntityModel.of(new RoleModel(this.userService.updateRole(roleId, privilegeId, roleModelRequest)))); } /** @@ -159,7 +174,8 @@ ResponseEntity> updateUserRole(@PathVariable UUID roleId, */ @Operation(operationId = "deleteUser", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Delete a user") @DeleteMapping(value = "/{userId}") - @PreAuthorize(value = Authority.USER_DELETE) + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)" + + "or (hasGlobalPermission(@PC.USER_READ) and #userId.equals(loggedInUUID()))") ResponseEntity deleteUser(@PathVariable UUID userId) { this.userService.deleteUser(userId); return ResponseEntity.noContent().build(); diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java index 39a20df..856b277 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java @@ -43,6 +43,13 @@ public boolean hasGlobalPermission(String permissionType) { permissionType); } + public UUID loggedInUUID() { + if(this.getAuthentication() != null) { + return UUID.fromString(this.getAuthentication().getName()); + } + return null; + } + /** * Checks permission given the objects UUID. * Will check for general version of the permission (e.g. ISSUE_READ_ALL) From 181baad41546b86a9fceed8ad0e08da7023cb3b2 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Apr 2022 12:58:44 +0200 Subject: [PATCH 42/68] finished usercontroller permission --- .../api/rest/controller/UserController.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 6b5bc57..2c9e96f 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -49,19 +49,6 @@ public UserController( this.objectMapper = objectMapper; } - // TODO Entfernen (only for debug) - @GetMapping(value="/whoami") - String whoami(Principal user) { - UserEntity userEntity = this.userService.getUserById(UUID.fromString(user.getName())); - Map> privs = new HashMap<>(); - userEntity.getRoles().forEach( - role -> privs.put(role, role.getPrivileges()) - ); - return user.toString() + - " maps to: " + userEntity.toString() + "\n" + - "privileges" + privs.toString(); - } - /** * GET Methods From 9d69d5231880dc89419575a83cc92de4bf11ec25 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Apr 2022 15:22:49 +0200 Subject: [PATCH 43/68] moved privilege checks --- .../api/rest/controller/AuthorController.java | 3 ++ .../rest/controller/CandidateController.java | 22 ++----------- .../api/rest/controller/IssueController.java | 31 +++++-------------- .../api/rest/controller/UserController.java | 9 ------ ...sourceMethodSecurityExpressionHandler.java | 3 -- .../ResourceSecurityExpressionRoot.java | 9 ------ .../api/service/CandidateService.java | 23 ++++++++++++++ .../api/service/IssueService.java | 23 +++++++++++++- .../patternatlas/api/service/UserService.java | 18 +++++++++++ 9 files changed, 77 insertions(+), 64 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java index 349f537..488050d 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java @@ -13,6 +13,7 @@ import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PostFilter; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; @@ -36,6 +37,8 @@ public AuthorController( * GET Methods */ @Operation(operationId = "getallUsersAsAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all authors") + @PostFilter(value = "hasGlobalPermission(@PC.USER_READ_ALL) " + + "or (hasGlobalPermission(@PC.USER_READ) and filterObject.getContent().id.equals(loggedInUUID()))") @GetMapping(value = "") CollectionModel> getAll() { List> authors = this.userService.getAllUsers() diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java index 373cd83..40a2127 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java @@ -25,6 +25,7 @@ import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @@ -59,7 +60,6 @@ public CandidateController( */ @Operation(operationId = "getAllCandidates", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all candidates") @GetMapping(value = "") - // TODO: Filter for read permissions CollectionModel> all(@RequestParam(value = "lid", required = false) UUID languageId) { List> candidates; @@ -80,14 +80,12 @@ CollectionModel> all(@RequestParam(value = "lid", re @Operation(operationId = "getCandidateById", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by id") @GetMapping(value = "/{candidateId}") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_READ)") ResponseEntity> getCandidateById(@PathVariable UUID candidateId) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateById(candidateId)))); } @Operation(operationId = "getCandidateByURI", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by URI") - @GetMapping(value = "/?uri={candidateUri}") - @PreAuthorize(value = "hasResourcePermission(@candidateService.getCandidateByURI(#candidateUri).id, @PC.PATTERN_CANDIDATE_READ)") + @GetMapping(value = "/findByUri") ResponseEntity> getCandidateByUri(@RequestParam("uri") String candidateUri) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateByURI(candidateUri)))); } @@ -97,7 +95,6 @@ ResponseEntity> getCandidateByUri(@RequestParam("uri */ @Operation(operationId = "createCandidate", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate") @PostMapping(value = "") - @PreAuthorize(value = "hasGlobalPermission(@PC.PATTERN_CANDIDATE_CREATE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newCandidate(@RequestBody CandidateModelRequest candidateModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createCandidate(candidateModelRequest, UUID.fromString(principal.getName()))))); @@ -105,7 +102,6 @@ ResponseEntity> newCandidate(@RequestBody CandidateM @Operation(operationId = "createCandidateComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate comment") @PostMapping(value = "/{candidateId}/comments") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_COMMENT)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newCandidateComment(@PathVariable UUID candidateId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createComment(candidateId, UUID.fromString(principal.getName()), commentModel)))); @@ -113,7 +109,6 @@ ResponseEntity> newCandidateComment(@PathVariable UU @Operation(operationId = "createCandidateEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate evidence") @PostMapping(value = "/{candidateId}/evidences") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EVIDENCE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueEvidence(@PathVariable UUID candidateId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createEvidence(candidateId, UUID.fromString(principal.getName()), evidenceModel)))); @@ -124,7 +119,6 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID */ @Operation(operationId = "updateCandidate", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate") @PutMapping(value = "/{candidateId}") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidate(@PathVariable UUID candidateId, Principal principal, @RequestBody CandidateModelRequest candidateModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidate(candidateId, UUID.fromString(principal.getName()), candidateModelRequest)))); @@ -132,21 +126,18 @@ ResponseEntity> putCandidate(@PathVariable UUID cand @Operation(operationId = "updateCandidateRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate rating") @PutMapping(value = "/{candidateId}/ratings") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") ResponseEntity> putCandidateRating(@PathVariable UUID candidateId, Principal principal, @RequestBody RatingModelMultiRequest ratingModelMultiRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateRating(candidateId, UUID.fromString(principal.getName()), ratingModelMultiRequest)))); } @Operation(operationId = "updateCandidateAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate authors") @PutMapping(value = "{candidateId}/authors") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") ResponseEntity> putCandidateAuthor(@PathVariable UUID candidateId, @RequestBody AuthorModelRequest authorModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.saveCandidateAuthor(candidateId, authorModelRequest)))); } @Operation(operationId = "updateCandidateComment", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment") @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_COMMENT)") @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> putCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()), commentModel)))); @@ -154,22 +145,19 @@ ResponseEntity> putCandidateComment(@PathVariable UU @Operation(operationId = "updateCandidateCommentRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate comment rating") @PutMapping(value = "/{candidateId}/comments/{candidateCommentId}/ratings") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") ResponseEntity> putCandidateCommentRating(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateCommentRating(candidateId, candidateCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateCandidateEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence") @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") @ResponseStatus(HttpStatus.ACCEPTED) - ResponseEntity> putIssueEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { + ResponseEntity> putIssueEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); } @Operation(operationId = "updateCandidateEvidenceRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate evidence rating") @PutMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}/ratings") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") ResponseEntity> putCandidateEvidenceRating(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.updateCandidateEvidenceRating(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -179,7 +167,6 @@ ResponseEntity> putCandidateEvidenceRating(@PathVari */ @Operation(operationId = "deleteCandidateById", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate by id") @DeleteMapping(value = "/{candidateId}") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_DELETE)") @ResponseStatus(HttpStatus.OK) ResponseEntity deleteCandidate(@PathVariable UUID candidateId, Principal principal) { this.candidateService.deleteCandidate(candidateId, UUID.fromString(principal.getName())); @@ -188,14 +175,12 @@ ResponseEntity deleteCandidate(@PathVariable UUID candidateId, Principal prin @Operation(operationId = "deleteCandidateAuthor", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate author") @DeleteMapping(value = "{candidateId}/authors/{userId}") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") ResponseEntity> deleteCandidateAuthor(@PathVariable UUID candidateId, @PathVariable UUID userId) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteCandidateAuthor(candidateId, userId)))); } @Operation(operationId = "deleteCandidateComment", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate comment") @DeleteMapping(value = "/{candidateId}/comments/{candidateCommentId}") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") @ResponseStatus(HttpStatus.OK) ResponseEntity> deleteComment(@PathVariable UUID candidateId, @PathVariable UUID candidateCommentId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteComment(candidateId, candidateCommentId, UUID.fromString(principal.getName()))))); @@ -203,7 +188,6 @@ ResponseEntity> deleteComment(@PathVariable UUID can @Operation(operationId = "deleteCandidateEvidence", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate evidence") @DeleteMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}") - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") @ResponseStatus(HttpStatus.OK) ResponseEntity> deleteEvidence(@PathVariable UUID candidateId, @PathVariable UUID candidateEvidenceId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.deleteEvidence(candidateId, candidateEvidenceId, UUID.fromString(principal.getName()))))); diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index 46aad40..0dc4d0d 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -54,9 +54,16 @@ public IssueController( /** * GET Methods */ + + @Operation(operationId = "getIssueByURI", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by URI") + @GetMapping(value = "/findByUri") + ResponseEntity> getIssueByUri(@RequestParam String uri) { + return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueByURI(uri)))); + } + + @Operation(operationId = "getAllIssues", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all issues") @GetMapping(value = "") - @PostFilter("hasResourcePermission(filterObject.getContent().id, @PC.ISSUE_READ)") CollectionModel> getAll() { List> issues = this.issueService.getAllIssues() .stream() @@ -69,24 +76,15 @@ CollectionModel> getAll() { @Operation(operationId = "getIssueById", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by id") @GetMapping(value = "/{issueId}") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_READ)") ResponseEntity> getIssueById(@PathVariable UUID issueId) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueById(issueId)))); } - @Operation(operationId = "getIssueByURI", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by URI") - @GetMapping(value = "/?uri={issueUri}") - @PreAuthorize(value = "hasResourcePermission(@issueService.getIssueByURI(#issueUri).id, @PC.ISSUE_READ)") - ResponseEntity> getIssueByUri(@PathVariable String issueUri) { - return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueByURI(issueUri)))); - } - /** * CREATE Methods */ @Operation(operationId = "createIssue", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue") @PostMapping(value = "") - @PreAuthorize(value = "hasGlobalPermission(@PC.ISSUE_CREATE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssue(@RequestBody IssueModelRequest issueModelRequest, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createIssue(issueModelRequest, UUID.fromString(principal.getName()))))); @@ -94,7 +92,6 @@ ResponseEntity> newIssue(@RequestBody IssueModelRequest @Operation(operationId = "createIssueComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue comment") @PostMapping(value = "/{issueId}/comments") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_COMMENT)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueComment(@PathVariable UUID issueId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createComment(issueId, UUID.fromString(principal.getName()), commentModel)))); @@ -102,7 +99,6 @@ ResponseEntity> newIssueComment(@PathVariable UUID issue @Operation(operationId = "createIssueEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue evidence") @PostMapping(value = "/{issueId}/evidences") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EVIDENCE)") @ResponseStatus(HttpStatus.CREATED) ResponseEntity> newIssueEvidence(@PathVariable UUID issueId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createEvidence(issueId, UUID.fromString(principal.getName()), evidenceModel)))); @@ -112,7 +108,6 @@ ResponseEntity> newIssueEvidence(@PathVariable UUID issu * UPDATE Methods */ @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @PutMapping(value = "/{issueId}") ResponseEntity> putIssue(@PathVariable UUID issueId, Principal principal, @RequestBody IssueModelRequest issueModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssue(issueId, UUID.fromString(principal.getName()), issueModelRequest)))); @@ -120,13 +115,11 @@ ResponseEntity> putIssue(@PathVariable UUID issueId, Pri @Operation(operationId = "updateIssueRatings", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue ratings") @PutMapping(value = "/{issueId}/ratings") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") ResponseEntity> putIssueRating(@PathVariable UUID issueId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueRating(issueId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateIssueAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue authors") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @PutMapping(value = "{issueId}/authors") ResponseEntity> putIssueAuthor(@PathVariable UUID issueId, @RequestBody AuthorModelRequest authorModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.saveIssueAuthor(issueId, authorModelRequest)))); @@ -134,28 +127,24 @@ ResponseEntity> putIssueAuthor(@PathVariable UUID issueI @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment") @PutMapping(value = "/{issueId}/comments/{issueCommentId}") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_COMMENT)") ResponseEntity> putIssueComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal, @RequestBody CommentModel commentModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateComment(issueId, issueCommentId, UUID.fromString(principal.getName()), commentModel)))); } @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment rating") @PutMapping(value = "/{issueId}/comments/{issueCommentId}/ratings") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") ResponseEntity> putIssueCommentRating(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EVIDENCE)") ResponseEntity> putIssueEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal, @RequestBody EvidenceModel evidenceModel) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()), evidenceModel)))); } @Operation(operationId = "updateIssueEvidenceRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue evidence rating") @PutMapping(value = "/{issueId}/evidences/{issueEvidenceId}/ratings") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") ResponseEntity> putIssueEvidenceRating(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueEvidenceRating(issueId, issueEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest)))); } @@ -165,28 +154,24 @@ ResponseEntity> putIssueEvidenceRating(@PathVariable UUI */ @Operation(operationId = "deleteIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue") @DeleteMapping(value = "/{issueId}") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_DELETE)") ResponseEntity deleteIssue(@PathVariable UUID issueId) { this.issueService.deleteIssue(issueId); return ResponseEntity.noContent().build(); } @Operation(operationId = "deleteIssueAuthor", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @DeleteMapping(value = "{issueId}/authors/{userId}") ResponseEntity> deleteIssueAuthor(@PathVariable UUID issueId, @PathVariable UUID userId) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteIssueAuthor(issueId, userId)))); } @Operation(operationId = "deleteIssueComment", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue comment") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @DeleteMapping(value = "/{issueId}/comments/{issueCommentId}") ResponseEntity> deleteComment(@PathVariable UUID issueId, @PathVariable UUID issueCommentId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteComment(issueId, issueCommentId, UUID.fromString(principal.getName()))))); } @Operation(operationId = "deleteIssueEvidence", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue evidence") - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @DeleteMapping(value = "/{issueId}/evidences/{issueEvidenceId}") ResponseEntity> deleteEvidence(@PathVariable UUID issueId, @PathVariable UUID issueEvidenceId, Principal principal) { return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.deleteEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()))))); diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 2c9e96f..a6d9026 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -55,8 +55,6 @@ public UserController( */ @Operation(operationId = "getAllUsers", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all users") @GetMapping(value = "") - @PostFilter(value = "hasGlobalPermission(@PC.USER_READ_ALL) " + - "or (hasGlobalPermission(@PC.USER_READ) and filterObject.getContent().id.equals(loggedInUUID()))") CollectionModel> getAll() { List> users = this.userService.getAllUsers() .stream() @@ -67,8 +65,6 @@ CollectionModel> getAll() { } @GetMapping(value = "/{userId}") - @PreAuthorize(value = "hasGlobalPermission(@PC.USER_READ_ALL)" + - "or (hasGlobalPermission(@PC.USER_READ) and #userId.equals(loggedInUUID()))") ResponseEntity> getUserById(@PathVariable UUID userId) { return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.getUserById(userId)))); } @@ -133,7 +129,6 @@ CollectionModel> getAllPrivilegesFromEntity(@PathVa @Operation(operationId = "createUser", responses = {@ApiResponse(responseCode = "200")}, description = "Create a user") @PostMapping(value = "") @ResponseStatus(HttpStatus.CREATED) - @PreAuthorize(value = "hasGlobalPermission(@PC.USER_CREATE)") ResponseEntity> newUser(@RequestBody UserModelRequest userModelRequest) { return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.createUser(userModelRequest)))); } @@ -144,14 +139,12 @@ ResponseEntity> newUser(@RequestBody UserModelRequest use @Operation(operationId = "updateUser", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Update a user") @PutMapping(value = "/{userId}") @ResponseStatus(HttpStatus.ACCEPTED) - @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") ResponseEntity> updateUser(@PathVariable UUID userId, @RequestBody UserModelRequest userModelRequest) { return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.updateUser(userId, userModelRequest)))); } @PutMapping(value = "/roles/{roleId}/privileges/{privilegeId}") @ResponseStatus(HttpStatus.ACCEPTED) - @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") ResponseEntity> updateUserRole(@PathVariable UUID roleId, @PathVariable UUID privilegeId, @RequestBody RoleModelRequest roleModelRequest) { return ResponseEntity.ok(EntityModel.of(new RoleModel(this.userService.updateRole(roleId, privilegeId, roleModelRequest)))); } @@ -161,8 +154,6 @@ ResponseEntity> updateUserRole(@PathVariable UUID roleId, */ @Operation(operationId = "deleteUser", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Delete a user") @DeleteMapping(value = "/{userId}") - @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)" + - "or (hasGlobalPermission(@PC.USER_READ) and #userId.equals(loggedInUUID()))") ResponseEntity deleteUser(@PathVariable UUID userId) { this.userService.deleteUser(userId); return ResponseEntity.noContent().build(); diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java index b37fc8c..1ef7f42 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java @@ -1,7 +1,6 @@ package io.github.patternatlas.api.security; import io.github.patternatlas.api.service.UserService; -import lombok.extern.slf4j.Slf4j; import org.aopalliance.intercept.MethodInvocation; import org.springframework.context.ApplicationContext; import org.springframework.expression.EvaluationContext; @@ -13,10 +12,8 @@ import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.Authentication; -import java.util.Collection; import java.util.LinkedList; -@Slf4j public class ResourceMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { private ApplicationContext applicationContext; private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java index 856b277..0124c08 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java @@ -1,20 +1,11 @@ package io.github.patternatlas.api.security; -import io.github.patternatlas.api.entities.user.UserEntity; -import io.github.patternatlas.api.entities.user.role.Privilege; -import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.service.UserService; -import org.apache.catalina.User; import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.UUID; public class ResourceSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations { diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateService.java b/src/main/java/io/github/patternatlas/api/service/CandidateService.java index eab59fa..7fe98db 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateService.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateService.java @@ -10,6 +10,9 @@ import io.github.patternatlas.api.rest.model.shared.*; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PostAuthorize; +import org.springframework.security.access.prepost.PostFilter; +import org.springframework.security.access.prepost.PreAuthorize; import java.util.List; import java.util.UUID; @@ -17,46 +20,66 @@ public interface CandidateService { Candidate saveCandidate(Candidate candidate); /** CRUD */ + @PreAuthorize(value = "hasGlobalPermission(@PC.PATTERN_CANDIDATE_CREATE)") Candidate createCandidate(CandidateModelRequest candidateModelRequest, UUID userId); + @PostFilter("hasResourcePermission(filterObject.id, @PC.PATTERN_CANDIDATE_READ)") List getAllCandidates(); + @PostFilter("hasResourcePermission(filterObject.id, @PC.PATTERN_CANDIDATE_READ)") List getAllCandidatesByLanguageId(UUID languageId); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_READ)") Candidate getCandidateById(UUID candidateId); + @PostAuthorize(value = "hasResourcePermission(returnObject.id, @PC.PATTERN_CANDIDATE_READ)") Candidate getCandidateByURI(String uri); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRequest candidateModelRequest); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") Candidate updateCandidateRating(UUID candidateId, UUID userId, RatingModelMultiRequest ratingModelMultiRequest); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_DELETE)") void deleteCandidate(UUID candidateId, UUID userId); /** Author */ + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") Candidate saveCandidateAuthor(UUID candidateId, AuthorModelRequest authorModelRequest); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") Candidate deleteCandidateAuthor(UUID candidateId, UUID userId); /** Comment */ + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_COMMENT)") Candidate createComment(UUID candidateId, UUID userId, CommentModel commentModel); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_READ)") CandidateComment getCommentById(UUID candidateCommentId); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") Candidate updateComment(UUID candidateId, UUID commentId, UUID userId, CommentModel commentModel); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") Candidate updateCandidateCommentRating(UUID candidateId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") Candidate deleteComment(UUID candidateId, UUID commentId, UUID userId); /** Evidence */ + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EVIDENCE)") Candidate createEvidence(UUID candidateId, UUID userId, EvidenceModel evidenceModel); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_READ)") CandidateEvidence getEvidenceById(UUID evidenceId); + @PreAuthorize(value = "hasResourcePermission(#candiateId, @PC.PATTERN_CANDIDATE_EDIT)") Candidate updateEvidence(UUID candidateId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") Candidate updateCandidateEvidenceRating(UUID candidateId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest); + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") Candidate deleteEvidence(UUID candidateId, UUID evidenceId, UUID userId); } \ No newline at end of file diff --git a/src/main/java/io/github/patternatlas/api/service/IssueService.java b/src/main/java/io/github/patternatlas/api/service/IssueService.java index dac0766..44c48aa 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueService.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueService.java @@ -16,6 +16,9 @@ import io.github.patternatlas.api.rest.model.shared.RatingModelRequest; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PostAuthorize; +import org.springframework.security.access.prepost.PostFilter; +import org.springframework.security.access.prepost.PreAuthorize; import java.util.UUID; @@ -23,48 +26,66 @@ public interface IssueService { Issue saveIssue(Issue issue); /** CRUD */ + @PreAuthorize(value = "hasGlobalPermission(@PC.ISSUE_CREATE)") Issue createIssue(IssueModelRequest issueModelRequest, UUID userId); + @PostFilter("hasResourcePermission(filterObject.id, @PC.ISSUE_READ)") List getAllIssues(); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_READ)") Issue getIssueById(UUID issueId); + @PostAuthorize(value = "hasResourcePermission(returnObject.id, @PC.ISSUE_READ)") Issue getIssueByURI(String uri); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") Issue updateIssue(UUID issueId, UUID userId, IssueModelRequest issueModelRequest); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") Issue updateIssueRating(UUID issueId, UUID userId, RatingModelRequest ratingModelRequest); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_DELETE)") void deleteIssue(UUID issueId); boolean authorPermissions(UUID issueId, UUID userId); /** Author */ - + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") Issue saveIssueAuthor(UUID issueId, AuthorModelRequest authorModelRequest); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") Issue deleteIssueAuthor(UUID issueId, UUID userId); /** Comment */ + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_COMMENT)") Issue createComment(UUID issueId, UUID userId, CommentModel commentModel); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_READ)") IssueComment getCommentById(UUID issueCommentId); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") Issue updateComment(UUID issueId, UUID commentId, UUID userId, CommentModel commentModel); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") Issue updateIssueCommentRating(UUID issueId, UUID commentId, UUID userId, RatingModelRequest ratingModelRequest); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") Issue deleteComment(UUID issueId, UUID commentId, UUID userId); /** Evidence */ + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EVIDENCE)") Issue createEvidence(UUID issueId, UUID userId, EvidenceModel evidenceModel); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_READ)") IssueEvidence getEvidenceById(UUID issueEvidenceId); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") Issue updateEvidence(UUID issueId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_VOTE)") Issue updateIssueEvidenceRating(UUID issueId, UUID evidenceID, UUID userId, RatingModelRequest ratingModelRequest); + @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") Issue deleteEvidence(UUID issueId, UUID evidenceId, UUID userId); diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index 3be35ad..80fed58 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -8,16 +8,32 @@ import io.github.patternatlas.api.rest.model.user.RoleModelRequest; import io.github.patternatlas.api.rest.model.user.UserModel; import io.github.patternatlas.api.rest.model.user.UserModelRequest; +import org.springframework.security.access.prepost.PostFilter; +import org.springframework.security.access.prepost.PreAuthorize; import java.util.List; import java.util.UUID; public interface UserService { UserEntity saveUser(UserEntity user); + + + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_CREATE)") UserEntity createUser(UserModelRequest userModelRequest); + + @PostFilter(value = "hasGlobalPermission(@PC.USER_READ_ALL) " + + "or (hasGlobalPermission(@PC.USER_READ) and filterObject.id.equals(loggedInUUID()))") List getAllUsers(); + + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_READ_ALL)" + + "or (hasGlobalPermission(@PC.USER_READ) and #userId.equals(loggedInUUID()))") UserEntity getUserById(UUID UserId); + + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") UserEntity updateUser(UUID userId, UserModelRequest userModelRequest); + + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_DELETE_ALL)" + + "or (hasGlobalPermission(@PC.USER_DELETE) and #userId.equals(loggedInUUID()))") void deleteUser(UUID UserId); /** @@ -36,5 +52,7 @@ public interface UserService { List getAllRolesFromEntity(UUID entityId); List getAllPlatformPrivileges(); List getAllPrivilegesFromEntity(UUID entityId); + + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") Role updateRole(UUID roleId, UUID privilegeId, RoleModelRequest roleModelRequest); } \ No newline at end of file From 77a5ea67266a4ae93ac2c0e12f2dfd48d88ab351 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 5 Apr 2022 10:25:32 +0200 Subject: [PATCH 44/68] removed swagger ui --- pom.xml | 5 ----- .../api/rest/exception/RestResponseExceptionHandler.java | 1 + src/main/resources/application-docker.properties | 4 ---- src/main/resources/application.properties | 4 ---- src/main/resources/applicationYML.yml | 4 ---- 5 files changed, 1 insertion(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index 20d0393..a60d28e 100644 --- a/pom.xml +++ b/pom.xml @@ -138,11 +138,6 @@ - - org.springdoc - springdoc-openapi-ui - ${springdoc-ui.version} - org.springdoc springdoc-openapi-data-rest diff --git a/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java b/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java index fc87066..54176fe 100644 --- a/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java +++ b/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java @@ -40,6 +40,7 @@ protected ResponseEntity handleNullPatternSchemaException(RuntimeExcepti Exception.class }) protected ResponseEntity handleStorageExceptions(Exception ex, WebRequest request) { + ex.printStackTrace(); ErrorMessageDTO errorMessage = new ErrorMessageDTO(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); return handleExceptionInternal(ex, errorMessage, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request); } diff --git a/src/main/resources/application-docker.properties b/src/main/resources/application-docker.properties index ef71205..ca87b57 100644 --- a/src/main/resources/application-docker.properties +++ b/src/main/resources/application-docker.properties @@ -8,10 +8,6 @@ spring.jpa.hibernate.ddl-auto=update logging.level.io.github.patternatlas.api=debug spring.datasource.initialization-mode=always spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true -#springdoc.swagger-ui.url=/patternpedia/v3/api-docs -#springdoc.swagger-ui.path=/swagger-ui -#springdoc.swagger-ui.config-url=/patternpedia/v3/api-docs/swagger-config -#springdoc.swagger-ui.operationsSorter=alpha springdoc.default-produces-media-type=application/hal+json security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json #okta.oauth2.issuer=https://dev-918271.okta.com/oauth2/default diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8d52214..2beae1f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -8,10 +8,6 @@ spring.jpa.hibernate.ddl-auto=update logging.level.io.github.patternatlas.api=debug spring.datasource.initialization-mode=always spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true -#springdoc.swagger-ui.url=/patternatlas/v3/api-docs -#springdoc.swagger-ui.path=/swagger-ui -#springdoc.swagger-ui.config-url=/patternatlas/v3/api-docs/swagger-config -#springdoc.swagger-ui.operationsSorter=alpha springdoc.default-produces-media-type=application/hal+json security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json #okta.oauth2.issuer=https://dev-918271.okta.com/oauth2/default diff --git a/src/main/resources/applicationYML.yml b/src/main/resources/applicationYML.yml index dc4a697..b670a8f 100644 --- a/src/main/resources/applicationYML.yml +++ b/src/main/resources/applicationYML.yml @@ -29,7 +29,3 @@ security: jwk: key-set-uri: http://localhost:8081/.well-known/jwks.json -springdoc: - swagger-ui: - path: /swagger-ui.html - From 8e2541efc75f88ea8051be266bf48f35ded251c6 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 5 Apr 2022 10:53:24 +0200 Subject: [PATCH 45/68] changed resource server config for removed swagger --- .../io/github/patternatlas/api/config/ResourceServerConfig.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java index de3ea1f..01045a1 100644 --- a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java +++ b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java @@ -27,7 +27,6 @@ public void configure(HttpSecurity http) throws Exception { .antMatchers("/**") .and() .authorizeRequests() - .antMatchers("/swagger-ui/**").permitAll() // START::Comment for local development with authorization // .antMatchers(HttpMethod.GET, "/**").permitAll() // .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") From c4b248355f924c295bf0b6f9c36a6452957411ab Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 5 Apr 2022 12:00:11 +0200 Subject: [PATCH 46/68] added role management for authors in candidateservice --- .../api/rest/controller/AuthorController.java | 5 +++-- .../api/rest/controller/UserController.java | 5 +++++ .../patternatlas/api/service/CandidateServiceImpl.java | 10 ++++++++++ .../github/patternatlas/api/service/UserService.java | 4 ---- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java index 488050d..c82c872 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java @@ -36,9 +36,10 @@ public AuthorController( /** * GET Methods */ + + // Only exposes username and ID for author management purposes - every user should be able to set others + // as authors, therefore it is not secured @Operation(operationId = "getallUsersAsAuthors", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all authors") - @PostFilter(value = "hasGlobalPermission(@PC.USER_READ_ALL) " + - "or (hasGlobalPermission(@PC.USER_READ) and filterObject.getContent().id.equals(loggedInUUID()))") @GetMapping(value = "") CollectionModel> getAll() { List> authors = this.userService.getAllUsers() diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index a6d9026..26ae8e0 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -53,8 +53,13 @@ public UserController( /** * GET Methods */ + + // Exposes whole activity of each user (including created issues, candidates...). This should only be + // allowed for USER_READ_ALL, or USER_READ if it is for user themselves @Operation(operationId = "getAllUsers", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all users") @GetMapping(value = "") + @PostFilter(value = "hasGlobalPermission(@PC.USER_READ_ALL) or " + + "(hasGlobalPermission(@PC.USER_READ) and filterObject.getContent().id.equals(loggedInUUID()))") CollectionModel> getAll() { List> users = this.userService.getAllUsers() .stream() diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index dc04244..5097a20 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -31,6 +31,8 @@ import javax.persistence.EntityExistsException; import javax.persistence.EntityNotFoundException; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; @Service @Transactional @@ -323,7 +325,15 @@ public Candidate deleteCandidateAuthor(UUID candidateId, UUID userId) { UserEntity user = this.userService.getUserById(userId); CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user); if (this.candidateAuthorRepository.existsById(candidateAuthor.getId())) { + + List roles = this.userService.getAllRolesFromEntity(candidateId) // find all roles for candidate + .stream().filter((role) -> role.getUsers().contains(user)) // filter for roles for current user + .collect(Collectors.toList()); + + user.getRoles().removeAll(roles); // delete only those + this.candidateAuthorRepository.deleteById(candidateAuthor.getId()); + this.userService.saveUser(user); } return this.getCandidateById(candidateId); } diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index 80fed58..c3cfdd5 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -21,12 +21,8 @@ public interface UserService { @PreAuthorize(value = "hasGlobalPermission(@PC.USER_CREATE)") UserEntity createUser(UserModelRequest userModelRequest); - @PostFilter(value = "hasGlobalPermission(@PC.USER_READ_ALL) " + - "or (hasGlobalPermission(@PC.USER_READ) and filterObject.id.equals(loggedInUUID()))") List getAllUsers(); - @PreAuthorize(value = "hasGlobalPermission(@PC.USER_READ_ALL)" + - "or (hasGlobalPermission(@PC.USER_READ) and #userId.equals(loggedInUUID()))") UserEntity getUserById(UUID UserId); @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") From e7db34786fdd34855512aa55a084d254735ac9de Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 5 Apr 2022 12:18:27 +0200 Subject: [PATCH 47/68] fixed author deleting for issue --- .../patternatlas/api/service/CandidateServiceImpl.java | 1 - .../github/patternatlas/api/service/IssueServiceImpl.java | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index 5097a20..b28a3b0 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -325,7 +325,6 @@ public Candidate deleteCandidateAuthor(UUID candidateId, UUID userId) { UserEntity user = this.userService.getUserById(userId); CandidateAuthor candidateAuthor = new CandidateAuthor(candidate, user); if (this.candidateAuthorRepository.existsById(candidateAuthor.getId())) { - List roles = this.userService.getAllRolesFromEntity(candidateId) // find all roles for candidate .stream().filter((role) -> role.getUsers().contains(user)) // filter for roles for current user .collect(Collectors.toList()); diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index ee3b909..9ef99f7 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -30,6 +30,7 @@ import javax.persistence.EntityExistsException; import javax.persistence.EntityNotFoundException; import java.util.*; +import java.util.stream.Collectors; @Service @Transactional @@ -226,6 +227,13 @@ public Issue deleteIssueAuthor(UUID issueId, UUID userId) { UserEntity user = this.userService.getUserById(userId); IssueAuthor issueAuthor = new IssueAuthor(issue, user); if (this.issueAuthorRepository.existsById(issueAuthor.getId())) { + List roles = this.userService.getAllRolesFromEntity(issueId) // find all roles for issue + .stream().filter((role) -> role.getUsers().contains(user)) // filter for roles for current user + .collect(Collectors.toList()); + + user.getRoles().removeAll(roles); // delete only those + + this.userService.saveUser(user); this.issueAuthorRepository.deleteById(issueAuthor.getId()); } return this.getIssueById(issueId); From 430107c03f1ffe15280a7ead5613b0f8fc56c905 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 5 Apr 2022 12:26:45 +0200 Subject: [PATCH 48/68] removed in-code checks for privileges --- .../api/service/CandidateServiceImpl.java | 55 ++++++------------- .../api/service/IssueService.java | 2 - .../api/service/IssueServiceImpl.java | 14 ----- 3 files changed, 16 insertions(+), 55 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index b28a3b0..9b50a34 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -212,26 +212,21 @@ public Candidate updateCandidate(UUID candidateId, UUID userId, CandidateModelRe Candidate candidate = this.getCandidateById(candidateId); UserEntity user = this.userService.getUserById(userId); - if (user.getRoles().stream().anyMatch(role -> role.checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EDIT_ALL)) || this.authorPermissions(candidateModelRequest.getId(), userId)) { - // UPDATE issue fields - if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) { - Candidate candidateByURI = this.getCandidateByURI(candidateModelRequest.getUri()); - // NOT uri & name change - if (!candidateByURI.getId().equals(candidate.getId())) { - throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); - } + if (this.candidateRepository.existsByUri(candidateModelRequest.getUri())) { + Candidate candidateByURI = this.getCandidateByURI(candidateModelRequest.getUri()); + // NOT uri & name change + if (!candidateByURI.getId().equals(candidate.getId())) { + throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); } - // ADD pattern language - if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) - candidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); + } + // ADD pattern language + if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) + candidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); - // UPDATE issue fields - candidate.updateCandidate(candidateModelRequest); + // UPDATE issue fields + candidate.updateCandidate(candidateModelRequest); - return this.candidateRepository.save(candidate); - } else { - throw new RuntimeException("You don't have the permission"); - } + return this.candidateRepository.save(candidate); } @Override @@ -273,29 +268,11 @@ public Candidate updateCandidateRating(UUID candidateId, UUID userId, RatingMode public void deleteCandidate(UUID candidateId, UUID userId) { UserEntity user = this.userService.getUserById(userId); - if (user.getRoles().stream().anyMatch(role -> role.checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_DELETE_ALL)) || this.authorPermissions(candidateId, userId)) { - this.roleService.deleteAllRolesByResourceId(candidateId); - this.privilegeService.deleteAllPrivilegesByResourceId(candidateId); - user.removeRole(candidateId.toString()); - this.candidateRepository.deleteById(candidateId); - } else { - throw new RuntimeException("You don't have the permission"); - } - - } + this.roleService.deleteAllRolesByResourceId(candidateId); + this.privilegeService.deleteAllPrivilegesByResourceId(candidateId); + user.removeRole(candidateId.toString()); + this.candidateRepository.deleteById(candidateId); - public boolean authorPermissions(UUID candidateId, UUID userId) { - if (candidateId == null) - return false; - Candidate candidate = this.getCandidateById(candidateId); - for (CandidateAuthor author : candidate.getAuthors()) { - if (author.getUser().getId() == userId) { - if (author.getRole().equals(AuthorConstant.OWNER) || author.getRole().equals(AuthorConstant.MAINTAINER)) { - return true; - } - } - } - return false; } /** diff --git a/src/main/java/io/github/patternatlas/api/service/IssueService.java b/src/main/java/io/github/patternatlas/api/service/IssueService.java index 44c48aa..cc3709e 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueService.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueService.java @@ -47,8 +47,6 @@ public interface IssueService { @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_DELETE)") void deleteIssue(UUID issueId); - boolean authorPermissions(UUID issueId, UUID userId); - /** Author */ @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") Issue saveIssueAuthor(UUID issueId, AuthorModelRequest authorModelRequest); diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index 9ef99f7..c6797c4 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -184,20 +184,6 @@ public void deleteIssue(UUID issueId) { this.issueRepository.deleteById(issueId); } - public boolean authorPermissions(UUID issueId, UUID userId) { - if (issueId == null) - return false; - Issue issue = this.getIssueById(issueId); - for (IssueAuthor author : issue.getAuthors()) { - if (author.getUser().getId() == userId) { - if (author.getRole().equals(AuthorConstant.OWNER) || author.getRole().equals(AuthorConstant.MAINTAINER) ) { - return true; - } - } - } - return false; - } - /** * Author */ From 7a297a884e35e1aa3f18468195b399d4f6dda4a4 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 5 Apr 2022 12:35:23 +0200 Subject: [PATCH 49/68] fixed candidate service privilege check --- .../api/service/CandidateServiceImpl.java | 130 +++++++++--------- 1 file changed, 63 insertions(+), 67 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index 9b50a34..357e5a6 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -103,78 +103,74 @@ public Candidate createCandidate(CandidateModelRequest candidateModelRequest, UU throw new EntityExistsException(String.format("Candidate uri %s already exist!", candidateModelRequest.getUri())); // ISSUE TO PATTERN - if (user.getRoles().stream().anyMatch(role -> role.checkPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_CREATE)) || this.issueService.authorPermissions(candidateModelRequest.getIssueId(), userId)) { - Candidate newCandidate = this.candidateRepository.save(candidate); - - Privilege readCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_READ + '_' + newCandidate.getId()); - Privilege updateCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EDIT + '_' + newCandidate.getId()); - Privilege deleteCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_DELETE + '_' + newCandidate.getId()); - Privilege commentCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_COMMENT + '_' + newCandidate.getId()); - Privilege voteCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_VOTE + '_' + newCandidate.getId()); - Privilege evidenceCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EVIDENCE + '_' + newCandidate.getId()); - Privilege toApprovedPattern = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_TO_PATTERN + '_' + newCandidate.getId()); - - Role helper = this.roleService.createRole(RoleConstant.HELPER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( - readCandidatePrivilege, - commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege - )); - Role maintainer = this.roleService.createRole(RoleConstant.MAINTAINER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( - readCandidatePrivilege, updateCandidatePrivilege, - commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege - )); - Role owner = this.roleService.createRole(RoleConstant.OWNER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( - readCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege, toApprovedPattern, - commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege - )); - - if (candidateModelRequest.getIssueId() != null) { - logger.info("Issue to Candidate request"); - Issue issue = this.issueService.getIssueById(candidateModelRequest.getIssueId()); - for (IssueEvidence issueEvidence: issue.getEvidences()) { - CandidateEvidence evidence = new CandidateEvidence(issueEvidence, newCandidate, user); - newCandidate.getEvidences().add(evidence); - } - this.issueService.deleteIssue(candidateModelRequest.getIssueId()); + Candidate newCandidate = this.candidateRepository.save(candidate); + + Privilege readCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_READ + '_' + newCandidate.getId()); + Privilege updateCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EDIT + '_' + newCandidate.getId()); + Privilege deleteCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_DELETE + '_' + newCandidate.getId()); + Privilege commentCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_COMMENT + '_' + newCandidate.getId()); + Privilege voteCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_VOTE + '_' + newCandidate.getId()); + Privilege evidenceCandidatePrivilege = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_EVIDENCE + '_' + newCandidate.getId()); + Privilege toApprovedPattern = this.privilegeService.createPrivilege(PrivilegeConstant.PATTERN_CANDIDATE_TO_PATTERN + '_' + newCandidate.getId()); + + Role helper = this.roleService.createRole(RoleConstant.HELPER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( + readCandidatePrivilege, + commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege + )); + Role maintainer = this.roleService.createRole(RoleConstant.MAINTAINER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( + readCandidatePrivilege, updateCandidatePrivilege, + commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege + )); + Role owner = this.roleService.createRole(RoleConstant.OWNER + "_PATTERN_CANDIDATE_" + newCandidate.getId(), Arrays.asList( + readCandidatePrivilege, updateCandidatePrivilege, deleteCandidatePrivilege, toApprovedPattern, + commentCandidatePrivilege, voteCandidatePrivilege, evidenceCandidatePrivilege + )); + + if (candidateModelRequest.getIssueId() != null) { + logger.info("Issue to Candidate request"); + Issue issue = this.issueService.getIssueById(candidateModelRequest.getIssueId()); + for (IssueEvidence issueEvidence: issue.getEvidences()) { + CandidateEvidence evidence = new CandidateEvidence(issueEvidence, newCandidate, user); + newCandidate.getEvidences().add(evidence); } - // ADD author - if (candidateModelRequest.getAuthors() != null) { - for (AuthorModel authorModel : candidateModelRequest.getAuthors()) { - newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(authorModel.getUserId()), authorModel.getAuthorRole() + "_PATTERN_CANDIDATE_" + newCandidate.getId())); - UserEntity u = this.userService.getUserById(authorModel.getUserId()); - switch (authorModel.getAuthorRole()) { - case AuthorConstant.HELPER: - user.getRoles().add(helper); - this.userService.saveUser(u); - break; - case AuthorConstant.MAINTAINER: - user.getRoles().add(maintainer); - this.userService.saveUser(u); - break; - case AuthorConstant.OWNER: - if (null != u.getRoles()) { - u.getRoles().add(owner); - } else { - u.setRoles(new HashSet<>(Arrays.asList(owner))); - } - this.userService.saveUser(u); - break; - default: - throw new IllegalArgumentException("Invalid author role: " + authorModel.getAuthorRole()); - } + this.issueService.deleteIssue(candidateModelRequest.getIssueId()); + } + // ADD author + if (candidateModelRequest.getAuthors() != null) { + for (AuthorModel authorModel : candidateModelRequest.getAuthors()) { + newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(authorModel.getUserId()), authorModel.getAuthorRole() + "_PATTERN_CANDIDATE_" + newCandidate.getId())); + UserEntity u = this.userService.getUserById(authorModel.getUserId()); + switch (authorModel.getAuthorRole()) { + case AuthorConstant.HELPER: + user.getRoles().add(helper); + this.userService.saveUser(u); + break; + case AuthorConstant.MAINTAINER: + user.getRoles().add(maintainer); + this.userService.saveUser(u); + break; + case AuthorConstant.OWNER: + if (null != u.getRoles()) { + u.getRoles().add(owner); + } else { + u.setRoles(new HashSet<>(Arrays.asList(owner))); + } + this.userService.saveUser(u); + break; + default: + throw new IllegalArgumentException("Invalid author role: " + authorModel.getAuthorRole()); } - } else { - newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(userId), AuthorConstant.OWNER)); - user.getRoles().add(owner); } - - // ADD pattern language - if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) - newCandidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); - - return this.candidateRepository.save(newCandidate); } else { - throw new RuntimeException("You don't have the permission"); + newCandidate.getAuthors().add(new CandidateAuthor(newCandidate, this.userService.getUserById(userId), AuthorConstant.OWNER)); + user.getRoles().add(owner); } + + // ADD pattern language + if (candidateModelRequest.getPatternLanguageId() != null && this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId()) != null) + newCandidate.setPatternLanguage(this.patternLanguageService.getPatternLanguageById(candidateModelRequest.getPatternLanguageId())); + + return this.candidateRepository.save(newCandidate); } @Override From 8ff69f449381e35b9d58776bc01b8cafbdde527d Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Apr 2022 15:29:40 +0200 Subject: [PATCH 50/68] added function for changing platform wide roles for users --- .../api/entities/user/role/RoleConstant.java | 16 ++++++ .../api/rest/controller/UserController.java | 7 +++ .../api/rest/model/user/UserModel.java | 4 +- .../api/rest/model/user/UserModelRequest.java | 1 - .../patternatlas/api/service/UserService.java | 10 ++++ .../api/service/UserServiceImpl.java | 51 +++++++++++++------ 6 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java index aed35c3..2a3e959 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java @@ -1,5 +1,8 @@ package io.github.patternatlas.api.entities.user.role; +import java.util.Arrays; +import java.util.List; + public class RoleConstant { public static final String MEMBER = "MEMBER"; public static final String HELPER = "HELPER"; @@ -10,5 +13,18 @@ public class RoleConstant { public static final String ADMIN = "ADMIN"; public static final String DEVELOPER = "DEVELOPER"; + public static List PLATFORM_ROLES = Arrays.asList( + RoleConstant.ADMIN, + RoleConstant.MEMBER, + RoleConstant.EXPERT, + RoleConstant.LIBRARIAN + ); + + public static List AUTHOR_ROLES = Arrays.asList( + RoleConstant.HELPER, + RoleConstant.MAINTAINER, + RoleConstant.OWNER + ); + } diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 26ae8e0..57d2087 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -148,6 +148,13 @@ ResponseEntity> updateUser(@PathVariable UUID userId, @Re return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.updateUser(userId, userModelRequest)))); } + @Operation(operationId = "updatePlatformRole", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Update platform wide roles for user") + @PutMapping(value = "/{userId}/role") + @ResponseStatus(HttpStatus.ACCEPTED) + ResponseEntity> updatePlatformRole(@PathVariable UUID userId, @RequestBody UserModelRequest userModelRequest) { + return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.updatePlatformRole(userId, userModelRequest)))); + } + @PutMapping(value = "/roles/{roleId}/privileges/{privilegeId}") @ResponseStatus(HttpStatus.ACCEPTED) ResponseEntity> updateUserRole(@PathVariable UUID roleId, @PathVariable UUID privilegeId, @RequestBody RoleModelRequest roleModelRequest) { diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java index e2e0ac9..4290943 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModel.java @@ -22,7 +22,7 @@ public class UserModel { private UUID id; - private List roles; + private List roles; private String email; private String name; private List issues; @@ -40,7 +40,7 @@ public class UserModel { public UserModel(UserEntity user) { this.id = user.getId(); - this.roles = user.getRoles().stream().map(role -> role.getName()).collect(Collectors.toList()); + this.roles = user.getRoles().stream().map(role -> new RoleModel(role)).collect(Collectors.toList()); this.email = user.getEmail(); this.name = user.getName(); // ISSUE diff --git a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java index 330e408..6b5a643 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/user/UserModelRequest.java @@ -11,5 +11,4 @@ public class UserModelRequest extends UserModel { private String oldPassword; private String password; - private String role; } diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index c3cfdd5..1dbefa3 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -32,6 +32,16 @@ public interface UserService { "or (hasGlobalPermission(@PC.USER_DELETE) and #userId.equals(loggedInUUID()))") void deleteUser(UUID UserId); + /** + * Updates the platform wide roles for a given user (does not change other roles even when they are supplied + * in the request). + * @param userId + * @param userModelRequest + * @return + */ + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") + UserEntity updatePlatformRole(UUID userId, UserModelRequest userModelRequest); + /** * Checks if a user has one of the supplied privileges, without querying all * available roles and privileges diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 3450ad0..9163f7c 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -20,6 +20,7 @@ import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; @Service @Transactional @@ -62,21 +63,12 @@ public UserEntity createUser(UserModelRequest userModelRequest) { UserEntity user = new UserEntity(userModelRequest, passwordEncoder.encode(userModelRequest.getPassword())); if(userModelRequest.getRoles() != null) { userModelRequest.getRoles().stream().forEach(role -> { - if (this.roleRepository.findByName(role) != null) { - user.getRoles().add(this.roleRepository.findByName(role)); + if (this.roleRepository.findByName(role.getName()) != null) { + user.getRoles().add(this.roleRepository.findByName(role.getName())); } else { user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); } }); - } else { - // It could be that the UI only sends one singular role (not a set): - if(userModelRequest.getRole() != null) { - if (this.roleRepository.findByName(userModelRequest.getRole()) != null) { - user.getRoles().add(this.roleRepository.findByName(userModelRequest.getRole())); - } else { - user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); - } - } } @@ -102,14 +94,14 @@ public UserEntity updateUser(UUID userId, UserModelRequest userModelRequest) { if (userModelRequest == null) throw new RuntimeException("User to update is null!"); userModelRequest.getRoles().stream().forEach(role -> { - if (!this.roleRepository.existsByName(role)) + if (!this.roleRepository.existsByName(role.getName())) throw new ResourceNotFoundException(String.format("User Role %s not found!", role)); }); UserEntity user = this.getUserById(userId); userModelRequest.getRoles().stream().forEach(role -> { if (!user.getRoles().stream().map(r -> r.getName()).collect(Collectors.toList()).contains(role)) - user.getRoles().add(this.roleRepository.findByName(role)); + user.getRoles().add(this.roleRepository.findByName(role.getName())); }); if (userModelRequest.getOldPassword() != null || userModelRequest.getPassword() != null) { if (!passwordEncoder.matches(userModelRequest.getOldPassword(), user.getPassword()) && !user.getRoles().stream().map(role -> role.getName()).collect(Collectors.toList()).contains(RoleConstant.ADMIN)) @@ -128,6 +120,35 @@ public void deleteUser(UUID userId) { this.userRepository.deleteById(userId); } + @Override + public UserEntity updatePlatformRole(UUID userId, UserModelRequest userModelRequest) { + if (userModelRequest == null) + throw new RuntimeException("User to update is null!"); + + UserEntity user = this.getUserById(userId); + logger.warn("Request: {}", userModelRequest); + // Find new supplied platform wide role (should be only one) + if(userModelRequest.getRoles() != null) { + Optional requestedRole = + userModelRequest.getRoles().stream() + .filter(role -> RoleConstant.PLATFORM_ROLES.contains(role.getName())) + .findFirst(); + if(requestedRole.isPresent()) { + // Find old existing platform role + List existingRoles = user.getRoles().stream() + .filter(role -> RoleConstant.PLATFORM_ROLES.contains(role.getName())) + .collect(Collectors.toList()); + if(!existingRoles.isEmpty()) { + user.getRoles().removeAll(existingRoles); + user.getRoles().add(this.roleRepository.findByName(requestedRole.get().getName())); + user = this.saveUser(user); + } + } + } + + return user; + } + @Override public boolean hasAnyPrivilege(UUID userId, String... permissions) { for(String permission : permissions) { @@ -150,13 +171,13 @@ public List getAllRoles() { @Override @Transactional(readOnly = true) public List getAllPlatformRoles() { - return this.roleRepository.findAllRolesByNames(Arrays.asList("ADMIN", "MEMBER", "EXPERT", "LIBRARIAN")); + return this.roleRepository.findAllRolesByNames(RoleConstant.PLATFORM_ROLES); } @Override @Transactional(readOnly = true) public List getAllAuthorRoles() { - return this.roleRepository.findAllRolesByNames(Arrays.asList("HELPER", "MAINTAINER", "OWNER")); + return this.roleRepository.findAllRolesByNames(RoleConstant.AUTHOR_ROLES); } @Override From 7f25d8084ddf51dc9d2b6741f5caf6b461f60393 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Mon, 25 Apr 2022 11:49:22 +0200 Subject: [PATCH 51/68] add endpoint to get all default privileges --- .../api/repositories/PrivilegeRepository.java | 3 +++ .../patternatlas/api/rest/controller/UserController.java | 9 +++++++++ .../io/github/patternatlas/api/service/UserService.java | 1 + .../github/patternatlas/api/service/UserServiceImpl.java | 6 ++++++ 4 files changed, 19 insertions(+) diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java index 2a6b3ac..68eaeec 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java @@ -19,6 +19,9 @@ public interface PrivilegeRepository extends JpaRepository { @Query(value = "SELECT * FROM privilege p WHERE p.name like '%ALL' OR p.name like '%CREATE'", nativeQuery = true) public List findAllPlatformPrivileges(); + @Query(value = "SELECT * FROM privilege p WHERE (p.name LIKE 'ISSUE%' OR p.name LIKE 'PATTERN_CANDIDATE%' OR p.name LIKE 'APPROVED_PATTERN%') AND p.name NOT LIKE '%ALL' AND p.name NOT LIKE '%CREATE' AND p.name NOT LIKE '%\\_%-%'", nativeQuery = true) + public List findAllDefaultPrivileges(); + @Query(value = "SELECT * FROM privilege p WHERE p.name like %:entityId", nativeQuery = true) public List findAllFromEntity(@Param("entityId") UUID entityId); diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 57d2087..dacf352 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -119,6 +119,15 @@ CollectionModel> getAllPlatformPrivileges() { return CollectionModel.of(privileges); } + @GetMapping(value = "/roles/default_privileges") + CollectionModel> getAllDefaultPrivileges() { + List> privileges = this.userService.getAllDefaultPrivileges() + .stream() + .map(privilege -> EntityModel.of(new PrivilegeModel(privilege))) + .collect(Collectors.toList()); + return CollectionModel.of(privileges); + } + @GetMapping(value = "/roles/privileges/{entityId}") CollectionModel> getAllPrivilegesFromEntity(@PathVariable UUID entityId) { List> privileges = this.userService.getAllPrivilegesFromEntity(entityId) diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index 1dbefa3..17d5c84 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -57,6 +57,7 @@ public interface UserService { List getAllAuthorRoles(); List getAllRolesFromEntity(UUID entityId); List getAllPlatformPrivileges(); + List getAllDefaultPrivileges(); List getAllPrivilegesFromEntity(UUID entityId); @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 9163f7c..0a2c141 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -192,6 +192,12 @@ public List getAllPlatformPrivileges() { return this.privilegeRepository.findAllPlatformPrivileges(); } + @Override + @Transactional(readOnly = true) + public List getAllDefaultPrivileges() { + return this.privilegeRepository.findAllDefaultPrivileges(); + } + @Override @Transactional(readOnly = true) public List getAllPrivilegesFromEntity(UUID entityId) { From 294aafeebd7e23c67ee9beacf38095d50e439078 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Mon, 25 Apr 2022 14:32:01 +0200 Subject: [PATCH 52/68] improve endpoint naming --- .../api/repositories/PrivilegeRepository.java | 3 +-- .../api/rest/controller/UserController.java | 12 +++--------- .../github/patternatlas/api/service/UserService.java | 6 +----- .../patternatlas/api/service/UserServiceImpl.java | 7 ++----- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java index 68eaeec..81240fa 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java @@ -6,7 +6,6 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; import java.util.Optional; import java.util.UUID; @@ -20,7 +19,7 @@ public interface PrivilegeRepository extends JpaRepository { public List findAllPlatformPrivileges(); @Query(value = "SELECT * FROM privilege p WHERE (p.name LIKE 'ISSUE%' OR p.name LIKE 'PATTERN_CANDIDATE%' OR p.name LIKE 'APPROVED_PATTERN%') AND p.name NOT LIKE '%ALL' AND p.name NOT LIKE '%CREATE' AND p.name NOT LIKE '%\\_%-%'", nativeQuery = true) - public List findAllDefaultPrivileges(); + public List findAllDefaultAuthorPrivileges(); @Query(value = "SELECT * FROM privilege p WHERE p.name like %:entityId", nativeQuery = true) public List findAllFromEntity(@Param("entityId") UUID entityId); diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index dacf352..62246ca 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -1,9 +1,5 @@ package io.github.patternatlas.api.rest.controller; -import io.github.patternatlas.api.config.Authority; -import io.github.patternatlas.api.entities.user.UserEntity; -import io.github.patternatlas.api.entities.user.role.Privilege; -import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.rest.model.user.*; import io.github.patternatlas.api.service.UserService; @@ -11,7 +7,6 @@ import org.springframework.hateoas.EntityModel; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PostFilter; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -25,7 +20,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.security.Principal; import java.util.*; import java.util.stream.Collectors; @@ -119,9 +113,9 @@ CollectionModel> getAllPlatformPrivileges() { return CollectionModel.of(privileges); } - @GetMapping(value = "/roles/default_privileges") - CollectionModel> getAllDefaultPrivileges() { - List> privileges = this.userService.getAllDefaultPrivileges() + @GetMapping(value = "/roles/default_author_privileges") + CollectionModel> getAllDefaultAuthorPrivileges() { + List> privileges = this.userService.getAllDefaultAuthorPrivileges() .stream() .map(privilege -> EntityModel.of(new PrivilegeModel(privilege))) .collect(Collectors.toList()); diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index 17d5c84..773e03a 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -1,14 +1,10 @@ package io.github.patternatlas.api.service; -import io.github.patternatlas.api.entities.candidate.Candidate; import io.github.patternatlas.api.entities.user.role.Privilege; import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.entities.user.UserEntity; -import io.github.patternatlas.api.rest.model.user.RoleModel; import io.github.patternatlas.api.rest.model.user.RoleModelRequest; -import io.github.patternatlas.api.rest.model.user.UserModel; import io.github.patternatlas.api.rest.model.user.UserModelRequest; -import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import java.util.List; @@ -57,7 +53,7 @@ public interface UserService { List getAllAuthorRoles(); List getAllRolesFromEntity(UUID entityId); List getAllPlatformPrivileges(); - List getAllDefaultPrivileges(); + List getAllDefaultAuthorPrivileges(); List getAllPrivilegesFromEntity(UUID entityId); @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 0a2c141..d0fabc9 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -1,11 +1,9 @@ package io.github.patternatlas.api.service; -import io.github.patternatlas.api.entities.candidate.Candidate; import io.github.patternatlas.api.entities.user.role.RoleConstant; import io.github.patternatlas.api.entities.user.role.Privilege; import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.entities.user.UserEntity; -import io.github.patternatlas.api.exception.*; import io.github.patternatlas.api.repositories.PrivilegeRepository; import io.github.patternatlas.api.repositories.RoleRepository; import io.github.patternatlas.api.repositories.UserRepository; @@ -20,7 +18,6 @@ import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; @Service @Transactional @@ -194,8 +191,8 @@ public List getAllPlatformPrivileges() { @Override @Transactional(readOnly = true) - public List getAllDefaultPrivileges() { - return this.privilegeRepository.findAllDefaultPrivileges(); + public List getAllDefaultAuthorPrivileges() { + return this.privilegeRepository.findAllDefaultAuthorPrivileges(); } @Override From 075e9b38161fc2cb6887ab8cf7d23cd81079ba09 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Mon, 2 May 2022 10:20:39 +0200 Subject: [PATCH 53/68] add endpoint to update all resource specific roles this is used to add/remove a privilege to/from an author role for all resources --- .../api/entities/user/role/Role.java | 5 +++ .../api/repositories/PrivilegeRepository.java | 3 ++ .../api/repositories/RoleRepository.java | 6 ++- .../rest/controller/PatternController.java | 2 +- .../api/rest/controller/UserController.java | 18 +++++++++ .../api/service/CandidateServiceImpl.java | 6 +-- .../api/service/IssueServiceImpl.java | 3 +- .../patternatlas/api/service/RoleService.java | 2 +- .../api/service/RoleServiceImpl.java | 7 +--- .../patternatlas/api/service/UserService.java | 3 ++ .../api/service/UserServiceImpl.java | 40 +++++++++++++++++++ 11 files changed, 79 insertions(+), 16 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java index 5c886a4..35e1896 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java @@ -51,4 +51,9 @@ public void removePrivilege(Privilege privilege) { privilege.getRoles().remove(this); } + public void addPrivilege(Privilege privilege) { + this.privileges.add(privilege); + privilege.getRoles().add(this); + } + } diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java index 81240fa..7f633b8 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java @@ -24,6 +24,9 @@ public interface PrivilegeRepository extends JpaRepository { @Query(value = "SELECT * FROM privilege p WHERE p.name like %:entityId", nativeQuery = true) public List findAllFromEntity(@Param("entityId") UUID entityId); + @Query(value = "SELECT * FROM privilege p WHERE p.name like CONCAT(:defaultAuthorPrivilege, '_________-____-____-____-____________')", nativeQuery = true) + public List findAllResourceSpecific(@Param("defaultAuthorPrivilege") String defaultAuthorPrivilege); + @Modifying @Query(value = "DELETE FROM privilege p WHERE p.name like %:entityId", nativeQuery = true) public void deleteAllFromEntity(@Param("entityId") UUID entityId); diff --git a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java index 11370fc..058ef52 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java @@ -6,7 +6,6 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; import java.util.UUID; import java.util.List; @@ -23,7 +22,10 @@ public interface RoleRepository extends JpaRepository { public List findAllFromEntity(@Param("entityId") UUID entityId); @Query(value = "SELECT * from role r where r.name like %:entityId and r.name like :authorRole%", nativeQuery = true) - public List findAllFromEntityForAuthorType(@Param("entityId") UUID entityId, @Param("authorRole") String authorRole); + public List findAllFromEntityForAuthorRole(@Param("entityId") UUID entityId, @Param("authorRole") String authorRole); + + @Query(value = "SELECT * from role r where r.name like :authorRole%", nativeQuery = true) + public List findAllForAuthorRole(@Param("authorRole") String authorRole); @Modifying @Query(value = "DELETE FROM role r WHERE r.name like %:entityId", nativeQuery = true) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/PatternController.java b/src/main/java/io/github/patternatlas/api/rest/controller/PatternController.java index d9c9ef0..be01399 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/PatternController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/PatternController.java @@ -358,7 +358,7 @@ ResponseEntity removePatternFromView(@PathVariable UUID patternViewId, @PathV return ResponseEntity.noContent().build(); } - @Operation(operationId = "addPatternToPatternLanguage", responses = {@ApiResponse(responseCode = "201")}, description = "Delete pattern from pattern view") + @Operation(operationId = "addPatternToPatternLanguage", responses = {@ApiResponse(responseCode = "201")}, description = "Add pattern to pattern language") @PostMapping(value = "/patternLanguages/{patternLanguageId}/patterns") @CrossOrigin(exposedHeaders = "Location") @ResponseStatus(HttpStatus.CREATED) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 62246ca..2a9435b 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -164,6 +164,24 @@ ResponseEntity> updateUserRole(@PathVariable UUID roleId, return ResponseEntity.ok(EntityModel.of(new RoleModel(this.userService.updateRole(roleId, privilegeId, roleModelRequest)))); } + /** + * This endpoint updates all resource specific roles that are related to the specified author role (HELPER, MAINTAINER or OWNER) according to the value of the specified default author privilege. + * e.g. the role is 'HELPER', the default author privilege is 'PATTERN_CANDIDATE_EDIT' and the checkboxValue of roleModelRequest is false. This + * means the privilege 'PATTERN_CANDIDATE_EDIT' should be removed from all 'HELPER' roles from all resources. If a resources has + * the ID 123, privilege 'PATTERN_CANDIDATE_EDIT_123' will be removed from the role 'HELPER_PATTERN_CANDIDATE_123' + * + * @param authorRoleId + * @param defaultAuthorPrivilegeId + * @param roleModelRequest + * @return + */ + @Operation(description = "Update all resource specific roles according to the value of the specified default author privilege") + @PostMapping(value = "/roles/{authorRoleId}/privileges/{defaultAuthorPrivilegeId}/all_resource_specific") + @ResponseStatus(HttpStatus.ACCEPTED) + void updateAllResourceSpecificAuthorRoles(@PathVariable UUID authorRoleId, @PathVariable UUID defaultAuthorPrivilegeId, @RequestBody RoleModelRequest roleModelRequest) { + this.userService.updateAllResourceSpecificRoles(authorRoleId, defaultAuthorPrivilegeId, roleModelRequest); + } + /** * DELETE Methods */ diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index 357e5a6..86690ad 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -8,7 +8,6 @@ import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidence; import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidenceRating; import io.github.patternatlas.api.entities.issue.Issue; -import io.github.patternatlas.api.entities.issue.author.IssueAuthor; import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence; import io.github.patternatlas.api.entities.shared.AuthorConstant; import io.github.patternatlas.api.entities.user.UserEntity; @@ -19,12 +18,10 @@ import io.github.patternatlas.api.repositories.*; import io.github.patternatlas.api.rest.model.candidate.CandidateModelRequest; import io.github.patternatlas.api.rest.model.shared.*; -import io.github.patternatlas.api.util.RatingHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.rest.webmvc.ResourceNotFoundException; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,7 +29,6 @@ import javax.persistence.EntityNotFoundException; import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; @Service @Transactional @@ -283,7 +279,7 @@ public Candidate saveCandidateAuthor(UUID candidateId, AuthorModelRequest author candidateAuthor = this.candidateAuthorRepository.save(candidateAuthor); // Save roles associated with author - List authorRoles = this.roleService.findAllFromEntityForAuthorType(candidate.getId(), + List authorRoles = this.roleService.findAllFromEntityForAuthorRole(candidate.getId(), authorModelRequest.getAuthorRole()); user.getRoles().addAll(authorRoles); this.userService.saveUser(user); diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index c6797c4..d4ec4b1 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -23,7 +23,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.rest.webmvc.ResourceNotFoundException; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -197,7 +196,7 @@ public Issue saveIssueAuthor(UUID issueId, AuthorModelRequest authorModelRequest // Save roles associated with the author // Get requested role - List authorRoles = this.roleService.findAllFromEntityForAuthorType(issue.getId(), + List authorRoles = this.roleService.findAllFromEntityForAuthorRole(issue.getId(), authorModelRequest.getAuthorRole()); user.getRoles().addAll(authorRoles); this.userService.saveUser(user); diff --git a/src/main/java/io/github/patternatlas/api/service/RoleService.java b/src/main/java/io/github/patternatlas/api/service/RoleService.java index 7fccc07..716143a 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleService.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleService.java @@ -13,5 +13,5 @@ public interface RoleService { void deleteAllRolesByResourceId(UUID entityId); - List findAllFromEntityForAuthorType(UUID entityId, String authorRole); + List findAllFromEntityForAuthorRole(UUID entityId, String authorRole); } diff --git a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java index c95aed1..bbe6e50 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java @@ -6,12 +6,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import io.github.patternatlas.api.service.RoleService; - import java.util.List; import java.util.UUID; import java.util.Collection; @@ -52,7 +49,7 @@ public void deleteAllRolesByResourceId(UUID entityId) { } @Override - public List findAllFromEntityForAuthorType(UUID entityId, String authorRole) { - return this.roleRepository.findAllFromEntityForAuthorType(entityId, authorRole); + public List findAllFromEntityForAuthorRole(UUID entityId, String authorRole) { + return this.roleRepository.findAllFromEntityForAuthorRole(entityId, authorRole); } } diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index 773e03a..c9d356e 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -58,4 +58,7 @@ public interface UserService { @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") Role updateRole(UUID roleId, UUID privilegeId, RoleModelRequest roleModelRequest); + + @PreAuthorize(value = "hasGlobalPermission(@PC.USER_EDIT_ALL)") + void updateAllResourceSpecificRoles(UUID authorRoleId, UUID defaultAuthorPrivilegeId, RoleModelRequest roleModelRequest); } \ No newline at end of file diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index d0fabc9..be4d8fb 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -218,4 +218,44 @@ public Role updateRole(UUID roleId, UUID privilegeId, RoleModelRequest roleModel return this.roleRepository.save(role); } + + @Override + @Transactional + public void updateAllResourceSpecificRoles(UUID authorRoleId, UUID defaultAuthorPrivilegeId, RoleModelRequest roleModelRequest) { + Role authorRole = this.roleRepository.findById(authorRoleId).orElseThrow(() -> new ResourceNotFoundException(String.format("Role %s not found!", authorRoleId))); + Privilege defaultAuthorPrivilege = this.privilegeRepository.findById(defaultAuthorPrivilegeId).orElseThrow(() -> new ResourceNotFoundException(String.format("Privilege %s not found!", defaultAuthorPrivilegeId))); + List privileges = this.privilegeRepository.findAllResourceSpecific(defaultAuthorPrivilege.getName()); + + if (roleModelRequest.isCheckboxValue()) { + for (Privilege privilege : privileges) { + String privilegeName = privilege.getName(); + String uuidString = privilegeName.substring(privilegeName.length() - 36); + UUID resourceId = UUID.fromString(uuidString); + + List roles = this.roleRepository.findAllFromEntityForAuthorRole(resourceId, authorRole.getName()); + + if (roles.size() > 1) { + logger.warn(String.format("Found more than one role %s for resource ID %s", authorRole.getName(), resourceId)); + } + + if (roles.size() == 0) { + logger.warn(String.format("Could not find role %s for resource ID %s", authorRole.getName(), resourceId)); + } else { + roles.get(0).addPrivilege(privilege); + } + } + } else { + List authors = this.roleRepository.findAllForAuthorRole(authorRole.getName()); + + for (Role author : authors) { + Collection privilegesOfAuthor = author.getPrivileges(); + + for (Privilege privilege : privileges) { + if (privilegesOfAuthor.contains(privilege)) { + author.removePrivilege(privilege); + } + } + } + } + } } \ No newline at end of file From 224bfa956cf42baa78ab22fbb6677daf01b26250 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Mon, 2 May 2022 15:10:56 +0200 Subject: [PATCH 54/68] change http method to match the REST guidelines --- .../github/patternatlas/api/rest/controller/UserController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 2a9435b..8852f6e 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -176,7 +176,7 @@ ResponseEntity> updateUserRole(@PathVariable UUID roleId, * @return */ @Operation(description = "Update all resource specific roles according to the value of the specified default author privilege") - @PostMapping(value = "/roles/{authorRoleId}/privileges/{defaultAuthorPrivilegeId}/all_resource_specific") + @PutMapping(value = "/roles/{authorRoleId}/privileges/{defaultAuthorPrivilegeId}/all_resource_specific") @ResponseStatus(HttpStatus.ACCEPTED) void updateAllResourceSpecificAuthorRoles(@PathVariable UUID authorRoleId, @PathVariable UUID defaultAuthorPrivilegeId, @RequestBody RoleModelRequest roleModelRequest) { this.userService.updateAllResourceSpecificRoles(authorRoleId, defaultAuthorPrivilegeId, roleModelRequest); From 829182b31819bb0fc4cc209da2ceed4e2292a40f Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Thu, 5 May 2022 14:57:37 +0200 Subject: [PATCH 55/68] add missing permission checks --- .../patternatlas/api/entities/Pattern.java | 1 + .../api/entities/PatternView.java | 2 + .../entities/user/role/PrivilegeConstant.java | 8 +++ .../api/repositories/PrivilegeRepository.java | 2 +- .../api/service/PatternLanguageService.java | 55 +++++++++++-------- .../api/service/PatternViewService.java | 35 ++++++++++-- 6 files changed, 73 insertions(+), 30 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/Pattern.java b/src/main/java/io/github/patternatlas/api/entities/Pattern.java index 26f7072..9cad317 100644 --- a/src/main/java/io/github/patternatlas/api/entities/Pattern.java +++ b/src/main/java/io/github/patternatlas/api/entities/Pattern.java @@ -34,6 +34,7 @@ public class Pattern extends EntityWithURI { private PatternLanguage patternLanguage; @JsonIgnore + @ToString.Exclude @OneToMany(mappedBy = "pattern", cascade = CascadeType.ALL, orphanRemoval = true) private List patternViews = new ArrayList<>(); diff --git a/src/main/java/io/github/patternatlas/api/entities/PatternView.java b/src/main/java/io/github/patternatlas/api/entities/PatternView.java index 4b1bbbf..8b8f530 100644 --- a/src/main/java/io/github/patternatlas/api/entities/PatternView.java +++ b/src/main/java/io/github/patternatlas/api/entities/PatternView.java @@ -13,6 +13,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.ToString; @Entity @Data @@ -23,6 +24,7 @@ public class PatternView extends PatternGraph { private URL logo; @JsonIgnore + @ToString.Exclude @OneToMany(mappedBy = "patternView", cascade = CascadeType.ALL, orphanRemoval = true) private List patterns = new ArrayList<>(); diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java index 09946ce..cfec2a8 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java @@ -61,4 +61,12 @@ public class PrivilegeConstant { public static final String USER_EDIT_ALL = "USER_EDIT_ALL"; public static final String USER_DELETE_ALL = "USER_DELETE_ALL"; public static final String USER_ALL = "USER_ALL"; + /** Pattern View */ + public static final String PATTERN_VIEW_READ = "PATTERN_VIEW_READ"; + public static final String PATTERN_VIEW_EDIT = "PATTERN_VIEW_EDIT"; + public static final String PATTERN_VIEW_DELETE = "PATTERN_VIEW_DELETE"; + public static final String PATTERN_VIEW_CREATE = "PATTERN_VIEW_CREATE"; + public static final String PATTERN_VIEW_READ_ALL = "PATTERN_VIEW_READ_ALL"; + public static final String PATTERN_VIEW_EDIT_ALL = "PATTERN_VIEW_EDIT_ALL"; + public static final String PATTERN_VIEW_DELETE_ALL = "PATTERN_VIEW_DELETE_ALL"; } diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java index 7f633b8..fe14991 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java @@ -18,7 +18,7 @@ public interface PrivilegeRepository extends JpaRepository { @Query(value = "SELECT * FROM privilege p WHERE p.name like '%ALL' OR p.name like '%CREATE'", nativeQuery = true) public List findAllPlatformPrivileges(); - @Query(value = "SELECT * FROM privilege p WHERE (p.name LIKE 'ISSUE%' OR p.name LIKE 'PATTERN_CANDIDATE%' OR p.name LIKE 'APPROVED_PATTERN%') AND p.name NOT LIKE '%ALL' AND p.name NOT LIKE '%CREATE' AND p.name NOT LIKE '%\\_%-%'", nativeQuery = true) + @Query(value = "SELECT * FROM privilege p WHERE (p.name LIKE 'ISSUE%' OR p.name LIKE 'PATTERN_CANDIDATE%' OR p.name LIKE 'APPROVED_PATTERN%' OR p.name LIKE 'PATTERN_VIEW%') AND p.name NOT LIKE '%ALL' AND p.name NOT LIKE '%CREATE' AND p.name NOT LIKE '%\\_%-%'", nativeQuery = true) public List findAllDefaultAuthorPrivileges(); @Query(value = "SELECT * FROM privilege p WHERE p.name like %:entityId", nativeQuery = true) diff --git a/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java b/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java index c666fee..a7b5a12 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java @@ -3,7 +3,9 @@ import java.util.List; import java.util.UUID; -import org.springframework.transaction.annotation.Transactional; +import org.springframework.security.access.prepost.PostAuthorize; +import org.springframework.security.access.prepost.PostFilter; +import org.springframework.security.access.prepost.PreAuthorize; import io.github.patternatlas.api.entities.DirectedEdge; import io.github.patternatlas.api.entities.Pattern; @@ -16,80 +18,85 @@ public interface PatternLanguageService { - @Transactional + @PreAuthorize(value = "hasGlobalPermission(@PC.PATTERN_LANGUAGE_CREATE)") PatternLanguage createPatternLanguage(PatternLanguage patternLanguage); - @Transactional(readOnly = true) + @PostFilter("hasResourcePermission(filterObject.id, @PC.PATTERN_LANGUAGE_READ)") List getPatternLanguages(); - @Transactional(readOnly = true) + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") PatternLanguage getPatternLanguageById(UUID patternLanguageId); - @Transactional(readOnly = true) + @PostAuthorize(value = "hasResourcePermission(returnObject.id, @PC.PATTERN_LANGUAGE_READ)") PatternLanguage getPatternLanguageByUri(String uri); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguage.id, @PC.PATTERN_LANGUAGE_EDIT)") PatternLanguage updatePatternLanguage(PatternLanguage patternLanguage); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_DELETE)") void deletePatternLanguage(UUID patternLanguageId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") Pattern createPatternAndAddToPatternLanguage(UUID patternLanguageId, Pattern pattern); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") + @PostFilter("hasResourcePermission(filterObject.id, @PC.APPROVED_PATTERN_READ)") List getPatternsOfPatternLanguage(UUID patternLanguageId); - @Transactional(readOnly = true) + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ) && hasResourcePermission(#patternId, @PC.APPROVED_PATTERN_READ)") Pattern getPatternOfPatternLanguageById(UUID patternLanguageId, UUID patternId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") void deletePatternOfPatternLanguage(UUID patternLanguageId, UUID patternId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") PatternSchema createPatternSchemaAndAddToPatternLanguage(UUID patternLanguageId, PatternSchema patternSchema); - @Transactional(readOnly = true) + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") PatternSchema getPatternSchemaByPatternLanguageId(UUID patternLanguageId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") PatternSchema updatePatternSchemaOfPatternLanguage(UUID patternLanguageId, PatternSchema patternSchema); - @Transactional(readOnly = true) + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") Object getGraphOfPatternLanguage(UUID patternLanguageId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") Object createGraphOfPatternLanguage(UUID patternLanguageId, Object graph); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") Object updateGraphOfPatternLanguage(UUID patternLanguageId, Object graph); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") void deleteGraphOfPatternLanguage(UUID patternLanguageId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") DirectedEdge createDirectedEdgeAndAddToPatternLanguage(UUID patternLanguageId, CreateDirectedEdgeRequest createDirectedEdgeRequest); + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") List getDirectedEdgesOfPatternLanguage(UUID patternLanguageId); + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") DirectedEdge getDirectedEdgeOfPatternLanguageById(UUID patternLanguageId, UUID directedEdgeId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") DirectedEdge updateDirectedEdgeOfPatternLanguage(UUID patternLanguageId, DirectedEdge directedEdge); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") void removeDirectedEdgeFromPatternLanguage(UUID patternLanguageId, UUID directedEdgeId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") UndirectedEdge createUndirectedEdgeAndAddToPatternLanguage(UUID patternLanguageId, CreateUndirectedEdgeRequest createUndirectedEdgeRequest); - @Transactional(readOnly = true) + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") List getUndirectedEdgesOfPatternLanguage(UUID patternLanguageId); + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") UndirectedEdge getUndirectedEdgeOfPatternLanguageById(UUID patternLanguageId, UUID undirectedEdgeId) throws UndirectedEdgeNotFoundException; + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") UndirectedEdge updateUndirectedEdgeOfPatternLanguage(UUID patternLanguageId, UndirectedEdge undirectedEdge); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") void removeUndirectedEdgeFromPatternLanguage(UUID patternLanguageId, UUID undirectedEdgeId); } diff --git a/src/main/java/io/github/patternatlas/api/service/PatternViewService.java b/src/main/java/io/github/patternatlas/api/service/PatternViewService.java index 8804cf8..f42586c 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternViewService.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternViewService.java @@ -3,7 +3,9 @@ import java.util.List; import java.util.UUID; -import org.springframework.transaction.annotation.Transactional; +import org.springframework.security.access.prepost.PostAuthorize; +import org.springframework.security.access.prepost.PostFilter; +import org.springframework.security.access.prepost.PreAuthorize; import io.github.patternatlas.api.entities.DirectedEdge; import io.github.patternatlas.api.entities.Pattern; @@ -16,59 +18,82 @@ public interface PatternViewService { + @PreAuthorize(value = "hasGlobalPermission(@PC.PATTERN_VIEW_CREATE)") PatternView createPatternView(PatternView patternView); + @PostFilter("hasResourcePermission(filterObject.id, @PC.PATTERN_VIEW_READ)") List getAllPatternViews(); + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_VIEW_READ)") PatternView getPatternViewById(UUID patternViewId); + @PostAuthorize(value = "hasResourcePermission(returnObject.id, @PC.PATTERN_VIEW_READ)") PatternView getPatternViewByUri(String uri); + @PreAuthorize(value = "hasResourcePermission(#patternView.id, @PC.PATTERN_VIEW_EDIT)") PatternView updatePatternView(PatternView patternView); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_DELETE)") void deletePatternView(UUID patternViewId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") void addPatternToPatternView(UUID patternViewId, UUID patternId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ)") + @PostFilter("hasResourcePermission(filterObject.id, @PC.APPROVED_PATTERN_READ)") List getPatternsOfPatternView(UUID patternViewId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ) && hasResourcePermission(#patternId, @PC.APPROVED_PATTERN_READ)") Pattern getPatternOfPatternViewById(UUID patternViewId, UUID patternId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") void removePatternFromPatternView(UUID patternViewId, UUID patternId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") void addDirectedEdgeToPatternView(UUID patternViewId, UUID directedEdgeId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") DirectedEdge createDirectedEdgeAndAddToPatternView(UUID patternViewId, AddDirectedEdgeToViewRequest request); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ)") List getDirectedEdgesByPatternViewId(UUID patternViewId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ)") DirectedEdge getDirectedEdgeOfPatternViewById(UUID patternViewId, UUID directedEdgeId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") DirectedEdge updateDirectedEdgeOfPatternView(UUID patternViewId, UpdateDirectedEdgeRequest request); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") void removeDirectedEdgeFromPatternView(UUID patternViewId, UUID directedEdgeId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") void addUndirectedEdgeToPatternView(UUID patternViewId, UUID undirectedEdgeId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") UndirectedEdge createUndirectedEdgeAndAddToPatternView(UUID patternViewId, AddUndirectedEdgeToViewRequest request); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ)") List getUndirectedEdgesByPatternViewId(UUID patternViewId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ)") UndirectedEdge getUndirectedEdgeOfPatternViewById(UUID patternViewId, UUID undirectedEdgeId); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") UndirectedEdge updateUndirectedEdgeOfPatternView(UUID patternViewId, UpdateUndirectedEdgeRequest request); + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") void removeUndirectedEdgeFromPatternView(UUID patternViewId, UUID undirectedEdgeId); - @Transactional(readOnly = true) + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ)") Object getGraphOfPatternView(UUID patternLanguageId); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") Object createGraphOfPatternView(UUID patternLanguageId, Object graph); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") Object updateGraphOfPatternView(UUID patternLanguageId, Object graph); - @Transactional + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") void deleteGraphOfPatternView(UUID patternLanguageId); } From 9b01014df14bd31cff045fb3f5c87de02f3db955 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Fri, 6 May 2022 11:21:38 +0200 Subject: [PATCH 56/68] add guest role to specify what a user can do who is not logged in --- .../api/entities/user/role/RoleConstant.java | 4 +- .../api/repositories/RoleRepository.java | 13 ++++ ...sourceMethodSecurityExpressionHandler.java | 6 +- .../ResourceSecurityExpressionRoot.java | 62 ++++++++++++++----- .../patternatlas/api/service/RoleService.java | 9 +++ .../api/service/RoleServiceImpl.java | 10 +++ 6 files changed, 86 insertions(+), 18 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java index 2a3e959..37400e6 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java @@ -12,12 +12,14 @@ public class RoleConstant { public static final String LIBRARIAN = "LIBRARIAN"; public static final String ADMIN = "ADMIN"; public static final String DEVELOPER = "DEVELOPER"; + public static final String GUEST = "GUEST"; public static List PLATFORM_ROLES = Arrays.asList( RoleConstant.ADMIN, RoleConstant.MEMBER, RoleConstant.EXPERT, - RoleConstant.LIBRARIAN + RoleConstant.LIBRARIAN, + RoleConstant.GUEST ); public static List AUTHOR_ROLES = Arrays.asList( diff --git a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java index 058ef52..e16d901 100644 --- a/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java +++ b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java @@ -31,4 +31,17 @@ public interface RoleRepository extends JpaRepository { @Query(value = "DELETE FROM role r WHERE r.name like %:entityId", nativeQuery = true) public void deleteAllFromEntity(@Param("entityId") UUID entityId); + @Query(value = "" + + "SELECT CASE\n" + + " WHEN count(r.name) > 0\n" + + " THEN true\n" + + " ELSE false\n" + + "END\n" + + "FROM role r\n" + + "JOIN role_privileges rp on r.id = rp.roles_id\n" + + "JOIN privilege p on rp.privileges_id = p.id\n" + + "WHERE r.id = :roleId\n" + + "AND p.name = :privilegeName", + nativeQuery = true) + public boolean existsPrivilegeForRole(@Param("privilegeName") String privilegeName, @Param("roleId") UUID roleId); } diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java index 1ef7f42..4fec967 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java @@ -1,5 +1,7 @@ package io.github.patternatlas.api.security; +import io.github.patternatlas.api.repositories.RoleRepository; +import io.github.patternatlas.api.service.RoleService; import io.github.patternatlas.api.service.UserService; import org.aopalliance.intercept.MethodInvocation; import org.springframework.context.ApplicationContext; @@ -44,7 +46,9 @@ protected MethodSecurityExpressionOperations createSecurityExpressionRoot( Authentication authentication, MethodInvocation invocation) { ResourceSecurityExpressionRoot root = new ResourceSecurityExpressionRoot( authentication, - this.applicationContext.getBean(UserService.class)); + this.applicationContext.getBean(UserService.class), + this.applicationContext.getBean(RoleService.class), + this.applicationContext.getBean(RoleRepository.class)); root.setPermissionEvaluator(getPermissionEvaluator()); root.setTrustResolver(this.trustResolver); diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java index 0124c08..7588135 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java @@ -1,11 +1,15 @@ package io.github.patternatlas.api.security; +import io.github.patternatlas.api.entities.user.role.RoleConstant; +import io.github.patternatlas.api.repositories.RoleRepository; +import io.github.patternatlas.api.service.RoleService; import io.github.patternatlas.api.service.UserService; import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.core.Authentication; +import java.util.Optional; import java.util.UUID; public class ResourceSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations { @@ -13,11 +17,17 @@ public class ResourceSecurityExpressionRoot extends SecurityExpressionRoot imple private Object filterObject; private Object returnObject; private UserService userService; + private RoleService roleService; + private RoleRepository roleRepository; public ResourceSecurityExpressionRoot(Authentication authentication, - UserService userService) { + UserService userService, + RoleService roleService, + RoleRepository roleRepository) { super(authentication); this.userService = userService; + this.roleService = roleService; + this.roleRepository = roleRepository; } /** @@ -27,18 +37,30 @@ public ResourceSecurityExpressionRoot(Authentication authentication, * @return true if user has permission */ public boolean hasGlobalPermission(String permissionType) { - UUID userId = UUID.fromString(this.getAuthentication().getName()); // Supplied through JWT id field - - return this.userService.hasAnyPrivilege( - userId, - permissionType); + Optional userId = loggedInUUID(); + + if (userId.isPresent()) { + return this.userService.hasAnyPrivilege( + userId.get(), + permissionType); + } else { + return this.roleService.hasAnyPrivilege( + roleRepository.findByName(RoleConstant.GUEST).getId(), + permissionType + ); + } } - public UUID loggedInUUID() { - if(this.getAuthentication() != null) { - return UUID.fromString(this.getAuthentication().getName()); + public Optional loggedInUUID() { + if (this.getAuthentication() == null) { + return Optional.empty(); + } + + try { + return Optional.of(UUID.fromString(this.getAuthentication().getName())); // Supplied through JWT id field + } catch (IllegalArgumentException exception) { + return Optional.empty(); } - return null; } /** @@ -50,12 +72,20 @@ public UUID loggedInUUID() { * @return true if user has permission */ public boolean hasResourcePermission(UUID resource, String permissionType) { - UUID userId = UUID.fromString(this.getAuthentication().getName()); // Supplied through JWT id field - - return this.userService.hasAnyPrivilege( - userId, - permissionType + "_ALL", - permissionType + "_" + resource.toString()); + Optional userId = loggedInUUID(); + + if (userId.isPresent()) { + return this.userService.hasAnyPrivilege( + userId.get(), + permissionType + "_ALL", + permissionType + "_" + resource.toString()); + } else { + return this.roleService.hasAnyPrivilege( + roleRepository.findByName(RoleConstant.GUEST).getId(), + permissionType + "_ALL", + permissionType + "_" + resource.toString() + ); + } } public void setUserService(UserService userService) { diff --git a/src/main/java/io/github/patternatlas/api/service/RoleService.java b/src/main/java/io/github/patternatlas/api/service/RoleService.java index 716143a..243405a 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleService.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleService.java @@ -14,4 +14,13 @@ public interface RoleService { void deleteAllRolesByResourceId(UUID entityId); List findAllFromEntityForAuthorRole(UUID entityId, String authorRole); + + /** + * Checks if a user has one of the supplied privileges, without querying all + * available roles and privileges + * @param roleId + * @param privileges + * @return true if one of the privileges is present for the user + */ + boolean hasAnyPrivilege(UUID roleId, String ... privileges); } diff --git a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java index bbe6e50..c7d03bc 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java @@ -52,4 +52,14 @@ public void deleteAllRolesByResourceId(UUID entityId) { public List findAllFromEntityForAuthorRole(UUID entityId, String authorRole) { return this.roleRepository.findAllFromEntityForAuthorRole(entityId, authorRole); } + + @Override + public boolean hasAnyPrivilege(UUID roleId, String... privileges) { + for (String permission : privileges) { + if (this.roleRepository.existsPrivilegeForRole(permission, roleId)) { + return true; + } + } + return false; + } } From 1acd58184c9e4a237e3728a810fa84c0dc8d231c Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Mon, 9 May 2022 11:15:06 +0200 Subject: [PATCH 57/68] disable design model endpoints, because they are currently not used and don't check for privileges --- .../patternatlas/api/rest/controller/DesignModelController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/DesignModelController.java b/src/main/java/io/github/patternatlas/api/rest/controller/DesignModelController.java index fa2af05..00de902 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/DesignModelController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/DesignModelController.java @@ -18,6 +18,7 @@ import java.util.stream.Collectors; import org.apache.commons.text.CaseUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.Link; @@ -53,6 +54,7 @@ import lombok.extern.apachecommons.CommonsLog; @RestController +@ConditionalOnExpression(value = "false") // TODO: set to true if the design models should be used again @CommonsLog @CrossOrigin(allowedHeaders = "*", origins = "*") @RequestMapping(value = "/design-models", produces = "application/hal+json") From bfda094c60fc4c490ce6372e3f8d406e2032c779 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Mon, 9 May 2022 12:17:00 +0200 Subject: [PATCH 58/68] disable discussions endpoints, because they are currently not used and don't check for privileges --- .../patternatlas/api/rest/controller/DiscussionController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/DiscussionController.java b/src/main/java/io/github/patternatlas/api/rest/controller/DiscussionController.java index cee9818..b74f341 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/DiscussionController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/DiscussionController.java @@ -4,6 +4,7 @@ import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; @@ -22,6 +23,7 @@ import io.github.patternatlas.api.service.DiscussionService; @RestController +@ConditionalOnExpression(value = "false") // TODO: check if discussions can be removed completely @CrossOrigin(allowedHeaders = "*", origins = "*") public class DiscussionController { From 9474446ee16cf7f9d35500db91c8600e59c8a209 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Mon, 9 May 2022 12:26:24 +0200 Subject: [PATCH 59/68] disable image endpoints, because they are currently not used and don't check for privileges --- .../patternatlas/api/rest/controller/ImageController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/ImageController.java b/src/main/java/io/github/patternatlas/api/rest/controller/ImageController.java index 4499e31..f44fb6f 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/ImageController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/ImageController.java @@ -3,6 +3,7 @@ import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; @@ -19,6 +20,7 @@ import io.github.patternatlas.api.service.ImageService; @RestController +@ConditionalOnExpression(value = "false") // TODO: check if the ImageController can be removed entirely @CrossOrigin(allowedHeaders = "*", origins = "*") public class ImageController { From 696959999e9bffd41d2b5c0a5cabaf2c86a1d005 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Tue, 10 May 2022 16:30:39 +0200 Subject: [PATCH 60/68] fix error when deleting pattern from pattern language --- .../patternatlas/api/service/PatternLanguageServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java index 425c2a6..88dd4f5 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java @@ -232,7 +232,7 @@ public void deletePatternOfPatternLanguage(UUID patternLanguageId, UUID patternI } // 2. Remove Pattern from Views it is included - pattern.setPatternViews(null); + pattern.getPatternViews().clear(); pattern = this.patternService.updatePattern(pattern); // 3. Remove pattern From 55a5b4d75bb790a1d8e13e01d30eb4ab05a529a3 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 10 May 2022 16:50:55 +0200 Subject: [PATCH 61/68] added initial user creation for users created in keycloak --- .../api/config/ResourceServerConfig.java | 9 +++ .../api/entities/user/UserEntity.java | 8 ++- ...sourceMethodSecurityExpressionHandler.java | 4 +- .../ResourceSecurityExpressionRoot.java | 60 ++++++++++++++++++- .../api/service/UserAuthService.java | 17 ++++++ .../api/service/UserServiceImpl.java | 21 ++++++- .../api/util/UserIdGenerator.java | 18 ++++++ src/main/resources/application.properties | 5 +- 8 files changed, 133 insertions(+), 9 deletions(-) create mode 100644 src/main/java/io/github/patternatlas/api/service/UserAuthService.java create mode 100644 src/main/java/io/github/patternatlas/api/util/UserIdGenerator.java diff --git a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java index 01045a1..f439b06 100644 --- a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java +++ b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java @@ -1,5 +1,6 @@ package io.github.patternatlas.api.config; +import org.springframework.boot.autoconfigure.security.oauth2.resource.JwtAccessTokenConverterConfigurer; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -12,10 +13,17 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.DefaultTokenServices; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; +import java.util.Map; + @Configuration @EnableResourceServer class ResourceServerConfig extends ResourceServerConfigurerAdapter { @@ -66,4 +74,5 @@ public FilterRegistrationBean customCorsFilter() { bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; } + } diff --git a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java index 8558c81..d180d7a 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java @@ -4,6 +4,7 @@ import java.util.*; import javax.persistence.*; +import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.NaturalId; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; @@ -35,7 +36,8 @@ public class UserEntity implements Serializable{ * User fields */ @Id - @GeneratedValue(generator = "pg-uuid") + @GenericGenerator(name = "UserIdGenerator", strategy = "io.github.patternatlas.api.util.UserIdGenerator") + @GeneratedValue(generator = "UserIdGenerator") private UUID id; @JsonIgnore @@ -48,8 +50,8 @@ public class UserEntity implements Serializable{ )*/ private Set roles; - @NaturalId(mutable = true) - @Column(nullable = false, unique = true) + //@NaturalId(mutable = true) + @Column(nullable = false, unique = false) private String email; @NaturalId(mutable = true) diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java index 4fec967..c891e6f 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceMethodSecurityExpressionHandler.java @@ -2,6 +2,7 @@ import io.github.patternatlas.api.repositories.RoleRepository; import io.github.patternatlas.api.service.RoleService; +import io.github.patternatlas.api.service.UserAuthService; import io.github.patternatlas.api.service.UserService; import org.aopalliance.intercept.MethodInvocation; import org.springframework.context.ApplicationContext; @@ -48,7 +49,8 @@ protected MethodSecurityExpressionOperations createSecurityExpressionRoot( authentication, this.applicationContext.getBean(UserService.class), this.applicationContext.getBean(RoleService.class), - this.applicationContext.getBean(RoleRepository.class)); + this.applicationContext.getBean(RoleRepository.class), + this.applicationContext.getBean(UserAuthService.class)); root.setPermissionEvaluator(getPermissionEvaluator()); root.setTrustResolver(this.trustResolver); diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java index 7588135..50a371f 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java @@ -1,14 +1,30 @@ package io.github.patternatlas.api.security; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.patternatlas.api.entities.user.UserEntity; +import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.entities.user.role.RoleConstant; +import io.github.patternatlas.api.exception.UserNotFoundException; import io.github.patternatlas.api.repositories.RoleRepository; +import io.github.patternatlas.api.rest.model.user.RoleModel; +import io.github.patternatlas.api.rest.model.user.UserModelRequest; import io.github.patternatlas.api.service.RoleService; +import io.github.patternatlas.api.service.UserAuthService; import io.github.patternatlas.api.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.core.Authentication; - +import org.springframework.security.jwt.Jwt; +import org.springframework.security.jwt.JwtHelper; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; +import org.springframework.security.oauth2.provider.token.TokenStore; + +import java.util.Arrays; +import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -16,6 +32,7 @@ public class ResourceSecurityExpressionRoot extends SecurityExpressionRoot imple private Object filterObject; private Object returnObject; + private UserAuthService userAuthService; private UserService userService; private RoleService roleService; private RoleRepository roleRepository; @@ -23,11 +40,13 @@ public class ResourceSecurityExpressionRoot extends SecurityExpressionRoot imple public ResourceSecurityExpressionRoot(Authentication authentication, UserService userService, RoleService roleService, - RoleRepository roleRepository) { + RoleRepository roleRepository, + UserAuthService userAuthService) { super(authentication); this.userService = userService; this.roleService = roleService; this.roleRepository = roleRepository; + this.userAuthService = userAuthService; } /** @@ -51,13 +70,44 @@ public boolean hasGlobalPermission(String permissionType) { } } + private void createUser(UUID userId, Authentication authentication) { + OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) this.getAuthentication().getDetails(); + Jwt jwt = JwtHelper.decode(details.getTokenValue()); + System.out.println("Token: " + jwt.toString()); + System.out.println(jwt.getClaims()); + ObjectMapper objectMapper = new ObjectMapper(); + try { + Map claims = objectMapper.readValue(jwt.getClaims(), Map.class); + String preferredUsername = claims.get("preferred_username").toString(); + UserModelRequest req = new UserModelRequest(); + req.setId(userId); + req.setName(preferredUsername); + + System.out.println("Creating: " + req.toString()); + + UserEntity ent = this.userAuthService.createIntialMember(req); + System.out.println("Created: " + ent.toString()); + System.out.println("Created user id: " + ent.getId()); + } catch (JsonProcessingException e) { + throw new UserNotFoundException("Cannot infer preferred username from Token"); + } + } + public Optional loggedInUUID() { + + if (this.getAuthentication() == null) { return Optional.empty(); } try { - return Optional.of(UUID.fromString(this.getAuthentication().getName())); // Supplied through JWT id field + // Check if user exists in patternatlas + UUID userId = UUID.fromString(this.getAuthentication().getName()); // Supplied through JWT id field + if(!this.userAuthService.userExists(userId)) { + // The user is properly authenticated but is not yet created in patternatlas db + createUser(userId, this.getAuthentication()); + } + return Optional.of(userId); } catch (IllegalArgumentException exception) { return Optional.empty(); } @@ -88,6 +138,10 @@ public boolean hasResourcePermission(UUID resource, String permissionType) { } } + public void setUserAuthService(UserAuthService userAuthService) { + this.userAuthService = userAuthService; + } + public void setUserService(UserService userService) { this.userService = userService; } diff --git a/src/main/java/io/github/patternatlas/api/service/UserAuthService.java b/src/main/java/io/github/patternatlas/api/service/UserAuthService.java new file mode 100644 index 0000000..b2407b5 --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/service/UserAuthService.java @@ -0,0 +1,17 @@ +package io.github.patternatlas.api.service; + +import io.github.patternatlas.api.entities.user.UserEntity; +import io.github.patternatlas.api.rest.model.user.UserModelRequest; + +import java.util.UUID; + +/** + * Service for manipulating users based on incomping JW-Tokens. + * Not to be used for REST-Access. + * Used to query user information to handle authentication. + */ +public interface UserAuthService { + UserEntity createIntialMember(UserModelRequest userModelRequest); + + boolean userExists(UUID userId); +} diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index be4d8fb..c036699 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -21,7 +21,7 @@ @Service @Transactional -public class UserServiceImpl implements UserService { +public class UserServiceImpl implements UserService, UserAuthService { private UserRepository userRepository; private RoleRepository roleRepository; @@ -85,6 +85,25 @@ public UserEntity getUserById(UUID userId) { .orElseThrow(() -> new ResourceNotFoundException(String.format("User with ID %s not found!", userId))); } + @Override + public UserEntity createIntialMember(UserModelRequest userModelRequest) { + RoleModel memberModel = new RoleModel(); + memberModel.setName(RoleConstant.MEMBER); + userModelRequest.setRoles(Arrays.asList(memberModel)); + userModelRequest.setPassword(""); // Dummy password since authentication is not performed here + userModelRequest.setEmail(""); + + UserEntity user = new UserEntity(userModelRequest, ""); + user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); + + return this.userRepository.save(user); + } + + @Override + public boolean userExists(UUID userId) { + return this.userRepository.findById(userId).isPresent(); + } + @Override @Transactional public UserEntity updateUser(UUID userId, UserModelRequest userModelRequest) { diff --git a/src/main/java/io/github/patternatlas/api/util/UserIdGenerator.java b/src/main/java/io/github/patternatlas/api/util/UserIdGenerator.java new file mode 100644 index 0000000..68705ab --- /dev/null +++ b/src/main/java/io/github/patternatlas/api/util/UserIdGenerator.java @@ -0,0 +1,18 @@ +package io.github.patternatlas.api.util; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.id.UUIDGenerator; + +import java.io.Serializable; + +public class UserIdGenerator extends UUIDGenerator { + @Override + public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException { + Serializable id = session.getEntityPersister(null, object).getClassMetadata().getIdentifier(object, session); + if(id == null) { + id = super.generate(session, object); + } + return id; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2beae1f..39e6f97 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,7 +9,10 @@ logging.level.io.github.patternatlas.api=debug spring.datasource.initialization-mode=always spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true springdoc.default-produces-media-type=application/hal+json -security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json +# alt: AUTH-Server +# security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json +# neu: Keycloak +security.oauth2.resource.jwk.key-set-uri=http://localhost:8080/realms/dev/protocol/openid-connect/certs #okta.oauth2.issuer=https://dev-918271.okta.com/oauth2/default #okta.oauth2.clientId=0oa1eflyl1wZDVLLg357 #---------------------------- From 0d295d3bf791076c09ee88ea6585601c70a16719 Mon Sep 17 00:00:00 2001 From: Philipp Wundrack Date: Tue, 10 May 2022 17:17:10 +0200 Subject: [PATCH 62/68] add missing permission checks, fix some existing permission checks, fix some bugs that caused exceptions --- .../github/patternatlas/api/entities/PatternView.java | 2 ++ .../patternatlas/api/service/CandidateService.java | 6 +++--- .../github/patternatlas/api/service/IssueService.java | 4 ++-- .../api/service/PatternLanguageService.java | 4 ++-- .../api/service/PatternLanguageServiceImpl.java | 2 +- .../patternatlas/api/service/PatternSchemaService.java | 8 +++++++- .../api/service/PatternSchemaServiceImpl.java | 4 ++-- .../patternatlas/api/service/PatternService.java | 7 +++++++ .../patternatlas/api/service/PatternViewService.java | 10 +++++----- .../github/patternatlas/api/service/UserService.java | 2 +- 10 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/PatternView.java b/src/main/java/io/github/patternatlas/api/entities/PatternView.java index 8b8f530..85c8cf6 100644 --- a/src/main/java/io/github/patternatlas/api/entities/PatternView.java +++ b/src/main/java/io/github/patternatlas/api/entities/PatternView.java @@ -29,10 +29,12 @@ public class PatternView extends PatternGraph { private List patterns = new ArrayList<>(); @JsonIgnore + @ToString.Exclude @OneToMany(mappedBy = "patternView", cascade = CascadeType.ALL, orphanRemoval = true) private List directedEdges; @JsonIgnore + @ToString.Exclude @OneToMany(mappedBy = "patternView", cascade = CascadeType.ALL, orphanRemoval = true) private List undirectedEdges; diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateService.java b/src/main/java/io/github/patternatlas/api/service/CandidateService.java index 7fe98db..e15761f 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateService.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateService.java @@ -55,7 +55,7 @@ public interface CandidateService { @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_COMMENT)") Candidate createComment(UUID candidateId, UUID userId, CommentModel commentModel); - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_READ)") + @PostAuthorize(value = "hasResourcePermission(returnObject.candidate.id, @PC.PATTERN_CANDIDATE_READ)") CandidateComment getCommentById(UUID candidateCommentId); @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") @@ -71,10 +71,10 @@ public interface CandidateService { @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EVIDENCE)") Candidate createEvidence(UUID candidateId, UUID userId, EvidenceModel evidenceModel); - @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_READ)") + @PostAuthorize(value = "hasResourcePermission(returnObject.candidate.id, @PC.PATTERN_CANDIDATE_READ)") CandidateEvidence getEvidenceById(UUID evidenceId); - @PreAuthorize(value = "hasResourcePermission(#candiateId, @PC.PATTERN_CANDIDATE_EDIT)") + @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_EDIT)") Candidate updateEvidence(UUID candidateId, UUID evidenceId, UUID userId, EvidenceModel evidenceModel); @PreAuthorize(value = "hasResourcePermission(#candidateId, @PC.PATTERN_CANDIDATE_VOTE)") diff --git a/src/main/java/io/github/patternatlas/api/service/IssueService.java b/src/main/java/io/github/patternatlas/api/service/IssueService.java index cc3709e..b439773 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueService.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueService.java @@ -58,7 +58,7 @@ public interface IssueService { @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_COMMENT)") Issue createComment(UUID issueId, UUID userId, CommentModel commentModel); - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_READ)") + @PostAuthorize(value = "hasResourcePermission(returnObject.issue.id, @PC.ISSUE_READ)") IssueComment getCommentById(UUID issueCommentId); @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") @@ -74,7 +74,7 @@ public interface IssueService { @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EVIDENCE)") Issue createEvidence(UUID issueId, UUID userId, EvidenceModel evidenceModel); - @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_READ)") + @PostAuthorize(value = "hasResourcePermission(returnObject.issue.id, @PC.ISSUE_READ)") IssueEvidence getEvidenceById(UUID issueEvidenceId); @PreAuthorize(value = "hasResourcePermission(#issueId, @PC.ISSUE_EDIT)") diff --git a/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java b/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java index a7b5a12..05d9293 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternLanguageService.java @@ -36,7 +36,7 @@ public interface PatternLanguageService { @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_DELETE)") void deletePatternLanguage(UUID patternLanguageId); - @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT) && hasGlobalPermission(@PC.APPROVED_PATTERN_CREATE)") Pattern createPatternAndAddToPatternLanguage(UUID patternLanguageId, Pattern pattern); @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ)") @@ -46,7 +46,7 @@ public interface PatternLanguageService { @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_READ) && hasResourcePermission(#patternId, @PC.APPROVED_PATTERN_READ)") Pattern getPatternOfPatternLanguageById(UUID patternLanguageId, UUID patternId); - @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") + @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT) && hasResourcePermission(#patternId, @PC.APPROVED_PATTERN_DELETE)") void deletePatternOfPatternLanguage(UUID patternLanguageId, UUID patternId); @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_LANGUAGE_EDIT)") diff --git a/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java index 88dd4f5..3f2b799 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternLanguageServiceImpl.java @@ -142,7 +142,7 @@ public void deletePatternLanguage(UUID patternLanguageId) { } } - this.patternSchemaService.deletePatternSchemaById(patternLanguageId); + this.patternSchemaService.deletePatternSchema(patternLanguage.getPatternSchema()); this.patternLanguageRepository.delete(patternLanguage); } diff --git a/src/main/java/io/github/patternatlas/api/service/PatternSchemaService.java b/src/main/java/io/github/patternatlas/api/service/PatternSchemaService.java index 1567008..592e0d3 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternSchemaService.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternSchemaService.java @@ -3,14 +3,20 @@ import java.util.UUID; import io.github.patternatlas.api.entities.PatternSchema; +import org.springframework.security.access.prepost.PostAuthorize; +import org.springframework.security.access.prepost.PreAuthorize; public interface PatternSchemaService { + @PreAuthorize(value = "hasResourcePermission(#patternSchema.patternLanguage.id, @PC.PATTERN_LANGUAGE_EDIT)") PatternSchema createPatternSchema(PatternSchema patternSchema); + @PreAuthorize(value = "hasResourcePermission(#patternSchema.patternLanguage.id, @PC.PATTERN_LANGUAGE_EDIT)") PatternSchema updatePatternSchema(PatternSchema patternSchema); + @PostAuthorize(value = "hasResourcePermission(#returnObject.patternLanguage.id, @PC.PATTERN_LANGUAGE_READ)") PatternSchema getPatternSchemaById(UUID id); - void deletePatternSchemaById(UUID id); + @PreAuthorize(value = "hasResourcePermission(#schema.patternLanguage.id, @PC.PATTERN_LANGUAGE_EDIT)") + void deletePatternSchema(PatternSchema schema); } diff --git a/src/main/java/io/github/patternatlas/api/service/PatternSchemaServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PatternSchemaServiceImpl.java index 2b6e20c..0c9c943 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternSchemaServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternSchemaServiceImpl.java @@ -74,7 +74,7 @@ public PatternSchema getPatternSchemaById(UUID id) { @Override @Transactional - public void deletePatternSchemaById(UUID id) { - this.patternSchemaRepository.deleteById(id); + public void deletePatternSchema(PatternSchema schema) { + this.patternSchemaRepository.deleteById(schema.getId()); } } diff --git a/src/main/java/io/github/patternatlas/api/service/PatternService.java b/src/main/java/io/github/patternatlas/api/service/PatternService.java index 078c05d..257e9ce 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternService.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternService.java @@ -5,16 +5,23 @@ import io.github.patternatlas.api.entities.Pattern; import io.github.patternatlas.api.validator.PatternContentConstraint; +import org.springframework.security.access.prepost.PostAuthorize; +import org.springframework.security.access.prepost.PreAuthorize; public interface PatternService { + @PreAuthorize(value = "hasGlobalPermission(@PC.APPROVED_PATTERN_CREATE)") Pattern createPattern(@Valid @PatternContentConstraint Pattern pattern); + @PreAuthorize(value = "hasResourcePermission(#pattern.id, @PC.APPROVED_PATTERN_EDIT)") Pattern updatePattern(@Valid @PatternContentConstraint Pattern pattern); + @PreAuthorize(value = "hasResourcePermission(#pattern.id, @PC.APPROVED_PATTERN_DELETE)") void deletePattern(Pattern pattern); + @PostAuthorize(value = "hasResourcePermission(returnObject.id, @PC.APPROVED_PATTERN_READ)") Pattern getPatternById(UUID patternId); + @PostAuthorize(value = "hasResourcePermission(returnObject.id, @PC.APPROVED_PATTERN_READ)") Pattern getPatternByUri(String uri); } diff --git a/src/main/java/io/github/patternatlas/api/service/PatternViewService.java b/src/main/java/io/github/patternatlas/api/service/PatternViewService.java index f42586c..94f5426 100644 --- a/src/main/java/io/github/patternatlas/api/service/PatternViewService.java +++ b/src/main/java/io/github/patternatlas/api/service/PatternViewService.java @@ -24,7 +24,7 @@ public interface PatternViewService { @PostFilter("hasResourcePermission(filterObject.id, @PC.PATTERN_VIEW_READ)") List getAllPatternViews(); - @PreAuthorize(value = "hasResourcePermission(#patternLanguageId, @PC.PATTERN_VIEW_READ)") + @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ)") PatternView getPatternViewById(UUID patternViewId); @PostAuthorize(value = "hasResourcePermission(returnObject.id, @PC.PATTERN_VIEW_READ)") @@ -86,14 +86,14 @@ public interface PatternViewService { void removeUndirectedEdgeFromPatternView(UUID patternViewId, UUID undirectedEdgeId); @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_READ)") - Object getGraphOfPatternView(UUID patternLanguageId); + Object getGraphOfPatternView(UUID patternViewId); @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") - Object createGraphOfPatternView(UUID patternLanguageId, Object graph); + Object createGraphOfPatternView(UUID patternViewId, Object graph); @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") - Object updateGraphOfPatternView(UUID patternLanguageId, Object graph); + Object updateGraphOfPatternView(UUID patternViewId, Object graph); @PreAuthorize(value = "hasResourcePermission(#patternViewId, @PC.PATTERN_VIEW_EDIT)") - void deleteGraphOfPatternView(UUID patternLanguageId); + void deleteGraphOfPatternView(UUID patternViewId); } diff --git a/src/main/java/io/github/patternatlas/api/service/UserService.java b/src/main/java/io/github/patternatlas/api/service/UserService.java index c9d356e..adac6c8 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserService.java @@ -26,7 +26,7 @@ public interface UserService { @PreAuthorize(value = "hasGlobalPermission(@PC.USER_DELETE_ALL)" + "or (hasGlobalPermission(@PC.USER_DELETE) and #userId.equals(loggedInUUID()))") - void deleteUser(UUID UserId); + void deleteUser(UUID userId); /** * Updates the platform wide roles for a given user (does not change other roles even when they are supplied From 75cc59753adbfb3d74160410836aabef9cd3bf55 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 11 May 2022 16:37:54 +0200 Subject: [PATCH 63/68] added logic for creating admin user on first login --- .../api/rest/controller/UserController.java | 23 +++++++++++++++ .../ResourceSecurityExpressionRoot.java | 19 ++++++------ .../api/service/UserAuthService.java | 10 ++++++- .../api/service/UserServiceImpl.java | 29 +++++++++++++------ src/main/resources/application.properties | 2 +- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index 8852f6e..ef5ac0d 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -1,5 +1,6 @@ package io.github.patternatlas.api.rest.controller; +import io.github.patternatlas.api.entities.user.UserEntity; import io.github.patternatlas.api.rest.model.user.*; import io.github.patternatlas.api.service.UserService; @@ -20,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.security.Principal; import java.util.*; import java.util.stream.Collectors; @@ -68,6 +70,27 @@ ResponseEntity> getUserById(@PathVariable UUID userId) { return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.getUserById(userId)))); } + /** + * Extended userinfo endpoint replaces endpoint in auth server. + * @param principal + * @return + */ + @RequestMapping(method = RequestMethod.GET, value = "/userinfo") + @ResponseBody + public Map user(Principal principal) { + if (principal != null) { + UUID id = UUID.fromString(principal.getName()); + UserEntity user = this.userService.getUserById(id); + Map model = new HashMap(); + model.put("name", user.getName()); + model.put("id", user.getId()); + model.put("role", user.getRoles().stream().map(role -> role.getName()).collect(Collectors.toList())); + model.put("privileges", user.getRoles().stream().flatMap(role -> role.getPrivileges().stream()).map(privilege -> privilege.getName()).collect(Collectors.toList())); + return model; + } + return null; + } + @GetMapping(value = "/roles") CollectionModel> getAllRoles() { List> roles = this.userService.getAllRoles() diff --git a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java index 50a371f..e22c974 100644 --- a/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java +++ b/src/main/java/io/github/patternatlas/api/security/ResourceSecurityExpressionRoot.java @@ -13,6 +13,9 @@ import io.github.patternatlas.api.service.RoleService; import io.github.patternatlas.api.service.UserAuthService; import io.github.patternatlas.api.service.UserService; +import io.github.patternatlas.api.service.UserServiceImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; @@ -73,8 +76,6 @@ public boolean hasGlobalPermission(String permissionType) { private void createUser(UUID userId, Authentication authentication) { OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) this.getAuthentication().getDetails(); Jwt jwt = JwtHelper.decode(details.getTokenValue()); - System.out.println("Token: " + jwt.toString()); - System.out.println(jwt.getClaims()); ObjectMapper objectMapper = new ObjectMapper(); try { Map claims = objectMapper.readValue(jwt.getClaims(), Map.class); @@ -83,19 +84,19 @@ private void createUser(UUID userId, Authentication authentication) { req.setId(userId); req.setName(preferredUsername); - System.out.println("Creating: " + req.toString()); - - UserEntity ent = this.userAuthService.createIntialMember(req); - System.out.println("Created: " + ent.toString()); - System.out.println("Created user id: " + ent.getId()); + if(this.userAuthService.hasUsers()) { + // Create standard member user + this.userAuthService.createInitialMember(req); + } else { + // There are no other users registered => create admin user as first user + this.userAuthService.createInitialAdmin(req); + } } catch (JsonProcessingException e) { throw new UserNotFoundException("Cannot infer preferred username from Token"); } } public Optional loggedInUUID() { - - if (this.getAuthentication() == null) { return Optional.empty(); } diff --git a/src/main/java/io/github/patternatlas/api/service/UserAuthService.java b/src/main/java/io/github/patternatlas/api/service/UserAuthService.java index b2407b5..4d1be48 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserAuthService.java +++ b/src/main/java/io/github/patternatlas/api/service/UserAuthService.java @@ -11,7 +11,15 @@ * Used to query user information to handle authentication. */ public interface UserAuthService { - UserEntity createIntialMember(UserModelRequest userModelRequest); + UserEntity createInitialMember(UserModelRequest userModelRequest); + + UserEntity createInitialAdmin(UserModelRequest userModelRequest); boolean userExists(UUID userId); + + /** + * Checks if there are users in the db already + * @return + */ + boolean hasUsers(); } diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index c036699..0db53cf 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -85,25 +85,36 @@ public UserEntity getUserById(UUID userId) { .orElseThrow(() -> new ResourceNotFoundException(String.format("User with ID %s not found!", userId))); } - @Override - public UserEntity createIntialMember(UserModelRequest userModelRequest) { - RoleModel memberModel = new RoleModel(); - memberModel.setName(RoleConstant.MEMBER); - userModelRequest.setRoles(Arrays.asList(memberModel)); - userModelRequest.setPassword(""); // Dummy password since authentication is not performed here - userModelRequest.setEmail(""); - + private UserEntity createInitialUser(UserModelRequest userModelRequest, String requestedRole) { UserEntity user = new UserEntity(userModelRequest, ""); - user.getRoles().add(this.roleRepository.findByName(RoleConstant.MEMBER)); + user.setEmail(""); + user.getRoles().add(this.roleRepository.findByName(requestedRole)); return this.userRepository.save(user); } + @Override + public UserEntity createInitialMember(UserModelRequest userModelRequest) { + return createInitialUser(userModelRequest, RoleConstant.MEMBER); + } + + @Override + public UserEntity createInitialAdmin(UserModelRequest userModelRequest) { + logger.info("Automatically creating admin user " + userModelRequest.getName()); + + return createInitialUser(userModelRequest, RoleConstant.ADMIN); + } + @Override public boolean userExists(UUID userId) { return this.userRepository.findById(userId).isPresent(); } + @Override + public boolean hasUsers() { + return this.userRepository.count() > 0; + } + @Override @Transactional public UserEntity updateUser(UUID userId, UserModelRequest userModelRequest) { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 39e6f97..e69363c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,7 +5,7 @@ spring.datasource.password=patternatlas spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true spring.jpa.hibernate.ddl-auto=update -logging.level.io.github.patternatlas.api=debug +logging.level.io.github.patternatlas.api=info spring.datasource.initialization-mode=always spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true springdoc.default-produces-media-type=application/hal+json From 86e81eea65154c3a1397662bb8ec5b8cfc1f61f7 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 12 May 2022 13:28:55 +0200 Subject: [PATCH 64/68] changed realm --- src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e69363c..0435388 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -12,7 +12,7 @@ springdoc.default-produces-media-type=application/hal+json # alt: AUTH-Server # security.oauth2.resource.jwk.key-set-uri=http://localhost:8081/.well-known/jwks.json # neu: Keycloak -security.oauth2.resource.jwk.key-set-uri=http://localhost:8080/realms/dev/protocol/openid-connect/certs +security.oauth2.resource.jwk.key-set-uri=http://localhost:8080/realms/patternatlas/protocol/openid-connect/certs #okta.oauth2.issuer=https://dev-918271.okta.com/oauth2/default #okta.oauth2.clientId=0oa1eflyl1wZDVLLg357 #---------------------------- From 0d7beeaf0b393f7c195f0c25c9492b4a90a93985 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 25 May 2022 11:45:12 +0200 Subject: [PATCH 65/68] removed old auth logic --- .../patternatlas/api/config/ResourceServerConfig.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java index f439b06..8b5da67 100644 --- a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java +++ b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java @@ -35,16 +35,7 @@ public void configure(HttpSecurity http) throws Exception { .antMatchers("/**") .and() .authorizeRequests() - // START::Comment for local development with authorization -// .antMatchers(HttpMethod.GET, "/**").permitAll() -// .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") -// .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") -// .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('delete')") -// .anyRequest().authenticated() - //END::Comment for local development without authorization - // START::Uncomment for local development without authorization .anyRequest().permitAll() - // END::Uncomment for local development withoutout authorization .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); From 6d2899ca192ebe232a9b42b6c3a01304bd37999f Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 25 May 2022 14:22:02 +0200 Subject: [PATCH 66/68] adapted dockerfile and properties template for authentication chagnes --- .docker/application.properties.tpl | 6 ++++-- Dockerfile | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.docker/application.properties.tpl b/.docker/application.properties.tpl index 83cbcdc..a272ea4 100644 --- a/.docker/application.properties.tpl +++ b/.docker/application.properties.tpl @@ -15,7 +15,9 @@ spring.jpa.properties.hibernate.show_sql=true spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.use_sql_comments=true spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true -spring.liquibase.enabled={{default .Env.PATTERN_ATLAS_FETCH_INITIAL_DATA "false"}} +spring.liquibase.enabled=true +spring.liquibase.change-log=file:patternatlas.xml spring.liquibase.password={{.Env.DB_INIT_PASSWORD}} spring.liquibase.user={{.Env.DB_INIT_USER}} -spring.liquibase.url=jdbc:postgresql://{{.Env.JDBC_DATABASE_URL}}:{{.Env.JDBC_DATABASE_PORT}}/{{.Env.JDBC_DATABASE_NAME}} \ No newline at end of file +spring.liquibase.url=jdbc:postgresql://{{.Env.JDBC_DATABASE_URL}}:{{.Env.JDBC_DATABASE_PORT}}/{{.Env.JDBC_DATABASE_NAME}} +security.oauth2.resource.jwk.key-set-uri={{.Env.JWK_URI}} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 6cfca2a..2ae75e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,6 +36,8 @@ ENV JDBC_DATABASE_NAME postgres ENV JDBC_DATABASE_PORT 5060 ENV HAL_EXPLORER true +ENV JWK_URI "http://localhost:8080/realms/patternatlas/protocol/openid-connect/certs" + RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz From 2b870b56aa5d4935172fafe68a248f40d074f8c9 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 25 May 2022 14:41:41 +0200 Subject: [PATCH 67/68] replaced imports with single class imports --- .../api/entities/candidate/Candidate.java | 20 ++++---- .../api/entities/issue/Issue.java | 16 ++++--- .../api/entities/issue/IssueRating.java | 14 ++++-- .../entities/issue/comment/IssueComment.java | 16 ++++--- .../api/entities/user/UserEntity.java | 19 ++++++-- .../api/entities/user/role/Privilege.java | 6 ++- .../api/entities/user/role/Role.java | 7 ++- .../api/rest/controller/AuthorController.java | 18 +++----- .../rest/controller/CandidateController.java | 25 ++++++---- .../api/rest/controller/IssueController.java | 41 +++++++++-------- .../api/rest/controller/UserController.java | 46 ++++++++++++------- .../RestResponseExceptionHandler.java | 8 +++- .../api/rest/model/issue/IssueModel.java | 5 +- .../shared/PatternLanguageSchemaModel.java | 9 ++-- .../api/service/CandidateService.java | 16 +++---- .../api/service/CandidateServiceImpl.java | 22 +++++++-- .../api/service/IssueServiceImpl.java | 24 ++++++---- .../api/service/PrivilegeServiceImpl.java | 13 ++---- .../api/service/RoleServiceImpl.java | 12 ++--- .../api/service/UserServiceImpl.java | 9 +++- 20 files changed, 214 insertions(+), 132 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java b/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java index de43876..aca7c48 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java @@ -1,27 +1,31 @@ package io.github.patternatlas.api.entities.candidate; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import io.github.patternatlas.api.entities.EntityWithURI; import io.github.patternatlas.api.entities.PatternLanguage; import io.github.patternatlas.api.entities.candidate.author.CandidateAuthor; import io.github.patternatlas.api.entities.candidate.comment.CandidateComment; import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidence; -import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence; import io.github.patternatlas.api.rest.model.candidate.CandidateModelRequest; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; - import org.hibernate.annotations.Type; -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import java.util.*; - @Entity @Data @EqualsAndHashCode(callSuper = true) diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java b/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java index bd73e2c..99d44be 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/Issue.java @@ -1,7 +1,7 @@ package io.github.patternatlas.api.entities.issue; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.ArrayList; +import java.util.List; import io.github.patternatlas.api.entities.EntityWithURI; import io.github.patternatlas.api.entities.issue.author.IssueAuthor; @@ -9,10 +9,14 @@ import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence; import io.github.patternatlas.api.rest.model.issue.IssueModelRequest; -import lombok.*; - -import javax.persistence.*; -import java.util.*; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.OneToMany; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; @Entity @Data diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java index 7eece12..38c46d3 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java @@ -1,13 +1,17 @@ package io.github.patternatlas.api.entities.issue; -import lombok.*; - -import javax.persistence.*; import java.util.Objects; -import io.github.patternatlas.api.entities.user.UserEntity; -import io.github.patternatlas.api.entities.issue.Issue; import io.github.patternatlas.api.entities.shared.CompositeKey; +import io.github.patternatlas.api.entities.user.UserEntity; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; @Entity @Data diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java index 2f47075..545fa7a 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java @@ -1,22 +1,24 @@ package io.github.patternatlas.api.entities.issue.comment; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import io.github.patternatlas.api.entities.issue.Issue; import io.github.patternatlas.api.entities.shared.Comment; import io.github.patternatlas.api.entities.user.UserEntity; -import io.github.patternatlas.api.entities.issue.comment.IssueCommentRating; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; -import javax.persistence.*; -import java.io.Serializable; -import java.util.*; - @Entity @Data @NoArgsConstructor diff --git a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java index d180d7a..83630d9 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java @@ -1,13 +1,22 @@ package io.github.patternatlas.api.entities.user; import java.io.Serializable; -import java.util.*; -import javax.persistence.*; - +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.OneToMany; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.NaturalId; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java index 939f403..fdc90ff 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java @@ -1,9 +1,13 @@ package io.github.patternatlas.api.entities.user.role; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToMany; import lombok.Data; import lombok.NoArgsConstructor; -import javax.persistence.*; import java.util.Collection; import java.util.UUID; diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java index 35e1896..e123981 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java @@ -2,10 +2,15 @@ import io.github.patternatlas.api.entities.user.UserEntity; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToMany; import lombok.Data; import lombok.NoArgsConstructor; -import javax.persistence.*; import java.util.Set; import java.util.UUID; import java.util.Collection; diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java index c82c872..c768672 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java @@ -1,25 +1,19 @@ package io.github.patternatlas.api.rest.controller; +import java.util.List; +import java.util.stream.Collectors; + import io.github.patternatlas.api.entities.shared.AuthorConstant; -import io.github.patternatlas.api.rest.model.candidate.CandidateModel; -import io.github.patternatlas.api.rest.model.issue.IssueModel; import io.github.patternatlas.api.rest.model.shared.AuthorModel; import io.github.patternatlas.api.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; - import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PostFilter; -import org.springframework.web.bind.annotation.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/authors", produces = "application/hal+json") diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java index 40a2127..0c27afb 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java @@ -2,21 +2,20 @@ import com.fasterxml.jackson.databind.ObjectMapper; -import io.github.patternatlas.api.config.Authority; import io.github.patternatlas.api.rest.model.candidate.CandidateModel; import io.github.patternatlas.api.rest.model.candidate.CandidateModelRequest; -import io.github.patternatlas.api.rest.model.issue.IssueModel; -import io.github.patternatlas.api.rest.model.shared.*; +import io.github.patternatlas.api.rest.model.shared.AuthorModelRequest; +import io.github.patternatlas.api.rest.model.shared.CommentModel; +import io.github.patternatlas.api.rest.model.shared.EvidenceModel; +import io.github.patternatlas.api.rest.model.shared.RatingModelMultiRequest; +import io.github.patternatlas.api.rest.model.shared.RatingModelRequest; import io.github.patternatlas.api.service.CandidateService; import io.github.patternatlas.api.service.PatternLanguageService; -import io.swagger.v3.core.util.Json; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,10 +24,16 @@ import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PostFilter; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import java.security.Principal; import java.util.List; diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index 0dc4d0d..392bea6 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -1,35 +1,38 @@ package io.github.patternatlas.api.rest.controller; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.security.Principal; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; -import io.github.patternatlas.api.config.Authority; -import io.github.patternatlas.api.rest.model.issue.IssueModelRequest; -import io.github.patternatlas.api.rest.model.shared.*; import io.github.patternatlas.api.rest.model.issue.IssueModel; -import io.github.patternatlas.api.service.*; +import io.github.patternatlas.api.rest.model.issue.IssueModelRequest; +import io.github.patternatlas.api.rest.model.shared.AuthorModelRequest; +import io.github.patternatlas.api.rest.model.shared.CommentModel; +import io.github.patternatlas.api.rest.model.shared.EvidenceModel; +import io.github.patternatlas.api.rest.model.shared.RatingModelRequest; +import io.github.patternatlas.api.service.IssueService; +import io.github.patternatlas.api.service.PatternLanguageService; +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; - -import liquibase.pro.packaged.P; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PostAuthorize; -import org.springframework.security.access.prepost.PostFilter; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; - -import java.security.Principal; -import java.util.Comparator; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/issues", produces = "application/hal+json") diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index ef5ac0d..e1bcac5 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -1,29 +1,43 @@ package io.github.patternatlas.api.rest.controller; +import java.security.Principal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + import io.github.patternatlas.api.entities.user.UserEntity; -import io.github.patternatlas.api.rest.model.user.*; +import io.github.patternatlas.api.rest.model.user.PrivilegeModel; +import io.github.patternatlas.api.rest.model.user.RoleModel; +import io.github.patternatlas.api.rest.model.user.RoleModelRequest; +import io.github.patternatlas.api.rest.model.user.UserModel; +import io.github.patternatlas.api.rest.model.user.UserModelRequest; import io.github.patternatlas.api.service.UserService; -import org.springframework.hateoas.CollectionModel; -import org.springframework.hateoas.EntityModel; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PostFilter; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.*; - +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; - -import com.fasterxml.jackson.databind.ObjectMapper; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import java.security.Principal; -import java.util.*; -import java.util.stream.Collectors; +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PostFilter; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/users", produces = "application/hal+json") diff --git a/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java b/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java index 54176fe..74a9d1e 100644 --- a/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java +++ b/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java @@ -1,6 +1,12 @@ package io.github.patternatlas.api.rest.exception; -import io.github.patternatlas.api.exception.*; +import io.github.patternatlas.api.exception.DirectedEdgeNotFoundException; +import io.github.patternatlas.api.exception.NullPatternSchemaException; +import io.github.patternatlas.api.exception.PatternLanguageNotFoundException; +import io.github.patternatlas.api.exception.PatternNotFoundException; +import io.github.patternatlas.api.exception.PatternSchemaNotFoundException; +import io.github.patternatlas.api.exception.PatternViewNotFoundException; +import io.github.patternatlas.api.exception.UndirectedEdgeNotFoundException; import io.github.patternatlas.api.rest.model.ErrorMessageDTO; import org.springframework.data.rest.webmvc.ResourceNotFoundException; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModel.java b/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModel.java index 63a80fa..07feffa 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/issue/IssueModel.java @@ -11,7 +11,10 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; @Data diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java index ca57b1b..ff70b45 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/PatternLanguageSchemaModel.java @@ -1,14 +1,17 @@ package io.github.patternatlas.api.rest.model.shared; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.UUID; +import java.util.stream.Collectors; + import io.github.patternatlas.api.entities.PatternLanguage; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import java.util.*; -import java.util.stream.Collectors; - @NoArgsConstructor @Data @EqualsAndHashCode(callSuper = false) diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateService.java b/src/main/java/io/github/patternatlas/api/service/CandidateService.java index e15761f..f90b6a2 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateService.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateService.java @@ -1,22 +1,22 @@ package io.github.patternatlas.api.service; +import java.util.List; +import java.util.UUID; + import io.github.patternatlas.api.entities.candidate.Candidate; -import io.github.patternatlas.api.entities.candidate.author.CandidateAuthor; import io.github.patternatlas.api.entities.candidate.comment.CandidateComment; -import io.github.patternatlas.api.entities.candidate.comment.CandidateCommentRating; import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidence; -import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidenceRating; import io.github.patternatlas.api.rest.model.candidate.CandidateModelRequest; -import io.github.patternatlas.api.rest.model.shared.*; +import io.github.patternatlas.api.rest.model.shared.AuthorModelRequest; +import io.github.patternatlas.api.rest.model.shared.CommentModel; +import io.github.patternatlas.api.rest.model.shared.EvidenceModel; +import io.github.patternatlas.api.rest.model.shared.RatingModelMultiRequest; +import io.github.patternatlas.api.rest.model.shared.RatingModelRequest; -import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; -import java.util.List; -import java.util.UUID; - public interface CandidateService { Candidate saveCandidate(Candidate candidate); /** CRUD */ diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index 86690ad..a67b6e0 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -15,9 +15,21 @@ import io.github.patternatlas.api.entities.user.role.PrivilegeConstant; import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.entities.user.role.RoleConstant; -import io.github.patternatlas.api.repositories.*; +import io.github.patternatlas.api.repositories.CandidateAuthorRepository; +import io.github.patternatlas.api.repositories.CandidateCommentRatingRepository; +import io.github.patternatlas.api.repositories.CandidateCommentRepository; +import io.github.patternatlas.api.repositories.CandidateEvidenceRatingRepository; +import io.github.patternatlas.api.repositories.CandidateEvidenceRepository; +import io.github.patternatlas.api.repositories.CandidateRatingRepository; +import io.github.patternatlas.api.repositories.CandidateRepository; import io.github.patternatlas.api.rest.model.candidate.CandidateModelRequest; -import io.github.patternatlas.api.rest.model.shared.*; +import io.github.patternatlas.api.rest.model.shared.AuthorModel; +import io.github.patternatlas.api.rest.model.shared.AuthorModelRequest; +import io.github.patternatlas.api.rest.model.shared.CommentModel; +import io.github.patternatlas.api.rest.model.shared.EvidenceModel; +import io.github.patternatlas.api.rest.model.shared.RatingModelMultiRequest; +import io.github.patternatlas.api.rest.model.shared.RatingModelRequest; +import io.github.patternatlas.api.rest.model.shared.RatingType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,7 +39,11 @@ import javax.persistence.EntityExistsException; import javax.persistence.EntityNotFoundException; -import java.util.*; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; @Service diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index d4ec4b1..6a7c731 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -1,9 +1,14 @@ package io.github.patternatlas.api.service; -import io.github.patternatlas.api.entities.issue.IssueRating; -import io.github.patternatlas.api.entities.issue.comment.IssueComment; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + import io.github.patternatlas.api.entities.issue.Issue; +import io.github.patternatlas.api.entities.issue.IssueRating; import io.github.patternatlas.api.entities.issue.author.IssueAuthor; +import io.github.patternatlas.api.entities.issue.comment.IssueComment; import io.github.patternatlas.api.entities.issue.comment.IssueCommentRating; import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence; import io.github.patternatlas.api.entities.issue.evidence.IssueEvidenceRating; @@ -13,24 +18,27 @@ import io.github.patternatlas.api.entities.user.role.PrivilegeConstant; import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.entities.user.role.RoleConstant; -import io.github.patternatlas.api.repositories.*; +import io.github.patternatlas.api.repositories.IssueAuthorRepository; +import io.github.patternatlas.api.repositories.IssueCommentRatingRepository; +import io.github.patternatlas.api.repositories.IssueCommentRepository; +import io.github.patternatlas.api.repositories.IssueEvidenceRatingRepository; +import io.github.patternatlas.api.repositories.IssueEvidenceRepository; +import io.github.patternatlas.api.repositories.IssueRatingRepository; +import io.github.patternatlas.api.repositories.IssueRepository; import io.github.patternatlas.api.rest.model.issue.IssueModelRequest; import io.github.patternatlas.api.rest.model.shared.AuthorModelRequest; import io.github.patternatlas.api.rest.model.shared.CommentModel; import io.github.patternatlas.api.rest.model.shared.EvidenceModel; import io.github.patternatlas.api.rest.model.shared.RatingModelRequest; +import javax.persistence.EntityExistsException; +import javax.persistence.EntityNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import javax.persistence.EntityExistsException; -import javax.persistence.EntityNotFoundException; -import java.util.*; -import java.util.stream.Collectors; - @Service @Transactional public class IssueServiceImpl implements IssueService { diff --git a/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java index 0b42c2e..7a576cf 100644 --- a/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/PrivilegeServiceImpl.java @@ -1,22 +1,15 @@ package io.github.patternatlas.api.service; +import java.util.UUID; + import io.github.patternatlas.api.entities.user.role.Privilege; -import io.github.patternatlas.api.repositories.*; +import io.github.patternatlas.api.repositories.PrivilegeRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.data.rest.webmvc.ResourceNotFoundException; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import io.github.patternatlas.api.service.PrivilegeService; - -import javax.persistence.EntityExistsException; -import javax.persistence.EntityNotFoundException; -import java.util.List; -import java.util.UUID; - @Service @Transactional public class PrivilegeServiceImpl implements PrivilegeService { diff --git a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java index c7d03bc..915d441 100644 --- a/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/RoleServiceImpl.java @@ -1,18 +1,18 @@ package io.github.patternatlas.api.service; -import io.github.patternatlas.api.entities.user.role.Role; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + import io.github.patternatlas.api.entities.user.role.Privilege; -import io.github.patternatlas.api.repositories.*; +import io.github.patternatlas.api.entities.user.role.Role; +import io.github.patternatlas.api.repositories.RoleRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.UUID; -import java.util.Collection; - @Service @Transactional public class RoleServiceImpl implements RoleService { diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 0db53cf..044ee93 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -7,7 +7,9 @@ import io.github.patternatlas.api.repositories.PrivilegeRepository; import io.github.patternatlas.api.repositories.RoleRepository; import io.github.patternatlas.api.repositories.UserRepository; -import io.github.patternatlas.api.rest.model.user.*; +import io.github.patternatlas.api.rest.model.user.RoleModel; +import io.github.patternatlas.api.rest.model.user.RoleModelRequest; +import io.github.patternatlas.api.rest.model.user.UserModelRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,7 +18,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import java.util.stream.Collectors; @Service From 74909cb47393b3bcbd720bb6a73c9d7ab25f926d Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 25 May 2022 15:25:06 +0200 Subject: [PATCH 68/68] small refactoring and code style changes --- .../candidate/comment/CandidateComment.java | 8 +-- .../entities/issue/comment/IssueComment.java | 8 +-- .../api/entities/shared/Comment.java | 17 +++++- .../api/entities/user/UserEntity.java | 13 ----- .../api/entities/user/role/Role.java | 5 -- .../rest/controller/CandidateController.java | 17 +++--- .../api/rest/controller/IssueController.java | 1 - .../api/rest/controller/UserController.java | 11 +++- .../api/rest/model/shared/CommentModel.java | 53 +++++++++---------- .../api/service/CandidateServiceImpl.java | 9 ---- .../api/service/IssueServiceImpl.java | 1 - .../api/service/UserServiceImpl.java | 6 ++- 12 files changed, 64 insertions(+), 85 deletions(-) diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java index 59aff9e..650b341 100644 --- a/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java +++ b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java @@ -32,11 +32,6 @@ public class CandidateComment extends Comment implements Serializable { @ManyToOne private Candidate candidate; - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - @ToString.Exclude - @ManyToOne - private UserEntity user; - @JsonIgnore @OneToMany(mappedBy = "candidateComment", cascade = CascadeType.ALL, orphanRemoval = true) private Set userRating = new HashSet<>(); @@ -44,9 +39,8 @@ public class CandidateComment extends Comment implements Serializable { private int rating = 0; public CandidateComment(String text, Candidate candidate, UserEntity user) { - super(text); + super(text, user); this.candidate = candidate; - this.user = user; } public void updateComment(String text) { diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java index 545fa7a..a343681 100644 --- a/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java +++ b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java @@ -30,11 +30,6 @@ public class IssueComment extends Comment implements Serializable { @ManyToOne private Issue issue; - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - @ToString.Exclude - @ManyToOne - private UserEntity user; - @JsonIgnore @OneToMany(mappedBy = "issueComment", cascade = CascadeType.ALL, orphanRemoval = true) private List userRating = new ArrayList<>(); @@ -42,9 +37,8 @@ public class IssueComment extends Comment implements Serializable { private int rating = 0; public IssueComment(String text, Issue issue, UserEntity user) { - super(text); + super(text, user); this.issue = issue; - this.user = user; } public void updateComment(String text) { diff --git a/src/main/java/io/github/patternatlas/api/entities/shared/Comment.java b/src/main/java/io/github/patternatlas/api/entities/shared/Comment.java index 50e0a18..86bfc8a 100644 --- a/src/main/java/io/github/patternatlas/api/entities/shared/Comment.java +++ b/src/main/java/io/github/patternatlas/api/entities/shared/Comment.java @@ -2,12 +2,18 @@ import java.util.Objects; import java.util.UUID; + +import io.github.patternatlas.api.entities.user.UserEntity; + +import com.fasterxml.jackson.annotation.JsonProperty; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.ManyToOne; import javax.persistence.MappedSuperclass; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.ToString; @MappedSuperclass @Data @@ -20,8 +26,14 @@ public abstract class Comment { private String text; - public Comment(String text) { + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @ToString.Exclude + @ManyToOne + private UserEntity user; + + public Comment(String text, UserEntity user) { this.text = text; + this.user = user; } @Override @@ -30,7 +42,8 @@ public boolean equals(Object o) { if (!(o instanceof Comment)) return false; Comment that = (Comment) o; return id.equals(that.id) && - text.equals(that.text); + text.equals(that.text) && + user.equals(that.user); } @Override diff --git a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java index 83630d9..dc5f693 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java @@ -52,14 +52,8 @@ public class UserEntity implements Serializable{ @JsonIgnore @ToString.Exclude @ManyToMany() - /*@JoinTable( - name = "user_entity_roles", - joinColumns = { @JoinColumn(name = "users_id") }, - inverseJoinColumns = { @JoinColumn(name = "roles_id") } - )*/ private Set roles; - //@NaturalId(mutable = true) @Column(nullable = false, unique = false) private String email; @@ -107,13 +101,6 @@ public class UserEntity implements Serializable{ private List candidateEvidence = new ArrayList<>(); /** Pattern fields*/ -// @JsonIgnore -// @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) -// private Set candidateRatings = new HashSet<>(); -// -// @JsonIgnore -// @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) -// private List candidateComments = new ArrayList<>(); public UserEntity(UserModel userModel, String password) { this(userModel.getName(), userModel.getEmail(), password, null); diff --git a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java index e123981..c265955 100644 --- a/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java +++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java @@ -31,11 +31,6 @@ public class Role { private Set users; @ManyToMany(cascade = CascadeType.ALL) - /*@JoinTable( - name = "role_privileges", - joinColumns = { @JoinColumn(name = "roles_id") }, - inverseJoinColumns = { @JoinColumn(name = "privileges_id") } - )*/ private Collection privileges; public Role(String name) { diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java index 0c27afb..9d2ea1b 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/CandidateController.java @@ -16,7 +16,6 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,19 +64,19 @@ public CandidateController( */ @Operation(operationId = "getAllCandidates", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve all candidates") @GetMapping(value = "") - CollectionModel> all(@RequestParam(value = "lid", required = false) UUID languageId) { - + CollectionModel> getAllCandidates(@RequestParam(value = "lid", required = false) UUID languageId) { + List> candidates; if (languageId == null) { candidates = this.candidateService.getAllCandidates() - .stream() - .map(candidate -> new EntityModel<>(new CandidateModel(candidate))) - .collect(Collectors.toList()); + .stream() + .map(candidate -> new EntityModel<>(new CandidateModel(candidate))) + .collect(Collectors.toList()); } else { candidates = this.candidateService.getAllCandidatesByLanguageId(languageId) - .stream() - .map(candidate -> new EntityModel<>(new CandidateModel(candidate))) - .collect(Collectors.toList()); + .stream() + .map(candidate -> new EntityModel<>(new CandidateModel(candidate))) + .collect(Collectors.toList()); } return new CollectionModel<>(candidates); diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java index 392bea6..5b7ffc9 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/IssueController.java @@ -71,7 +71,6 @@ CollectionModel> getAll() { List> issues = this.issueService.getAllIssues() .stream() .map(issue -> new EntityModel<>(new IssueModel(issue))) -// .sorted(Comparator.comparingInt(i -> i.getContent().getRating())) .sorted((i1, i2) -> Integer.compare(i2.getContent().getRating(), i1.getContent().getRating())) .collect(Collectors.toList()); return CollectionModel.of(issues); diff --git a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java index e1bcac5..98f24ab 100644 --- a/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java +++ b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java @@ -8,6 +8,8 @@ import java.util.stream.Collectors; import io.github.patternatlas.api.entities.user.UserEntity; +import io.github.patternatlas.api.entities.user.role.Privilege; +import io.github.patternatlas.api.entities.user.role.Role; import io.github.patternatlas.api.rest.model.user.PrivilegeModel; import io.github.patternatlas.api.rest.model.user.RoleModel; import io.github.patternatlas.api.rest.model.user.RoleModelRequest; @@ -98,8 +100,13 @@ public Map user(Principal principal) { Map model = new HashMap(); model.put("name", user.getName()); model.put("id", user.getId()); - model.put("role", user.getRoles().stream().map(role -> role.getName()).collect(Collectors.toList())); - model.put("privileges", user.getRoles().stream().flatMap(role -> role.getPrivileges().stream()).map(privilege -> privilege.getName()).collect(Collectors.toList())); + model.put("role", user.getRoles().stream() + .map(Role::getName) + .collect(Collectors.toList())); + model.put("privileges", user.getRoles().stream() + .flatMap(role -> role.getPrivileges().stream()) + .map(Privilege::getName) + .collect(Collectors.toList())); return model; } return null; diff --git a/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java b/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java index 06beeb9..658683a 100644 --- a/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java +++ b/src/main/java/io/github/patternatlas/api/rest/model/shared/CommentModel.java @@ -5,6 +5,8 @@ import io.github.patternatlas.api.entities.issue.IssueRating; import io.github.patternatlas.api.entities.issue.comment.IssueComment; import io.github.patternatlas.api.entities.issue.comment.IssueCommentRating; +import io.github.patternatlas.api.entities.shared.Comment; +import io.github.patternatlas.api.entities.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -27,24 +29,32 @@ public class CommentModel { private Collection upVotes = new ArrayList<>(); private Collection downVotes = new ArrayList<>(); + private void initialize(Comment comment) { + this.id = comment.getId(); + this.userId = comment.getUser().getId(); + this.userName = comment.getUser().getName(); + this.text = comment.getText(); + this.rating = 0; + } + + private void updateRatingInformation(UserEntity user, int rating) { + if (rating == 1) { + this.upVotes.add(user.getId()); + this.rating = this.rating + 1; + } + if (rating == -1) { + this.downVotes.add(user.getId()); + this.rating = this.rating - 1; + } + } + /** * For Issue Comments */ public CommentModel(IssueComment issueComment) { - this.id = issueComment.getId(); - this.userId = issueComment.getUser().getId(); - this.userName = issueComment.getUser().getName(); - this.text = issueComment.getText(); - this.rating = 0; + initialize(issueComment); for (IssueCommentRating issueRating : issueComment.getUserRating()) { - if (issueRating.getRating() == 1) { - this.upVotes.add(issueRating.getUser().getId()); - this.rating = this.rating + 1; - } - if (issueRating.getRating() == -1) { - this.downVotes.add(issueRating.getUser().getId()); - this.rating = this.rating - 1; - } + updateRatingInformation(issueRating.getUser(), issueRating.getRating()); } } @@ -56,20 +66,9 @@ public static CommentModel from(IssueComment issueComment) { * For Candidate Comments */ public CommentModel(CandidateComment candidateComment) { - this.id = candidateComment.getId(); - this.userId = candidateComment.getUser().getId(); - this.userName = candidateComment.getUser().getName(); - this.text = candidateComment.getText(); - this.rating = 0; - for (CandidateCommentRating candidateCommentRating : candidateComment.getUserRating()) { - if (candidateCommentRating.getRating() == 1) { - this.upVotes.add(candidateCommentRating.getUser().getId()); - this.rating = this.rating + 1; - } - if (candidateCommentRating.getRating() == -1) { - this.downVotes.add(candidateCommentRating.getUser().getId()); - this.rating = this.rating - 1; - } + initialize(candidateComment); + for (CandidateCommentRating issueRating : candidateComment.getUserRating()) { + updateRatingInformation(issueRating.getUser(), issueRating.getRating()); } } diff --git a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java index a67b6e0..9ef478c 100644 --- a/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/CandidateServiceImpl.java @@ -260,15 +260,6 @@ public Candidate updateCandidateRating(UUID candidateId, UUID userId, RatingMode } CandidateRating updatedCandidateRating = this.candidateRatingRepository.save(candidateRating); return updatedCandidateRating.getCandidate(); - -// if (ratingModelMultiRequest.getRatingType().equals(RatingType.READABILITY)) { -// return new RatingModel(updatedCandidateRating, updatedCandidateRating.getReadability()); -// } else if (ratingModelMultiRequest.getRatingType().equals(RatingType.UNDERSTANDABILITY)) { -// return new RatingModel(updatedCandidateRating, updatedCandidateRating.getUnderstandability()); -// } else{ -// return new RatingModel(updatedCandidateRating, updatedCandidateRating.getAppropriateness()); -// } - } @Override diff --git a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java index 6a7c731..3016bc6 100644 --- a/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/IssueServiceImpl.java @@ -187,7 +187,6 @@ public Issue updateIssueRating(UUID issueId, UUID userId, RatingModelRequest rat public void deleteIssue(UUID issueId) { this.roleService.deleteAllRolesByResourceId(issueId); this.privilegeService.deleteAllPrivilegesByResourceId(issueId); - //this.getIssueById(issueId); this.issueRepository.deleteById(issueId); } diff --git a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java index 044ee93..d2fe5b0 100644 --- a/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java +++ b/src/main/java/io/github/patternatlas/api/service/UserServiceImpl.java @@ -245,11 +245,13 @@ public Role updateRole(UUID roleId, UUID privilegeId, RoleModelRequest roleModel Role role = this.roleRepository.findById(roleId).orElseThrow(() -> new ResourceNotFoundException(String.format(" Role %s not found!", roleId))); Privilege privilege = this.privilegeRepository.findById(privilegeId).orElseThrow(() -> new ResourceNotFoundException(String.format("Privilege %s not found!", privilegeId))); - if (role.getPrivileges().contains(privilege) && !roleModelRequest.isCheckboxValue()) + if (role.getPrivileges().contains(privilege) && !roleModelRequest.isCheckboxValue()) { role.getPrivileges().remove(privilege); + } - if (!role.getPrivileges().contains(privilege) && roleModelRequest.isCheckboxValue()) + if (!role.getPrivileges().contains(privilege) && roleModelRequest.isCheckboxValue()) { role.getPrivileges().add(privilege); + } return this.roleRepository.save(role); }