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/.docker/docker-compose.yml b/.docker/docker-compose.yml
new file mode 100644
index 0000000..053a679
--- /dev/null
+++ b/.docker/docker-compose.yml
@@ -0,0 +1,15 @@
+version: '3'
+services:
+ db:
+ image: postgres:10
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: postgres
+ ports:
+ - "5432:5432"
+ networks:
+ - default
+networks:
+ default:
+ driver: bridge
diff --git a/.gitignore b/.gitignore
index 173b6aa..2da8a1e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
@@ -30,10 +31,13 @@ build/
### VS Code ###
.vscode/
+### MacOS File System ###
+**/.DS_STORE
+
### TexRendering ###
*.png
*.tex
*.pdf
*.log
*.aux
-*.svg
\ No newline at end of file
+*.svg
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
diff --git a/docs/dev/index.md b/docs/dev/index.md
index 9fe370a..ec62640 100644
--- a/docs/dev/index.md
+++ b/docs/dev/index.md
@@ -1,10 +1,14 @@
# PatternAtlas Developer Guide
-This document provides an index to all development guidelines and background information of the PatternPedia.
+This document provides an index to all development guidelines and background information of the PatternAtlas.
- [ADR](/adr) - Information on Architectural decisions can be found here
## Quick Develop
-
-1. Clone the repository `git clone https://github.com/PatternPedia/pattern-atlas-api.git`.
+1. Clone the repository `git clone https://github.com/PatternAtlas/pattern-atlas-api.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-atlas-ui.git`.
+3. Clone the repository `git clone https://github.com/PatternAtlas/pattern-atlas-ui.git`.
4. Build the repository `mvn package -DskipTests` (skiping the tests for a faster build), npm is required. (plus yarn, optionally)
5. Continue your IDE setup:
- [IntelliJ Ultimate](IntelliJ/)
diff --git a/pom.xml b/pom.xml
index 0c4906d..a60d28e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,6 +17,7 @@
1.8
1.5.9
2.5.0
+ 2.13.2
@@ -137,11 +138,6 @@
-
- org.springdoc
- springdoc-openapi-ui
- ${springdoc-ui.version}
-
org.springdoc
springdoc-openapi-data-rest
@@ -169,7 +165,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}
diff --git a/src/main/java/io/github/patternatlas/api/PatternAtlasAPI.java b/src/main/java/io/github/patternatlas/api/PatternAtlasAPI.java
index 1d20522..84f3222 100644
--- a/src/main/java/io/github/patternatlas/api/PatternAtlasAPI.java
+++ b/src/main/java/io/github/patternatlas/api/PatternAtlasAPI.java
@@ -4,20 +4,33 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
-
-import com.vladmihalcea.hibernate.type.util.Configuration;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Contact;
import io.swagger.v3.oas.annotations.info.Info;
+
+import com.vladmihalcea.hibernate.type.util.Configuration;
+
import lombok.extern.slf4j.Slf4j;
+import io.github.patternatlas.api.rest.controller.UserController;
+import io.github.patternatlas.api.service.IssueService;
+
@EnableTransactionManagement
@Slf4j
+@RestController
@SpringBootApplication
@OpenAPIDefinition(info = @Info(title = "pattern-atlas-api", version = "1.0", contact = @Contact(url = "https://github.com/PatternAtlas/pattern-atlas-api", name = "Pattern Atlas API")))
public class PatternAtlasAPI implements CommandLineRunner {
+ @Autowired
+ private UserController userController;
+
+ @Autowired
+ private IssueService issueService;
+
public static void main(String[] args) {
System.setProperty(Configuration.PropertyKey.PRINT_BANNER.getKey(), Boolean.FALSE.toString());
SpringApplication.run(PatternAtlasAPI.class, args);
diff --git a/src/main/java/io/github/patternatlas/api/config/Authority.java b/src/main/java/io/github/patternatlas/api/config/Authority.java
new file mode 100644
index 0000000..4c5c109
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/config/Authority.java
@@ -0,0 +1,29 @@
+package io.github.patternatlas.api.config;
+
+public interface Authority {
+
+ // TODO will be phased out - after all authority checks are changed to hasResourcePermission, this file should not be
+ // needed anymore
+
+ /** 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/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 027fc28..8b5da67 100644
--- a/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java
+++ b/src/main/java/io/github/patternatlas/api/config/ResourceServerConfig.java
@@ -1,9 +1,11 @@
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;
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;
@@ -11,15 +13,19 @@
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
-// START::Comment for local development with authorization
-//@EnableGlobalMethodSecurity(prePostEnabled = true)
-// END::Comment for local development with authorization
class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
@@ -29,17 +35,7 @@ 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')")
-// .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
-// .antMatchers(HttpMethod.DELETE, "/**").hasAuthority("ADMIN")
-// .anyRequest().authenticated()
- //END::Comment for local development with authorization
- // START::Uncomment for local development without authorization
.anyRequest().permitAll()
- // END::Uncomment for local development without authorization
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
@@ -69,4 +65,5 @@ public FilterRegistrationBean customCorsFilter() {
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
+
}
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/PatternGraph.java b/src/main/java/io/github/patternatlas/api/entities/PatternGraph.java
index ed26a36..7ccab25 100644
--- a/src/main/java/io/github/patternatlas/api/entities/PatternGraph.java
+++ b/src/main/java/io/github/patternatlas/api/entities/PatternGraph.java
@@ -11,6 +11,8 @@
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+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/io/github/patternatlas/api/entities/PatternLanguage.java b/src/main/java/io/github/patternatlas/api/entities/PatternLanguage.java
index 0ca1443..57f19ce 100644
--- a/src/main/java/io/github/patternatlas/api/entities/PatternLanguage.java
+++ b/src/main/java/io/github/patternatlas/api/entities/PatternLanguage.java
@@ -45,4 +45,6 @@ public class PatternLanguage extends PatternGraph {
@JsonIgnore
@OneToMany(mappedBy = "patternLanguage", fetch = FetchType.LAZY)
private List undirectedEdges;
+
+
}
diff --git a/src/main/java/io/github/patternatlas/api/entities/PatternSchema.java b/src/main/java/io/github/patternatlas/api/entities/PatternSchema.java
index 5935321..da4f38a 100644
--- a/src/main/java/io/github/patternatlas/api/entities/PatternSchema.java
+++ b/src/main/java/io/github/patternatlas/api/entities/PatternSchema.java
@@ -1,6 +1,7 @@
package io.github.patternatlas.api.entities;
import java.util.List;
+import java.util.Objects;
import java.util.UUID;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
@@ -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/io/github/patternatlas/api/entities/PatternView.java b/src/main/java/io/github/patternatlas/api/entities/PatternView.java
index 4b1bbbf..85c8cf6 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,14 +24,17 @@ public class PatternView extends PatternGraph {
private URL logo;
@JsonIgnore
+ @ToString.Exclude
@OneToMany(mappedBy = "patternView", cascade = CascadeType.ALL, orphanRemoval = true)
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/entities/candidate/Candidate.java b/src/main/java/io/github/patternatlas/api/entities/candidate/Candidate.java
index 88ac5c2..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
@@ -3,25 +3,28 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
-import java.util.ListIterator;
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.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 com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import io.github.patternatlas.api.entities.candidate.rating.CandidateRating;
-import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.rest.model.CandidateModel;
-import io.github.patternatlas.api.entities.EntityWithURI;
-import io.github.patternatlas.api.entities.PatternLanguage;
+import javax.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
+import org.hibernate.annotations.Type;
@Entity
@Data
@@ -36,15 +39,19 @@ public class Candidate extends EntityWithURI {
@ManyToOne
private PatternLanguage patternLanguage;
- // @Type(type = "jsonb")
-// @Column(columnDefinition = "jsonb")
-// @NotNull
- private String content;
-
- private int rating = 0;
+ @Type(type = "jsonb")
+ @Column(columnDefinition = "jsonb")
+ @NotNull
+ private Object content;
private String version = "0.1.0";
+ private int rating;
+
+ @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<>();
@@ -53,40 +60,31 @@ 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;
- }
- }
+ @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());
+ this.setName(candidateModelRequest.getName());
+ this.setIconUrl(candidateModelRequest.getIconUrl());
+ this.setContent(candidateModelRequest.getContent());
+ this.setVersion(candidateModelRequest.getVersion());
+ this.setRating(candidateModelRequest.getRating());
}
- 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());
+ this.setRating(candidateModelRequest.getRating());
}
public String toString() {
return this.getId().toString();
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java
similarity index 59%
rename from src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateRating.java
rename to src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java
index 175801f..09199f3 100644
--- a/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateRating.java
+++ b/src/main/java/io/github/patternatlas/api/entities/candidate/CandidateRating.java
@@ -1,4 +1,4 @@
-package io.github.patternatlas.api.entities.candidate.rating;
+package io.github.patternatlas.api.entities.candidate;
import java.util.Objects;
import javax.persistence.EmbeddedId;
@@ -8,10 +8,13 @@
import io.github.patternatlas.api.entities.user.UserEntity;
import io.github.patternatlas.api.entities.candidate.Candidate;
+import io.github.patternatlas.api.entities.shared.CompositeKey;
+
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+
@Entity
@Data
@NoArgsConstructor
@@ -19,10 +22,10 @@ public class CandidateRating {
@EmbeddedId
@EqualsAndHashCode.Include
- private CandidateRatingKey id;
+ private CompositeKey id;
@ManyToOne
- @MapsId("candidateId")
+ @MapsId("entityId")
@EqualsAndHashCode.Include
private Candidate candidate;
@@ -33,15 +36,26 @@ public class CandidateRating {
private int rating;
+ private int readability;
+ private int understandability;
+ private int appropriateness;
+
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 readability, int understandability, int appropriateness) {
+ this(candidate, user);
+ 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
@@ -51,11 +65,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/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java b/src/main/java/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java
new file mode 100644
index 0000000..cacb72f
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/candidate/author/CandidateAuthor.java
@@ -0,0 +1,48 @@
+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 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/io/github/patternatlas/api/entities/candidate/CandidateComment.java b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java
similarity index 67%
rename from src/main/java/io/github/patternatlas/api/entities/candidate/CandidateComment.java
rename to src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java
index 91ed163..650b341 100644
--- a/src/main/java/io/github/patternatlas/api/entities/candidate/CandidateComment.java
+++ b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateComment.java
@@ -1,4 +1,9 @@
-package io.github.patternatlas.api.entities.candidate;
+package io.github.patternatlas.api.entities.candidate.comment;
+
+import io.github.patternatlas.api.entities.candidate.Candidate;
+import io.github.patternatlas.api.entities.candidate.comment.CandidateCommentRating;
+import io.github.patternatlas.api.entities.shared.Comment;
+import io.github.patternatlas.api.entities.user.UserEntity;
import java.io.Serializable;
import java.util.HashSet;
@@ -11,9 +16,6 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
-import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.candidate.rating.CandidateCommentRating;
-import io.github.patternatlas.api.entities.shared.Comment;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -30,16 +32,18 @@ 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<>();
- public CandidateComment(String text) {
- super(text);
+ private int rating = 0;
+
+ public CandidateComment(String text, Candidate candidate, UserEntity user) {
+ super(text, user);
+ this.candidate = candidate;
+ }
+
+ public void updateComment(String text) {
+ this.setText(text);
}
}
diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateCommentRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java
similarity index 74%
rename from src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateCommentRating.java
rename to src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java
index ef19154..7f7ec77 100644
--- a/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateCommentRating.java
+++ b/src/main/java/io/github/patternatlas/api/entities/candidate/comment/CandidateCommentRating.java
@@ -1,4 +1,4 @@
-package io.github.patternatlas.api.entities.candidate.rating;
+package io.github.patternatlas.api.entities.candidate.comment;
import java.util.Objects;
import javax.persistence.EmbeddedId;
@@ -6,8 +6,10 @@
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;
+
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -19,10 +21,10 @@ public class CandidateCommentRating {
@EmbeddedId
@EqualsAndHashCode.Include
- private CandidateCommentRatingKey id;
+ private CompositeKey id;
@ManyToOne
- @MapsId("candidateCommentId")
+ @MapsId("entityId")
@EqualsAndHashCode.Include
private CandidateComment candidateComment;
@@ -36,7 +38,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/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java
new file mode 100644
index 0000000..11a38c5
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidence.java
@@ -0,0 +1,61 @@
+package io.github.patternatlas.api.entities.candidate.evidence;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+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;
+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/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java
new file mode 100644
index 0000000..7da3a26
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/candidate/evidence/CandidateEvidenceRating.java
@@ -0,0 +1,68 @@
+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 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/io/github/patternatlas/api/entities/candidate/rating/CandidateCommentRatingKey.java b/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateCommentRatingKey.java
deleted file mode 100644
index 5f15db8..0000000
--- a/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateCommentRatingKey.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package io.github.patternatlas.api.entities.candidate.rating;
-
-import java.io.Serializable;
-import java.util.UUID;
-import javax.persistence.Embeddable;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-
-@Embeddable
-@NoArgsConstructor
-@AllArgsConstructor
-@Data
-@EqualsAndHashCode(callSuper = false)
-public class CandidateCommentRatingKey implements Serializable {
-
- protected UUID candidateCommentId;
- protected UUID userId;
-}
diff --git a/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateRatingKey.java b/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateRatingKey.java
deleted file mode 100644
index 6b8acc5..0000000
--- a/src/main/java/io/github/patternatlas/api/entities/candidate/rating/CandidateRatingKey.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package io.github.patternatlas.api.entities.candidate.rating;
-
-import java.io.Serializable;
-import java.util.UUID;
-import javax.persistence.Embeddable;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-
-@Embeddable
-@NoArgsConstructor
-@AllArgsConstructor
-@Data
-@EqualsAndHashCode(callSuper = false)
-public class CandidateRatingKey implements Serializable {
-
- protected UUID candidateId;
- protected UUID userId;
-}
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 f0ab40b..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,20 +1,19 @@
package io.github.patternatlas.api.entities.issue;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-import javax.persistence.CascadeType;
-import javax.persistence.Entity;
-import javax.persistence.OneToMany;
+
+import io.github.patternatlas.api.entities.EntityWithURI;
+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.evidence.IssueEvidence;
+import io.github.patternatlas.api.rest.model.issue.IssueModelRequest;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
-
-import io.github.patternatlas.api.entities.issue.rating.IssueRating;
-import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.EntityWithURI;
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -27,42 +26,44 @@ public class Issue extends EntityWithURI {
private String description;
- private int rating = 0;
-
private String version = "0.1.0";
+ private int rating;
+
+ @JsonIgnore
+ @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true)
+ private List authors = new ArrayList<>();
+
@JsonIgnore
@OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true)
- private Set userRating = new HashSet<>();
+ 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);
- }
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL, orphanRemoval = true)
+ private List evidences = new ArrayList<>();
- 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());
+ this.setRating(issueModelRequest.getRating());
}
- 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());
+ this.setRating(issueModelRequest.getRating());
}
public String toString() {
- return this.getId().toString() + this.getDescription();
+ return this.getId().toString() + this.getDescription() + this.getComments().toString();
}
-}
+
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java
similarity index 66%
rename from src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueRating.java
rename to src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java
index 14a4a80..38c46d3 100644
--- a/src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueRating.java
+++ b/src/main/java/io/github/patternatlas/api/entities/issue/IssueRating.java
@@ -1,13 +1,14 @@
-package io.github.patternatlas.api.entities.issue.rating;
+package io.github.patternatlas.api.entities.issue;
import java.util.Objects;
+
+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 io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.issue.Issue;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -19,10 +20,10 @@ public class IssueRating {
@EmbeddedId
@EqualsAndHashCode.Include
- private IssueRatingKey id;
+ private CompositeKey id;
@ManyToOne
- @MapsId("issueId")
+ @MapsId("entityId")
@EqualsAndHashCode.Include
private Issue issue;
@@ -36,7 +37,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
@@ -49,9 +59,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/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java b/src/main/java/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java
new file mode 100644
index 0000000..26f2000
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/issue/author/IssueAuthor.java
@@ -0,0 +1,47 @@
+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 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/io/github/patternatlas/api/entities/issue/IssueComment.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java
similarity index 64%
rename from src/main/java/io/github/patternatlas/api/entities/issue/IssueComment.java
rename to src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java
index d023e79..a343681 100644
--- a/src/main/java/io/github/patternatlas/api/entities/issue/IssueComment.java
+++ b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueComment.java
@@ -1,19 +1,19 @@
-package io.github.patternatlas.api.entities.issue;
+package io.github.patternatlas.api.entities.issue.comment;
import java.io.Serializable;
-import java.util.HashSet;
-import java.util.Set;
+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 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 com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import io.github.patternatlas.api.entities.issue.rating.IssueCommentRating;
-import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.shared.Comment;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -30,16 +30,18 @@ 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 Set userRating = new HashSet<>();
+ private List userRating = new ArrayList<>();
+
+ private int rating = 0;
+
+ public IssueComment(String text, Issue issue, UserEntity user) {
+ super(text, user);
+ this.issue = issue;
+ }
- public IssueComment(String text) {
- super(text);
+ public void updateComment(String text) {
+ this.setText(text);
}
}
diff --git a/src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueCommentRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java
similarity index 75%
rename from src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueCommentRating.java
rename to src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java
index 4e84366..f671a90 100644
--- a/src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueCommentRating.java
+++ b/src/main/java/io/github/patternatlas/api/entities/issue/comment/IssueCommentRating.java
@@ -1,4 +1,4 @@
-package io.github.patternatlas.api.entities.issue.rating;
+package io.github.patternatlas.api.entities.issue.comment;
import java.util.Objects;
import javax.persistence.EmbeddedId;
@@ -7,7 +7,9 @@
import javax.persistence.MapsId;
import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.issue.IssueComment;
+import io.github.patternatlas.api.entities.issue.comment.IssueComment;
+import io.github.patternatlas.api.entities.shared.CompositeKey;
+
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -19,10 +21,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 +38,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/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java
new file mode 100644
index 0000000..bd7ba6c
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidence.java
@@ -0,0 +1,56 @@
+package io.github.patternatlas.api.entities.issue.evidence;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+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;
+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/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java
new file mode 100644
index 0000000..5173acf
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/issue/evidence/IssueEvidenceRating.java
@@ -0,0 +1,70 @@
+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 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/io/github/patternatlas/api/entities/issue/rating/IssueCommentRatingKey.java b/src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueCommentRatingKey.java
deleted file mode 100644
index c635bcf..0000000
--- a/src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueCommentRatingKey.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package io.github.patternatlas.api.entities.issue.rating;
-
-import java.io.Serializable;
-import java.util.UUID;
-import javax.persistence.Embeddable;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-
-@Embeddable
-@NoArgsConstructor
-@AllArgsConstructor
-@Data
-@EqualsAndHashCode(callSuper = false)
-public class IssueCommentRatingKey implements Serializable {
-
- protected UUID issueCommentId;
- protected UUID userId;
-}
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
new file mode 100644
index 0000000..683ab33
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/shared/AuthorConstant.java
@@ -0,0 +1,7 @@
+package io.github.patternatlas.api.entities.shared;
+
+public interface AuthorConstant {
+ String OWNER = "OWNER";
+ String MAINTAINER = "MAINTAINER";
+ String HELPER = "HELPER";
+}
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 0cf62b8..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,10 +26,14 @@ public abstract class Comment {
private String text;
- private int rating = 0;
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ @ToString.Exclude
+ @ManyToOne
+ private UserEntity user;
- public Comment(String text) {
+ public Comment(String text, UserEntity user) {
this.text = text;
+ this.user = user;
}
@Override
@@ -32,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
@@ -42,6 +53,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/io/github/patternatlas/api/entities/issue/rating/IssueRatingKey.java b/src/main/java/io/github/patternatlas/api/entities/shared/CompositeKey.java
similarity index 70%
rename from src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueRatingKey.java
rename to src/main/java/io/github/patternatlas/api/entities/shared/CompositeKey.java
index 9522921..b62b247 100644
--- a/src/main/java/io/github/patternatlas/api/entities/issue/rating/IssueRatingKey.java
+++ b/src/main/java/io/github/patternatlas/api/entities/shared/CompositeKey.java
@@ -1,4 +1,4 @@
-package io.github.patternatlas.api.entities.issue.rating;
+package io.github.patternatlas.api.entities.shared;
import java.io.Serializable;
import java.util.UUID;
@@ -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/io/github/patternatlas/api/entities/shared/Evidence.java b/src/main/java/io/github/patternatlas/api/entities/shared/Evidence.java
new file mode 100644
index 0000000..8e5ae3d
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/shared/Evidence.java
@@ -0,0 +1,53 @@
+package io.github.patternatlas.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/io/github/patternatlas/api/entities/user/UserEntity.java b/src/main/java/io/github/patternatlas/api/entities/user/UserEntity.java
index 679cb31..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
@@ -2,59 +2,63 @@
import java.io.Serializable;
import java.util.ArrayList;
-import java.util.Arrays;
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.ElementCollection;
import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
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;
-import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType;
-import io.github.patternatlas.api.entities.candidate.CandidateComment;
-import io.github.patternatlas.api.entities.candidate.rating.CandidateRating;
-import io.github.patternatlas.api.entities.issue.IssueComment;
-import io.github.patternatlas.api.entities.issue.rating.IssueRating;
+import io.github.patternatlas.api.entities.candidate.CandidateRating;
+import io.github.patternatlas.api.entities.candidate.comment.CandidateComment;
+import io.github.patternatlas.api.entities.candidate.author.CandidateAuthor;
+import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidence;
+import io.github.patternatlas.api.entities.issue.comment.IssueComment;
+import io.github.patternatlas.api.entities.issue.author.IssueAuthor;
+import io.github.patternatlas.api.entities.issue.IssueRating;
+import io.github.patternatlas.api.entities.issue.evidence.IssueEvidence;
+import io.github.patternatlas.api.entities.user.role.Role;
+import io.github.patternatlas.api.rest.model.user.UserModel;
+
import lombok.Data;
import lombok.NoArgsConstructor;
+import lombok.ToString;
@Entity
@Data
@NoArgsConstructor
-@TypeDef(name = "pgsql_enum", typeClass = PostgreSQLEnumType.class)
-public class UserEntity implements Serializable {
+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;
- @Enumerated(EnumType.STRING)
- @ElementCollection
- @Type(type = "pgsql_enum")
- private List roles = new ArrayList<>(Arrays.asList(UserRole.MEMBER));
+ @JsonIgnore
+ @ToString.Exclude
+ @ManyToMany()
+ private Set roles;
- @NaturalId(mutable = true)
- @Column(nullable = false, unique = true)
+ @Column(nullable = false, unique = false)
private String email;
+ @NaturalId(mutable = true)
+ @Column(nullable = false, unique = true)
private String name;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@@ -63,6 +67,10 @@ public class UserEntity implements Serializable {
/**
* 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<>();
@@ -71,9 +79,15 @@ public class UserEntity implements Serializable {
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List issueComments = new ArrayList<>();
- /**
- * Candidate fields
- */
+ @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)
+ private Set candidates = new HashSet<>();
+
@JsonIgnore
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private Set candidateRatings = new HashSet<>();
@@ -82,27 +96,31 @@ public class UserEntity implements Serializable {
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List candidateComments = 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(String name, String email, String password) {
- this.name = name;
- this.email = email;
- this.password = password;
+ @JsonIgnore
+ @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
+ private List candidateEvidence = new ArrayList<>();
+
+ /** Pattern fields*/
+
+ public UserEntity(UserModel userModel, String password) {
+ this(userModel.getName(), userModel.getEmail(), password, null);
+ this.id = userModel.getId();
}
- public UserEntity(String name, String email, String password, List roles) {
+ public UserEntity(String name, String email, String password, Set roles) {
this.name = name;
this.email = email;
this.password = password;
this.roles = roles;
+
+ if(this.roles == null) {
+ this.roles = new HashSet<>();
+ }
+ }
+
+ public void updateUserEntity(UserModel userModel) {
+ this.setName(userModel.getName());
+ this.setEmail(userModel.getEmail());
}
@Override
@@ -124,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/UserRole.java b/src/main/java/io/github/patternatlas/api/entities/user/UserRole.java
deleted file mode 100644
index de7a4e7..0000000
--- a/src/main/java/io/github/patternatlas/api/entities/user/UserRole.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package io.github.patternatlas.api.entities.user;
-
-public enum UserRole {
- MEMBER,
- EXPERT,
- AUTHOR,
- LIBRARIAN,
- ADMIN
-}
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
new file mode 100644
index 0000000..fdc90ff
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Privilege.java
@@ -0,0 +1,52 @@
+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 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/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java
new file mode 100644
index 0000000..cfec2a8
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/user/role/PrivilegeConstant.java
@@ -0,0 +1,72 @@
+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";
+ 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_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_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_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_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_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_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/entities/user/role/Role.java b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java
new file mode 100644
index 0000000..c265955
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/user/role/Role.java
@@ -0,0 +1,59 @@
+package io.github.patternatlas.api.entities.user.role;
+
+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 java.util.Set;
+import java.util.UUID;
+import java.util.Collection;
+
+@Entity
+@Data
+@NoArgsConstructor
+public class Role {
+
+ @Id
+ @GeneratedValue(generator = "pg-uuid")
+ private UUID id;
+
+ @Column(unique = true)
+ private String name;
+
+ @ManyToMany(mappedBy = "roles")
+ private Set users;
+
+ @ManyToMany(cascade = CascadeType.ALL)
+ private Collection privileges;
+
+ 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;
+ }
+
+ public void removePrivilege(Privilege privilege) {
+ this.privileges.remove(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/entities/user/role/RoleConstant.java b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java
new file mode 100644
index 0000000..37400e6
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/entities/user/role/RoleConstant.java
@@ -0,0 +1,32 @@
+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";
+ 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";
+ public static final String GUEST = "GUEST";
+
+ public static List PLATFORM_ROLES = Arrays.asList(
+ RoleConstant.ADMIN,
+ RoleConstant.MEMBER,
+ RoleConstant.EXPERT,
+ RoleConstant.LIBRARIAN,
+ RoleConstant.GUEST
+ );
+
+ public static List AUTHOR_ROLES = Arrays.asList(
+ RoleConstant.HELPER,
+ RoleConstant.MAINTAINER,
+ RoleConstant.OWNER
+ );
+
+}
+
diff --git a/src/main/java/io/github/patternatlas/api/exception/CandidateNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/CandidateNotFoundException.java
deleted file mode 100644
index badfb7f..0000000
--- a/src/main/java/io/github/patternatlas/api/exception/CandidateNotFoundException.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package io.github.patternatlas.api.exception;
-
-import java.util.UUID;
-
-import org.springframework.data.rest.webmvc.ResourceNotFoundException;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-import lombok.NoArgsConstructor;
-
-@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/io/github/patternatlas/api/exception/CommentNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/CommentNotFoundException.java
deleted file mode 100644
index e131790..0000000
--- a/src/main/java/io/github/patternatlas/api/exception/CommentNotFoundException.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package io.github.patternatlas.api.exception;
-
-import java.util.UUID;
-
-import org.springframework.data.rest.webmvc.ResourceNotFoundException;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-import lombok.NoArgsConstructor;
-
-@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/io/github/patternatlas/api/exception/NullIssueException.java b/src/main/java/io/github/patternatlas/api/exception/NullIssueException.java
deleted file mode 100644
index 0de5244..0000000
--- a/src/main/java/io/github/patternatlas/api/exception/NullIssueException.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package io.github.patternatlas.api.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-import lombok.NoArgsConstructor;
-
-@NoArgsConstructor
-@ResponseStatus(HttpStatus.NOT_FOUND)
-public class NullIssueException extends RuntimeException {
- public NullIssueException(String message) {
- super(message);
- }
-}
diff --git a/src/main/java/io/github/patternatlas/api/exception/NullRoleException.java b/src/main/java/io/github/patternatlas/api/exception/NullRoleException.java
new file mode 100644
index 0000000..48d00e9
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/exception/NullRoleException.java
@@ -0,0 +1,12 @@
+package io.github.patternatlas.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/io/github/patternatlas/api/exception/IssueNotFoundException.java b/src/main/java/io/github/patternatlas/api/exception/RoleNotFoundException.java
similarity index 61%
rename from src/main/java/io/github/patternatlas/api/exception/IssueNotFoundException.java
rename to src/main/java/io/github/patternatlas/api/exception/RoleNotFoundException.java
index c5c6b17..d29a65f 100644
--- a/src/main/java/io/github/patternatlas/api/exception/IssueNotFoundException.java
+++ b/src/main/java/io/github/patternatlas/api/exception/RoleNotFoundException.java
@@ -10,13 +10,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/io/github/patternatlas/api/exception/UserAlreadyVotedException.java b/src/main/java/io/github/patternatlas/api/exception/UserAlreadyVotedException.java
deleted file mode 100644
index 7548861..0000000
--- a/src/main/java/io/github/patternatlas/api/exception/UserAlreadyVotedException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package io.github.patternatlas.api.exception;
-
-import java.util.UUID;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-import io.github.patternatlas.api.entities.PatternView;
-import lombok.NoArgsConstructor;
-
-@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/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java
new file mode 100644
index 0000000..e8a6eb2
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateAuthorRepository.java
@@ -0,0 +1,12 @@
+package io.github.patternatlas.api.repositories;
+
+import io.github.patternatlas.api.entities.candidate.author.CandidateAuthor;
+import io.github.patternatlas.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/io/github/patternatlas/api/repositories/CandidateCommentRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRatingRepository.java
index 82ac2b9..d9e1d26 100644
--- a/src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRatingRepository.java
+++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRatingRepository.java
@@ -1,15 +1,13 @@
package io.github.patternatlas.api.repositories;
+import io.github.patternatlas.api.entities.candidate.comment.CandidateCommentRating;
+import io.github.patternatlas.api.entities.shared.CompositeKey;
+
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
-import io.github.patternatlas.api.entities.candidate.CandidateComment;
-import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.candidate.rating.CandidateCommentRating;
-import io.github.patternatlas.api.entities.candidate.rating.CandidateCommentRatingKey;
-
@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/io/github/patternatlas/api/repositories/CandidateCommentRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRepository.java
index 04b5249..c397c67 100644
--- a/src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRepository.java
+++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateCommentRepository.java
@@ -5,7 +5,7 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
-import io.github.patternatlas.api.entities.candidate.CandidateComment;
+import io.github.patternatlas.api.entities.candidate.comment.CandidateComment;
@RepositoryRestResource(exported = false)
public interface CandidateCommentRepository 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
new file mode 100644
index 0000000..772880b
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRatingRepository.java
@@ -0,0 +1,11 @@
+package io.github.patternatlas.api.repositories;
+
+import io.github.patternatlas.api.entities.candidate.evidence.CandidateEvidenceRating;
+import io.github.patternatlas.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/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java
new file mode 100644
index 0000000..256a265
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateEvidenceRepository.java
@@ -0,0 +1,9 @@
+package io.github.patternatlas.api.repositories;
+
+import io.github.patternatlas.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/io/github/patternatlas/api/repositories/CandidateRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/CandidateRatingRepository.java
index a948481..60987bb 100644
--- a/src/main/java/io/github/patternatlas/api/repositories/CandidateRatingRepository.java
+++ b/src/main/java/io/github/patternatlas/api/repositories/CandidateRatingRepository.java
@@ -1,21 +1,16 @@
package io.github.patternatlas.api.repositories;
-import java.util.List;
+import io.github.patternatlas.api.entities.candidate.CandidateRating;
+import io.github.patternatlas.api.entities.shared.CompositeKey;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
-import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.candidate.Candidate;
-import io.github.patternatlas.api.entities.candidate.rating.CandidateRating;
-import io.github.patternatlas.api.entities.candidate.rating.CandidateRatingKey;
-
@RepositoryRestResource(exported = false)
-public interface CandidateRatingRepository extends JpaRepository {
-
- List findAllByCandidate(Candidate candidate);
-
- List findAllByUser(UserEntity user);
+public interface CandidateRatingRepository extends JpaRepository {
- CandidateRating findByCandidateAndUser(Candidate candidate, UserEntity user);
-}
+ boolean existsById(CompositeKey compositeKey);
+ boolean existsByIdAndReadability(CompositeKey compositeKey, int rating);
+ boolean existsByIdAndUnderstandability(CompositeKey compositeKey, int rating);
+ boolean existsByIdAndAppropriateness(CompositeKey compositeKey, int rating);
+}
\ No newline at end of file
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 44ac023..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;
@@ -11,7 +14,10 @@
@RepositoryRestResource(exported = false)
public interface CandidateRepository extends JpaRepository {
- Optional findByUri(String uri);
+ public Optional findByUri(String uri);
+ public boolean existsByUri(String uri);
+ public boolean existsByName(String name);
- boolean existsByUri(String uri);
+ @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/repositories/IssueAuthorRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueAuthorRepository.java
new file mode 100644
index 0000000..f26d18d
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/repositories/IssueAuthorRepository.java
@@ -0,0 +1,12 @@
+package io.github.patternatlas.api.repositories;
+
+import io.github.patternatlas.api.entities.issue.author.IssueAuthor;
+import io.github.patternatlas.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/io/github/patternatlas/api/repositories/IssueCommentRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueCommentRatingRepository.java
index efa9705..9eb2ed1 100644
--- a/src/main/java/io/github/patternatlas/api/repositories/IssueCommentRatingRepository.java
+++ b/src/main/java/io/github/patternatlas/api/repositories/IssueCommentRatingRepository.java
@@ -3,13 +3,16 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
-import io.github.patternatlas.api.entities.issue.rating.IssueCommentRating;
-import io.github.patternatlas.api.entities.issue.rating.IssueCommentRatingKey;
+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 io.github.patternatlas.api.entities.issue.IssueComment;
@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/io/github/patternatlas/api/repositories/IssueCommentRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueCommentRepository.java
index 3d99658..f343bef 100644
--- a/src/main/java/io/github/patternatlas/api/repositories/IssueCommentRepository.java
+++ b/src/main/java/io/github/patternatlas/api/repositories/IssueCommentRepository.java
@@ -5,7 +5,7 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
-import io.github.patternatlas.api.entities.issue.IssueComment;
+import io.github.patternatlas.api.entities.issue.comment.IssueComment;
@RepositoryRestResource(exported = false)
public interface IssueCommentRepository 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
new file mode 100644
index 0000000..0486604
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRatingRepository.java
@@ -0,0 +1,11 @@
+package io.github.patternatlas.api.repositories;
+
+import io.github.patternatlas.api.entities.issue.evidence.IssueEvidenceRating;
+import io.github.patternatlas.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/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java
new file mode 100644
index 0000000..9075312
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/repositories/IssueEvidenceRepository.java
@@ -0,0 +1,12 @@
+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 org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.UUID;
+
+public interface IssueEvidenceRepository extends JpaRepository {
+
+}
diff --git a/src/main/java/io/github/patternatlas/api/repositories/IssueRatingRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueRatingRepository.java
index d3122dc..067c1a2 100644
--- a/src/main/java/io/github/patternatlas/api/repositories/IssueRatingRepository.java
+++ b/src/main/java/io/github/patternatlas/api/repositories/IssueRatingRepository.java
@@ -1,21 +1,17 @@
package io.github.patternatlas.api.repositories;
-import java.util.List;
+import io.github.patternatlas.api.entities.issue.Issue;
+import io.github.patternatlas.api.entities.issue.IssueRating;
+import io.github.patternatlas.api.entities.shared.CompositeKey;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
-import io.github.patternatlas.api.entities.issue.rating.IssueRating;
-import io.github.patternatlas.api.entities.issue.rating.IssueRatingKey;
-import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.issue.Issue;
+import java.util.Collection;
@RepositoryRestResource(exported = false)
-public interface IssueRatingRepository extends JpaRepository {
-
- List findAllByIssue(Issue issue);
-
- List findAllByUser(UserEntity user);
+public interface IssueRatingRepository extends JpaRepository {
- IssueRating findByIssueAndUser(Issue issue, UserEntity user);
-}
+ boolean existsByIdAndRating(CompositeKey compositeKey, int rating);
+ Collection findAllByIssue(Issue issue);
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/patternatlas/api/repositories/IssueRepository.java b/src/main/java/io/github/patternatlas/api/repositories/IssueRepository.java
index b867e5b..1970c5d 100644
--- a/src/main/java/io/github/patternatlas/api/repositories/IssueRepository.java
+++ b/src/main/java/io/github/patternatlas/api/repositories/IssueRepository.java
@@ -11,7 +11,7 @@
@RepositoryRestResource(exported = false)
public interface IssueRepository extends JpaRepository {
- Optional findByUri(String uri);
-
- boolean existsByUri(String uri);
+ public Optional findByUri(String uri);
+ public boolean existsByUri(String uri);
+ public boolean existsByName(String name);
}
diff --git a/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java
new file mode 100644
index 0000000..fe14991
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/repositories/PrivilegeRepository.java
@@ -0,0 +1,40 @@
+package io.github.patternatlas.api.repositories;
+
+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 java.util.Optional;
+import java.util.UUID;
+import java.util.List;
+
+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 '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)
+ 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);
+
+ @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/repositories/RoleRepository.java b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java
new file mode 100644
index 0000000..e16d901
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/repositories/RoleRepository.java
@@ -0,0 +1,47 @@
+package io.github.patternatlas.api.repositories;
+
+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 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);
+
+ @Query(value = "SELECT * from role r where r.name like %:entityId and r.name like :authorRole%", nativeQuery = true)
+ 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)
+ 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/repositories/UserRepository.java b/src/main/java/io/github/patternatlas/api/repositories/UserRepository.java
index 26e0803..e8c43e0 100644
--- a/src/main/java/io/github/patternatlas/api/repositories/UserRepository.java
+++ b/src/main/java/io/github/patternatlas/api/repositories/UserRepository.java
@@ -2,6 +2,8 @@
import java.util.UUID;
+import org.apache.catalina.User;
+
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
@@ -9,5 +11,5 @@
@RepositoryRestResource(exported = false)
public interface UserRepository extends JpaRepository {
-
+ UserEntity findByEmail(String email);
}
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
new file mode 100644
index 0000000..c768672
--- /dev/null
+++ b/src/main/java/io/github/patternatlas/api/rest/controller/AuthorController.java
@@ -0,0 +1,51 @@
+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.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.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")
+public class AuthorController {
+
+ private UserService userService;
+
+ public AuthorController(
+ UserService userService
+ ) {
+ this.userService = userService;
+ }
+
+ /**
+ * 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")
+ @GetMapping(value = "")
+ CollectionModel> getAll() {
+ List> authors = this.userService.getAllUsers()
+ .stream()
+ .map(user -> new EntityModel<>(new AuthorModel(user)))
+ .collect(Collectors.toList());
+ 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.HELPER, AuthorConstant.MAINTAINER, AuthorConstant.OWNER};
+ }
+}
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 e89e56a..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
@@ -1,16 +1,28 @@
package io.github.patternatlas.api.rest.controller;
-import java.util.List;
-import java.util.UUID;
-import java.util.stream.Collectors;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+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.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.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
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.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -18,19 +30,14 @@
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 com.fasterxml.jackson.databind.ObjectMapper;
-
-import io.github.patternatlas.api.rest.model.CandidateModel;
-import io.github.patternatlas.api.entities.candidate.Candidate;
-import io.github.patternatlas.api.entities.candidate.CandidateComment;
-import io.github.patternatlas.api.service.CandidateService;
-import io.github.patternatlas.api.service.PatternLanguageService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import java.security.Principal;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
@RestController
@RequestMapping(value = "/candidates", produces = "application/hal+json")
@@ -38,9 +45,9 @@ public class CandidateController {
Logger logger = LoggerFactory.getLogger(CandidateController.class);
- private final CandidateService candidateService;
- private final PatternLanguageService patternLanguageService;
- private final ObjectMapper objectMapper;
+ private CandidateService candidateService;
+ private PatternLanguageService patternLanguageService;
+ private ObjectMapper objectMapper;
public CandidateController(
CandidateService candidateService,
@@ -55,29 +62,36 @@ 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()
- .stream()
- .map(candidate -> new EntityModel<>(CandidateModel.from(candidate)))
-// getPatternViewLinks(patternView)))
- .collect(Collectors.toList());
+ 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());
+ } else {
+ candidates = this.candidateService.getAllCandidatesByLanguageId(languageId)
+ .stream()
+ .map(candidate -> new EntityModel<>(new CandidateModel(candidate)))
+ .collect(Collectors.toList());
+ }
return new CollectionModel<>(candidates);
}
@Operation(operationId = "getCandidateById", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by id")
@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))));
}
@Operation(operationId = "getCandidateByURI", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Retrieve a single candidate by URI")
- @GetMapping(value = "/?uri={candidateUri}")
- Candidate getCandidateByUri(@PathVariable String candidateUri) {
- return this.candidateService.getCandidateByURI(candidateUri);
+ @GetMapping(value = "/findByUri")
+ ResponseEntity> getCandidateByUri(@RequestParam("uri") String candidateUri) {
+ return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.getCandidateByURI(candidateUri))));
}
/**
@@ -86,15 +100,22 @@ Candidate getCandidateByUri(@PathVariable String candidateUri) {
@Operation(operationId = "createCandidate", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate")
@PostMapping(value = "")
@ResponseStatus(HttpStatus.CREATED)
- Candidate newCandidate(@RequestBody CandidateModel candidate) {
- return this.candidateService.createCandidate(candidate);
+ ResponseEntity> newCandidate(@RequestBody CandidateModelRequest candidateModelRequest, Principal principal) {
+ return ResponseEntity.ok(new EntityModel<>(new CandidateModel(this.candidateService.createCandidate(candidateModelRequest, UUID.fromString(principal.getName())))));
}
@Operation(operationId = "createCandidateComment", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate comment")
- @PostMapping(value = "/{candidateId}/comments/{userId}")
+ @PostMapping(value = "/{candidateId}/comments")
+ @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))));
+ }
+
+ @Operation(operationId = "createCandidateEvidence", responses = {@ApiResponse(responseCode = "201")}, description = "Create a candidate evidence")
+ @PostMapping(value = "/{candidateId}/evidences")
@ResponseStatus(HttpStatus.CREATED)
- Candidate newCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID userId, @RequestBody CandidateComment candidateComment) {
- return this.candidateService.createComment(candidateId, userId, candidateComment);
+ 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))));
}
/**
@@ -102,21 +123,47 @@ Candidate newCandidateComment(@PathVariable UUID candidateId, @PathVariable UUID
*/
@Operation(operationId = "updateCandidate", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate")
@PutMapping(value = "/{candidateId}")
- Candidate putCandidate(@PathVariable UUID candidateId, @RequestBody Candidate candidate) {
- logger.info(candidate.toString());
- return this.candidateService.updateCandidate(candidate);
+ @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))));
}
- @Operation(operationId = "updateCandidateRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update rating of a 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);
+ @Operation(operationId = "updateCandidateRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update a candidate rating")
+ @PutMapping(value = "/{candidateId}/ratings")
+ 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 = "updateCandidateCommentRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update rating of a candidate comment")
- @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);
+ @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}")
+ @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))));
+ }
+
+ @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, 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}")
+ @ResponseStatus(HttpStatus.ACCEPTED)
+ 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")
+ 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))));
}
/**
@@ -124,9 +171,29 @@ Candidate putCandidateCommentRating(@PathVariable UUID candidateCommentId, @Path
*/
@Operation(operationId = "deleteCandidateById", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate by id")
@DeleteMapping(value = "/{candidateId}")
-// @PreAuthorize(value = "#oauth2.hasScope('de')")
- ResponseEntity> deleteCandidate(@PathVariable UUID candidateId) {
- this.candidateService.deleteCandidate(candidateId);
+ @ResponseStatus(HttpStatus.OK)
+ ResponseEntity> deleteCandidate(@PathVariable UUID candidateId, 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}")
+ @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())))));
+ }
+
+ @Operation(operationId = "deleteCandidateEvidence", responses = {@ApiResponse(responseCode = "204")}, description = "Delete candidate evidence")
+ @DeleteMapping(value = "/{candidateId}/evidences/{candidateEvidenceId}")
+ @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())))));
+ }
+}
\ No newline at end of file
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")
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 {
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 {
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 11fad87..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
@@ -1,13 +1,28 @@
package io.github.patternatlas.api.rest.controller;
+import java.security.Principal;
import java.util.List;
import java.util.UUID;
+import java.util.stream.Collectors;
+
+import io.github.patternatlas.api.rest.model.issue.IssueModel;
+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 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.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -15,27 +30,19 @@
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 com.fasterxml.jackson.databind.ObjectMapper;
-
-import io.github.patternatlas.api.entities.issue.Issue;
-import io.github.patternatlas.api.entities.issue.IssueComment;
-import io.github.patternatlas.api.service.IssueService;
-import io.github.patternatlas.api.service.PatternLanguageService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-
@RestController
@RequestMapping(value = "/issues", produces = "application/hal+json")
public class IssueController {
Logger logger = LoggerFactory.getLogger(IssueController.class);
- private final IssueService issueService;
- private final PatternLanguageService patternLanguageService;
- private final ObjectMapper objectMapper;
+ private IssueService issueService;
+ private PatternLanguageService patternLanguageService;
+ private ObjectMapper objectMapper;
public IssueController(
IssueService issueService,
@@ -50,23 +57,29 @@ 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 = "")
- List all() {
- return this.issueService.getAllIssues();
+ CollectionModel> getAll() {
+ List> issues = this.issueService.getAllIssues()
+ .stream()
+ .map(issue -> new EntityModel<>(new IssueModel(issue)))
+ .sorted((i1, i2) -> Integer.compare(i2.getContent().getRating(), i1.getContent().getRating()))
+ .collect(Collectors.toList());
+ return CollectionModel.of(issues);
}
@Operation(operationId = "getIssueById", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by id")
@GetMapping(value = "/{issueId}")
- @PreAuthorize(value = "#oauth2.hasScope('read')")
- Issue getIssueById(@PathVariable UUID issueId) {
- return this.issueService.getIssueById(issueId);
- }
-
- @Operation(operationId = "getIssueByURI", responses = {@ApiResponse(responseCode = "200")}, description = "Retrieve issue by URI")
- @GetMapping(value = "/?uri={issueUri}")
- Issue getIssueByUri(@PathVariable String issueUri) {
- return this.issueService.getIssueByURI(issueUri);
+ ResponseEntity> getIssueById(@PathVariable UUID issueId) {
+ return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.getIssueById(issueId))));
}
/**
@@ -74,18 +87,23 @@ Issue getIssueByUri(@PathVariable String issueUri) {
*/
@Operation(operationId = "createIssue", responses = {@ApiResponse(responseCode = "201")}, description = "Create an issue")
@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, 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/{userId}")
-// @PreAuthorize(value = "#oauth2.hasScope('write')")
+ @PostMapping(value = "/{issueId}/comments")
@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, 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, Principal principal, @RequestBody EvidenceModel evidenceModel) {
+ return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.createEvidence(issueId, UUID.fromString(principal.getName()), evidenceModel))));
}
/**
@@ -93,21 +111,44 @@ Issue newIssueComment(@PathVariable UUID issueId, @PathVariable UUID userId, @Re
*/
@Operation(operationId = "updateIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue")
@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, 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, 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> 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, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) {
+ return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueCommentRating(issueId, issueCommentId, UUID.fromString(principal.getName()), ratingModelRequest))));
}
- @Operation(operationId = "updateIssueRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue rating")
- @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);
+ @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, Principal principal, @RequestBody EvidenceModel evidenceModel) {
+ return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateEvidence(issueId, issueEvidenceId, UUID.fromString(principal.getName()), evidenceModel))));
}
- @Operation(operationId = "updateIssueCommentRating", responses = {@ApiResponse(responseCode = "200")}, description = "Update an issue comment 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);
+ @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, Principal principal, @RequestBody RatingModelRequest ratingModelRequest) {
+ return ResponseEntity.ok(new EntityModel<>(new IssueModel(this.issueService.updateIssueEvidenceRating(issueId, issueEvidenceId, UUID.fromString(principal.getName()), ratingModelRequest))));
}
/**
@@ -115,9 +156,26 @@ Issue putIssueCommentRating(@PathVariable UUID issueCommentId, @PathVariable UUI
*/
@Operation(operationId = "deleteIssue", responses = {@ApiResponse(responseCode = "200")}, description = "Delete an issue")
@DeleteMapping(value = "/{issueId}")
-// @PreAuthorize(value = "#oauth2.hasScope('de')")
ResponseEntity> deleteIssue(@PathVariable UUID issueId) {
this.issueService.deleteIssue(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, 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, 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/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/PatternLanguageController.java b/src/main/java/io/github/patternatlas/api/rest/controller/PatternLanguageController.java
index bb68847..e7ddc23 100644
--- a/src/main/java/io/github/patternatlas/api/rest/controller/PatternLanguageController.java
+++ b/src/main/java/io/github/patternatlas/api/rest/controller/PatternLanguageController.java
@@ -39,7 +39,11 @@
import io.github.patternatlas.api.entities.PatternLanguage;
import io.github.patternatlas.api.entities.PatternSchema;
import io.github.patternatlas.api.rest.model.PatternLanguageModel;
+import io.github.patternatlas.api.rest.model.shared.PatternSchemaModel;
+import io.github.patternatlas.api.rest.model.PatternLanguageGraphModel;
+import io.github.patternatlas.api.rest.model.shared.PatternLanguageSchemaModel;
import io.github.patternatlas.api.service.PatternLanguageService;
+
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@@ -147,6 +151,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/io/github/patternatlas/api/rest/controller/UserController.java b/src/main/java/io/github/patternatlas/api/rest/controller/UserController.java
index 739d8c6..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
@@ -1,14 +1,33 @@
package io.github.patternatlas.api.rest.controller;
-import java.util.ArrayList;
-import java.util.Arrays;
+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.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;
+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 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 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.security.access.prepost.PreAuthorize;
+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;
@@ -17,18 +36,11 @@
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;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import io.github.patternatlas.api.entities.user.UserEntity;
-import io.github.patternatlas.api.entities.user.UserRole;
-import io.github.patternatlas.api.service.UserService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-
@RestController
@RequestMapping(value = "/users", produces = "application/hal+json")
public class UserController {
@@ -37,7 +49,7 @@ public class UserController {
private final UserService userService;
private final PasswordEncoder passwordEncoder;
- private final ObjectMapper objectMapper;
+ private ObjectMapper objectMapper;
public UserController(
UserService userService,
@@ -49,19 +61,118 @@ public UserController(
this.objectMapper = objectMapper;
}
+
/**
* 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 = "")
- @PreAuthorize(value = "hasAuthority('ADMIN')")
- List all() {
- return this.userService.getAllUsers();
+ @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());
+ // and )
+ return CollectionModel.of(users);
}
@GetMapping(value = "/{userId}")
- UserEntity getUserById(@PathVariable UUID userId) {
- return this.userService.getUserById(userId);
+ 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::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;
+ }
+
+ @GetMapping(value = "/roles")
+ CollectionModel> getAllRoles() {
+ List> roles = this.userService.getAllRoles()
+ .stream()
+ .map(role -> EntityModel.of(new RoleModel(role)))
+ .collect(Collectors.toList());
+ return CollectionModel.of(roles);
+ }
+
+ @GetMapping(value = "/roles/platform")
+ CollectionModel> getAllPlatformRoles() {
+ List> roles = this.userService.getAllPlatformRoles()
+ .stream()
+ .map(role -> EntityModel.of(new RoleModel(role)))
+ .collect(Collectors.toList());
+ return CollectionModel.of(roles);
+ }
+
+ @GetMapping(value = "/roles/authors")
+ CollectionModel> getAllAuthorRoles() {
+ List> roles = this.userService.getAllAuthorRoles()
+ .stream()
+ .map(role -> EntityModel.of(new RoleModel(role)))
+ .collect(Collectors.toList());
+ return CollectionModel.of(roles);
+ }
+
+ @GetMapping(value = "/roles/{entityId}")
+ CollectionModel> getAllRolesFromEntity(@PathVariable UUID entityId) {
+ List> roles = this.userService.getAllRolesFromEntity(entityId)
+ .stream()
+ .map(role -> EntityModel.of(new RoleModel(role)))
+ .collect(Collectors.toList());
+ return CollectionModel.of(roles);
+ }
+
+ @GetMapping(value = "/roles/privileges")
+ CollectionModel> getAllPlatformPrivileges() {
+ List> privileges = this.userService.getAllPlatformPrivileges()
+ .stream()
+ .map(privilege -> EntityModel.of(new PrivilegeModel(privilege)))
+ .collect(Collectors.toList());
+ return CollectionModel.of(privileges);
+ }
+
+ @GetMapping(value = "/roles/default_author_privileges")
+ CollectionModel> getAllDefaultAuthorPrivileges() {
+ List> privileges = this.userService.getAllDefaultAuthorPrivileges()
+ .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)
+ .stream()
+ .map(privilege -> EntityModel.of(new PrivilegeModel(privilege)))
+ .collect(Collectors.toList());
+ return CollectionModel.of(privileges);
}
/**
@@ -70,18 +181,8 @@ UserEntity getUserById(@PathVariable UUID userId) {
@Operation(operationId = "createUser", responses = {@ApiResponse(responseCode = "200")}, description = "Create a user")
@PostMapping(value = "")
@ResponseStatus(HttpStatus.CREATED)
- public UserEntity newUser(@RequestBody UserEntity user) {
- user.setPassword(passwordEncoder.encode(user.getPassword()));
- return this.userService.createUser(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);
+ ResponseEntity> newUser(@RequestBody UserModelRequest userModelRequest) {
+ return ResponseEntity.ok(EntityModel.of(new UserModel(this.userService.createUser(userModelRequest))));
}
/**
@@ -90,8 +191,39 @@ public void defaultUsers() {
@Operation(operationId = "updateUser", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Update a 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(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) {
+ 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")
+ @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);
}
/**
@@ -99,7 +231,8 @@ UserEntity updateUser(@PathVariable UUID userId, @RequestBody UserEntity user) {
*/
@Operation(operationId = "deleteUser", responses = {@ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "404", content = @Content)}, description = "Delete a user")
@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/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java b/src/main/java/io/github/patternatlas/api/rest/exception/RestResponseExceptionHandler.java
index eda1818..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,5 +1,14 @@
package io.github.patternatlas.api.rest.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;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -9,33 +18,35 @@
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
-import io.github.patternatlas.api.exception.NullPatternSchemaException;
-import io.github.patternatlas.api.rest.model.ErrorMessageDTO;
-
@ControllerAdvice
public class RestResponseExceptionHandler
extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = {
- ResourceNotFoundException.class
+ ResourceNotFoundException.class,
+ PatternLanguageNotFoundException.class,
+ PatternNotFoundException.class,
+ PatternSchemaNotFoundException.class,
+ PatternViewNotFoundException.class,
+ DirectedEdgeNotFoundException.class,
+ UndirectedEdgeNotFoundException.class
})
- protected ResponseEntity