From 84293063206746d9f81694c146abcb987c7bc4ef Mon Sep 17 00:00:00 2001 From: evrasouza <68034079+evrasouza@users.noreply.github.com> Date: Wed, 22 Dec 2021 21:27:19 -0300 Subject: [PATCH 1/5] Create README.md --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..195e6881 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +

Domínio e ORM, autorizações - Development Challenge

+

Competências

+

Domínio e ORM


+. Implementação de um modelo de domínio complexo (projeto DSLearn)
+. Instanciação (seed) de um modelo de domínio com SQL
+

Autorizações


+. Autorização customizada em nível de serviço
+. Conteúdo customizado para o usuário logado
+. Refresh token
+. Pré-autorização de métodos
+ +
+Implementado as funcionalidades necessárias para que os testes do projeto passem: https://github.com/evrasouza/bds05 +
+
+O que devo foi feito para resolver o desafio!
+-> Implementado o modelo conceitual, com seed do banco de dados.
+-> Incluído a infraestrutura de exceções, validação e segurança ao projeto.
+-> Implementar o endpoint GET /users/profile, para Obter o perfil do usuário logado
+
From 5d415b5b3fd0370c143818bfb7cfc4c4dfc97b12 Mon Sep 17 00:00:00 2001 From: evrasouza <68034079+evrasouza@users.noreply.github.com> Date: Wed, 22 Dec 2021 21:28:30 -0300 Subject: [PATCH 2/5] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 195e6881..510f62b7 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,4 @@ O que devo foi feito para resolver o desafio!
-> Incluído a infraestrutura de exceções, validação e segurança ao projeto.
-> Implementar o endpoint GET /users/profile, para Obter o perfil do usuário logado

+

Projeto finalizado na branch: https://github.com/evrasouza/bds05/tree/entregaTarefaMovieFlixDominioAutorizacao

From 318468432e7b606187925f7ff919bdef753d1da0 Mon Sep 17 00:00:00 2001 From: Everton Souza <68034079+evrasouza@users.noreply.github.com> Date: Thu, 6 Jan 2022 17:14:13 -0300 Subject: [PATCH 3/5] Update README.md --- README.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 510f62b7..88a865c0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

Domínio e ORM, autorizações - Development Challenge

+

Domínio e ORM, autorizações -Development Challenge- Chapter 4

Competências

Domínio e ORM


. Implementação de um modelo de domínio complexo (projeto DSLearn)
@@ -19,3 +19,21 @@ O que devo foi feito para resolver o desafio!
-> Implementar o endpoint GET /users/profile, para Obter o perfil do usuário logado

Projeto finalizado na branch: https://github.com/evrasouza/bds05/tree/entregaTarefaMovieFlixDominioAutorizacao

+ +

+

Consultas ao banco de dados -Development Challenge- Chapter 5

+

Competências

+

SQL e JPQL


+. Estudos de caso SQL e JPQL
+. Projeção, restrição, escalares
+. Joins
+. Group by
+. UNION
+

Spring Data JPA


+. Query methods
+. Estudo de caso: busca detalhada com parâmetros opcionais e paginação
+. Problema N+1 consultas
+. Refresh token
+. Pré-autorização de métodos
+
+

Projeto finalizado na branch: https://github.com/evrasouza/bds05/tree/entregaTarefaCapitulo5

From ac81a2969add77ae5193ec07c93fad5196fcd032 Mon Sep 17 00:00:00 2001 From: Everton Souza Date: Thu, 6 Jan 2022 18:02:25 -0300 Subject: [PATCH 4/5] First Commit - Challenge Chapter 5 --- .../movieflix/MovieflixApplication.java | 1 - .../components/JwtTokenEnhancer.java | 37 ++++ .../movieflix/config/AppConfig.java | 35 ++++ .../config/AuthorizationServerConfig.java | 83 ++++++++ .../config/ResourceServerConfig.java | 45 ++++ .../movieflix/config/WebSecurityConfig.java | 44 ++++ .../movieflix/controllers/UserController.java | 24 +++ .../controllers/exceptions/FieldMessage.java | 34 +++ .../exceptions/OAuthCustomError.java | 43 ++++ .../exceptions/ResourceExceptioHandler.java | 74 +++++++ .../controllers/exceptions/StandardError.java | 60 ++++++ .../exceptions/ValidationError.java | 20 ++ .../devsuperior/movieflix/dto/UserDTO.java | 53 +++++ .../devsuperior/movieflix/entities/Genre.java | 82 ++++++++ .../devsuperior/movieflix/entities/Movie.java | 140 +++++++++++++ .../movieflix/entities/Review.java | 100 +++++++++ .../devsuperior/movieflix/entities/Role.java | 71 +++++++ .../devsuperior/movieflix/entities/User.java | 164 +++++++++++++++ .../repositories/GenreRepository.java | 9 + .../repositories/MovieRepository.java | 9 + .../repositories/ReviewRepository.java | 9 + .../repositories/RoleRepository.java | 9 + .../repositories/UserRepository.java | 11 + .../movieflix/services/UserService.java | 51 +++++ .../exceptions/DatabaseException.java | 10 + .../exceptions/ForbiddenException.java | 12 ++ .../exceptions/ResourceNotFoundException.java | 10 + .../exceptions/UnauthorizedException.java | 10 + src/main/resources/application.properties | 8 +- src/main/resources/data.sql | 34 +++ .../controllers/GenreControllerIT.java | 91 ++++++++ .../controllers/MovieControllerIT.java | 198 ++++++++++++++++++ .../controllers/ReviewResourceIT.java | 141 +++++++++++++ .../movieflix/entities/RoleTests.java | 2 +- .../movieflix/entities/UserTests.java | 2 +- 35 files changed, 1722 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/devsuperior/movieflix/components/JwtTokenEnhancer.java create mode 100644 src/main/java/com/devsuperior/movieflix/config/AppConfig.java create mode 100644 src/main/java/com/devsuperior/movieflix/config/AuthorizationServerConfig.java create mode 100644 src/main/java/com/devsuperior/movieflix/config/ResourceServerConfig.java create mode 100644 src/main/java/com/devsuperior/movieflix/config/WebSecurityConfig.java create mode 100644 src/main/java/com/devsuperior/movieflix/controllers/UserController.java create mode 100644 src/main/java/com/devsuperior/movieflix/controllers/exceptions/FieldMessage.java create mode 100644 src/main/java/com/devsuperior/movieflix/controllers/exceptions/OAuthCustomError.java create mode 100644 src/main/java/com/devsuperior/movieflix/controllers/exceptions/ResourceExceptioHandler.java create mode 100644 src/main/java/com/devsuperior/movieflix/controllers/exceptions/StandardError.java create mode 100644 src/main/java/com/devsuperior/movieflix/controllers/exceptions/ValidationError.java create mode 100644 src/main/java/com/devsuperior/movieflix/dto/UserDTO.java create mode 100644 src/main/java/com/devsuperior/movieflix/entities/Genre.java create mode 100644 src/main/java/com/devsuperior/movieflix/entities/Movie.java create mode 100644 src/main/java/com/devsuperior/movieflix/entities/Review.java create mode 100644 src/main/java/com/devsuperior/movieflix/entities/Role.java create mode 100644 src/main/java/com/devsuperior/movieflix/entities/User.java create mode 100644 src/main/java/com/devsuperior/movieflix/repositories/GenreRepository.java create mode 100644 src/main/java/com/devsuperior/movieflix/repositories/MovieRepository.java create mode 100644 src/main/java/com/devsuperior/movieflix/repositories/ReviewRepository.java create mode 100644 src/main/java/com/devsuperior/movieflix/repositories/RoleRepository.java create mode 100644 src/main/java/com/devsuperior/movieflix/repositories/UserRepository.java create mode 100644 src/main/java/com/devsuperior/movieflix/services/UserService.java create mode 100644 src/main/java/com/devsuperior/movieflix/services/exceptions/DatabaseException.java create mode 100644 src/main/java/com/devsuperior/movieflix/services/exceptions/ForbiddenException.java create mode 100644 src/main/java/com/devsuperior/movieflix/services/exceptions/ResourceNotFoundException.java create mode 100644 src/main/java/com/devsuperior/movieflix/services/exceptions/UnauthorizedException.java create mode 100644 src/main/resources/data.sql create mode 100644 src/test/java/com/devsuperior/movieflix/controllers/GenreControllerIT.java create mode 100644 src/test/java/com/devsuperior/movieflix/controllers/MovieControllerIT.java create mode 100644 src/test/java/com/devsuperior/movieflix/controllers/ReviewResourceIT.java diff --git a/src/main/java/com/devsuperior/movieflix/MovieflixApplication.java b/src/main/java/com/devsuperior/movieflix/MovieflixApplication.java index d4bedff1..896e1ce9 100644 --- a/src/main/java/com/devsuperior/movieflix/MovieflixApplication.java +++ b/src/main/java/com/devsuperior/movieflix/MovieflixApplication.java @@ -9,5 +9,4 @@ public class MovieflixApplication { public static void main(String[] args) { SpringApplication.run(MovieflixApplication.class, args); } - } diff --git a/src/main/java/com/devsuperior/movieflix/components/JwtTokenEnhancer.java b/src/main/java/com/devsuperior/movieflix/components/JwtTokenEnhancer.java new file mode 100644 index 00000000..582c54ca --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/components/JwtTokenEnhancer.java @@ -0,0 +1,37 @@ +package com.devsuperior.movieflix.components; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; +import org.springframework.stereotype.Component; + +import com.devsuperior.movieflix.entities.User; +import com.devsuperior.movieflix.repositories.UserRepository; + +@Component +public class JwtTokenEnhancer implements TokenEnhancer{ + + @Autowired + private UserRepository userRepository; + + @Override + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { + + User user = userRepository.findByEmail(authentication.getName()); + + Map map = new HashMap<>(); + map.put("userName", user.getName()); + map.put("userId", user.getId()); + + DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken; + token.setAdditionalInformation(map); + + return token; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/config/AppConfig.java b/src/main/java/com/devsuperior/movieflix/config/AppConfig.java new file mode 100644 index 00000000..2170e4c2 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/config/AppConfig.java @@ -0,0 +1,35 @@ +package com.devsuperior.movieflix.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; + +@Configuration +public class AppConfig { + + @Value("${jwt.secret}") + private String jwtSecret; + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public JwtAccessTokenConverter accessTokenConverter() { + JwtAccessTokenConverter tokenConverter = new JwtAccessTokenConverter(); + tokenConverter.setSigningKey(jwtSecret); + return tokenConverter; + } + + @Bean + public JwtTokenStore tokenStore() { + return new JwtTokenStore(accessTokenConverter()); + } + + + +} diff --git a/src/main/java/com/devsuperior/movieflix/config/AuthorizationServerConfig.java b/src/main/java/com/devsuperior/movieflix/config/AuthorizationServerConfig.java new file mode 100644 index 00000000..f4ff3615 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/config/AuthorizationServerConfig.java @@ -0,0 +1,83 @@ +package com.devsuperior.movieflix.config; + +import java.util.Arrays; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; +import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; + +import com.devsuperior.movieflix.components.JwtTokenEnhancer; + +@Configuration +@EnableAuthorizationServer +public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { + + @Value("${security.oauth2.client.client-id}") + private String clientId; + + @Value("${security.oauth2.client.client-secret}") + private String clientSecret; + + @Value("${jwt.duration}") + private Integer jwtDuration; + + @Autowired + private BCryptPasswordEncoder passwordEncoder; + + @Autowired + private JwtAccessTokenConverter accessTokenConverter; + + @Autowired + private TokenStore tokenStore; + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private JwtTokenEnhancer tokenEnhancer; + + @Autowired + private UserDetailsService userDetailsService; + + @Override + public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { + security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()"); + } + + @Override + public void configure(ClientDetailsServiceConfigurer clients) throws Exception { + clients.inMemory() + .withClient(clientId) + .secret(passwordEncoder.encode(clientSecret)) + .scopes("read", "write") + .authorizedGrantTypes("password") + .accessTokenValiditySeconds(jwtDuration); + } + + @Override + public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { + + TokenEnhancerChain chain = new TokenEnhancerChain(); + chain.setTokenEnhancers(Arrays.asList(accessTokenConverter, tokenEnhancer)); + + endpoints.authenticationManager(authenticationManager) + .tokenStore(tokenStore) + .accessTokenConverter(accessTokenConverter) + .tokenEnhancer(chain) + .userDetailsService(userDetailsService); + } + + + +} diff --git a/src/main/java/com/devsuperior/movieflix/config/ResourceServerConfig.java b/src/main/java/com/devsuperior/movieflix/config/ResourceServerConfig.java new file mode 100644 index 00000000..15c861b0 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/config/ResourceServerConfig.java @@ -0,0 +1,45 @@ +package com.devsuperior.movieflix.config; + +import java.util.Arrays; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +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.token.store.JwtTokenStore; + +@Configuration +@EnableResourceServer +public class ResourceServerConfig extends ResourceServerConfigurerAdapter{ + + @Autowired + private Environment env; + + @Autowired + private JwtTokenStore tokenStore; + + private static final String[] PUBLIC = { "/oauth/token", "/h2-console/**" }; + + @Override + public void configure(ResourceServerSecurityConfigurer resources) throws Exception { + resources.tokenStore(tokenStore); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + + // H2 + if (Arrays.asList(env.getActiveProfiles()).contains("test")) { + http.headers().frameOptions().disable(); + } + + http.authorizeRequests() + .antMatchers(PUBLIC).permitAll() + .anyRequest().authenticated(); + + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/config/WebSecurityConfig.java b/src/main/java/com/devsuperior/movieflix/config/WebSecurityConfig.java new file mode 100644 index 00000000..1155dd0a --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/config/WebSecurityConfig.java @@ -0,0 +1,44 @@ +package com.devsuperior.movieflix.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private BCryptPasswordEncoder passwordEncoder; + + @Autowired + private UserDetailsService userDetailService; + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder); + super.configure(auth); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring().antMatchers("/actuator/**"); + } + + @Override + @Bean + protected AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/devsuperior/movieflix/controllers/UserController.java b/src/main/java/com/devsuperior/movieflix/controllers/UserController.java new file mode 100644 index 00000000..2cc77ec9 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/controllers/UserController.java @@ -0,0 +1,24 @@ +package com.devsuperior.movieflix.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.devsuperior.movieflix.dto.UserDTO; +import com.devsuperior.movieflix.services.UserService; + +@RestController +@RequestMapping(value = "/users") +public class UserController { + + @Autowired + private UserService service; + + @GetMapping(value = "/profile") + public ResponseEntity findCurrentUser(){ + UserDTO dto = service.findCurrentUser(); + return ResponseEntity.ok().body(dto); + } +} \ No newline at end of file diff --git a/src/main/java/com/devsuperior/movieflix/controllers/exceptions/FieldMessage.java b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/FieldMessage.java new file mode 100644 index 00000000..507526d0 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/FieldMessage.java @@ -0,0 +1,34 @@ +package com.devsuperior.movieflix.controllers.exceptions; + +import java.io.Serializable; + +public class FieldMessage implements Serializable { + private static final long serialVersionUID = 1L; + + private String fieldName; + private String message; + + public FieldMessage() {} + + public FieldMessage(String fieldName, String message) { + this.fieldName = fieldName; + this.message = message; + } + + public String getFieldName() { + return fieldName; + } + + public void setFieldName(String fieldName) { + this.fieldName = fieldName; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/controllers/exceptions/OAuthCustomError.java b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/OAuthCustomError.java new file mode 100644 index 00000000..d02762f3 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/OAuthCustomError.java @@ -0,0 +1,43 @@ +package com.devsuperior.movieflix.controllers.exceptions; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class OAuthCustomError implements Serializable { + private static final long serialVersionUID = 1L; + + private String error; + + @JsonProperty("error_description") + private String errorDescription; + + public OAuthCustomError() { + } + + public OAuthCustomError(String error, String errorDescription) { + super(); + this.error = error; + this.errorDescription = errorDescription; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getErrorDescription() { + return errorDescription; + } + + public void setErrorDescription(String errorDescription) { + this.errorDescription = errorDescription; + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/devsuperior/movieflix/controllers/exceptions/ResourceExceptioHandler.java b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/ResourceExceptioHandler.java new file mode 100644 index 00000000..1102e88c --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/ResourceExceptioHandler.java @@ -0,0 +1,74 @@ +package com.devsuperior.movieflix.controllers.exceptions; + +import java.time.Instant; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +import com.devsuperior.movieflix.services.exceptions.DatabaseException; +import com.devsuperior.movieflix.services.exceptions.ForbiddenException; +import com.devsuperior.movieflix.services.exceptions.ResourceNotFoundException; +import com.devsuperior.movieflix.services.exceptions.UnauthorizedException; + +@ControllerAdvice +public class ResourceExceptioHandler { + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity entityNotFound(ResourceNotFoundException e, HttpServletRequest request) { + HttpStatus status = HttpStatus.NOT_FOUND; + StandardError err = new StandardError(); + err.setTimestamp(Instant.now()); + err.setStatus(status.value()); + err.setError("Resource not found"); + err.setMessage(e.getMessage()); + err.setPath(request.getRequestURI()); + return ResponseEntity.status(status).body(err); + } + + @ExceptionHandler(DatabaseException.class) + public ResponseEntity database(DatabaseException e, HttpServletRequest request) { + HttpStatus status = HttpStatus.BAD_REQUEST; + StandardError err = new StandardError(); + err.setTimestamp(Instant.now()); + err.setStatus(status.value()); + err.setError("Database Exception"); + err.setMessage(e.getMessage()); + err.setPath(request.getRequestURI()); + return ResponseEntity.status(status).body(err); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity validation(MethodArgumentNotValidException e, HttpServletRequest request) { + HttpStatus status = HttpStatus.UNPROCESSABLE_ENTITY; + ValidationError err = new ValidationError(); + err.setTimestamp(Instant.now()); + err.setStatus(status.value()); + err.setError("Validation Exception"); + err.setMessage(e.getMessage()); + err.setPath(request.getRequestURI()); + + for (FieldError f : e.getBindingResult().getFieldErrors()) { + err.addError(f.getField(), f.getDefaultMessage()); + } + + return ResponseEntity.status(status).body(err); + } + + @ExceptionHandler(ForbiddenException.class) + public ResponseEntity forbidden(ForbiddenException e, HttpServletRequest request) { + OAuthCustomError err = new OAuthCustomError("Forbidden", e.getMessage()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(err); + } + + @ExceptionHandler(UnauthorizedException.class) + public ResponseEntity unauthorized(UnauthorizedException e, HttpServletRequest request) { + OAuthCustomError err = new OAuthCustomError("Unauthorized", e.getMessage()); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(err); + } +} diff --git a/src/main/java/com/devsuperior/movieflix/controllers/exceptions/StandardError.java b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/StandardError.java new file mode 100644 index 00000000..5c86a8ff --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/StandardError.java @@ -0,0 +1,60 @@ +package com.devsuperior.movieflix.controllers.exceptions; + +import java.io.Serializable; +import java.time.Instant; + +public class StandardError implements Serializable { + private static final long serialVersionUID = 1L; + + private Instant timestamp; + private Integer status; + private String error; + private String message; + private String path; + + public StandardError() {} + + public Instant getTimestamp() { + return timestamp; + } + + public void setTimestamp(Instant timestamp) { + this.timestamp = timestamp; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + + + +} diff --git a/src/main/java/com/devsuperior/movieflix/controllers/exceptions/ValidationError.java b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/ValidationError.java new file mode 100644 index 00000000..6e19f440 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/controllers/exceptions/ValidationError.java @@ -0,0 +1,20 @@ +package com.devsuperior.movieflix.controllers.exceptions; + +import java.util.ArrayList; +import java.util.List; + +public class ValidationError extends StandardError { + + private static final long serialVersionUID = 1L; + + private List errors = new ArrayList<>(); + + public List getErrors() { + return errors; + } + + public void addError(String fieldName, String message) { + errors.add(new FieldMessage(fieldName, message)); + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/dto/UserDTO.java b/src/main/java/com/devsuperior/movieflix/dto/UserDTO.java new file mode 100644 index 00000000..226f6716 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/dto/UserDTO.java @@ -0,0 +1,53 @@ +package com.devsuperior.movieflix.dto; + +import java.io.Serializable; + +import com.devsuperior.movieflix.entities.User; + +public class UserDTO implements Serializable{ + private static final long serialVersionUID = 1L; + + private Long id; + private String name; + private String email; + + public UserDTO() { + } + + public UserDTO(Long id, String name, String email) { + this.id = id; + this.name = name; + this.email = email; + } + + public UserDTO(User entity) { + id = entity.getId(); + name = entity.getName(); + email = entity.getEmail(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/entities/Genre.java b/src/main/java/com/devsuperior/movieflix/entities/Genre.java new file mode 100644 index 00000000..d11ffb29 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/entities/Genre.java @@ -0,0 +1,82 @@ +package com.devsuperior.movieflix.entities; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +@Entity +@Table(name = "tb_genre") +public class Genre implements Serializable{ + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + + @OneToMany(mappedBy = "genre") + private List movies = new ArrayList<>(); + + public Genre() { + } + + public Genre(Long id, String name) { + super(); + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getMovies() { + return movies; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Genre other = (Genre) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/entities/Movie.java b/src/main/java/com/devsuperior/movieflix/entities/Movie.java new file mode 100644 index 00000000..75708f13 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/entities/Movie.java @@ -0,0 +1,140 @@ +package com.devsuperior.movieflix.entities; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +@Entity +@Table(name = "tb_movie") +public class Movie implements Serializable{ + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String title; + private String subTitle; + private Integer year; + private String imgUrl; + + @Column(columnDefinition = "TEXT") + private String synopsis; + + @ManyToOne + @JoinColumn(name = "genre_id") + private Genre genre; + + @OneToMany(mappedBy = "movie") + private List reviews = new ArrayList<>(); + + public Movie() { + } + + public Movie(Long id, String title, String subTitle, Integer year, String imgUrl, String synopsis, Genre genre) { + super(); + this.id = id; + this.title = title; + this.subTitle = subTitle; + this.year = year; + this.imgUrl = imgUrl; + this.synopsis = synopsis; + this.genre = genre; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getSubTitle() { + return subTitle; + } + + public void setSubTitle(String subTitle) { + this.subTitle = subTitle; + } + + public Integer getYear() { + return year; + } + + public void setYear(Integer year) { + this.year = year; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getSynopsis() { + return synopsis; + } + + public void setSynopsis(String synopsis) { + this.synopsis = synopsis; + } + + public Genre getGenre() { + return genre; + } + + public void setGenre(Genre genre) { + this.genre = genre; + } + + public List getReviews() { + return reviews; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Movie other = (Movie) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/entities/Review.java b/src/main/java/com/devsuperior/movieflix/entities/Review.java new file mode 100644 index 00000000..8bff235b --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/entities/Review.java @@ -0,0 +1,100 @@ +package com.devsuperior.movieflix.entities; + +import java.io.Serializable; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "tb_review") +public class Review implements Serializable{ + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String text; + + @ManyToOne + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne + @JoinColumn(name = "movie_id") + private Movie movie; + + public Review() { + } + + public Review(Long id, String text, User user, Movie movie) { + super(); + this.id = id; + this.text = text; + this.user = user; + this.movie = movie; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public Movie getMovie() { + return movie; + } + + public void setMovie(Movie movie) { + this.movie = movie; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Review other = (Review) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/entities/Role.java b/src/main/java/com/devsuperior/movieflix/entities/Role.java new file mode 100644 index 00000000..f106bd81 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/entities/Role.java @@ -0,0 +1,71 @@ +package com.devsuperior.movieflix.entities; + +import java.io.Serializable; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "tb_role") +public class Role implements Serializable{ + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String authority; + + public Role() { + } + + public Role(Long id, String authority) { + this.id = id; + this.authority = authority; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAuthority() { + return authority; + } + + public void setAuthority(String authority) { + this.authority = authority; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Role other = (Role) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/entities/User.java b/src/main/java/com/devsuperior/movieflix/entities/User.java new file mode 100644 index 00000000..35a2c9aa --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/entities/User.java @@ -0,0 +1,164 @@ +package com.devsuperior.movieflix.entities; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + + +@Entity +@Table(name = "tb_user") +public class User implements UserDetails, Serializable{ + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + private String email; + private String password; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "tb_user_role", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "role_id")) + private Set roles = new HashSet<>(); + + @OneToMany(mappedBy = "user") + private List reviews = new ArrayList<>(); + + public User() { + } + + public User(Long id, String name, String email, String password) { + super(); + this.id = id; + this.name = name; + this.email = email; + this.password = password; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Set getRoles() { + return roles; + } + + public List getReviews() { + return reviews; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + User other = (User) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + + @Override + public Collection getAuthorities() { + return roles.stream().map(role -> new SimpleGrantedAuthority(role.getAuthority())).collect(Collectors.toList()); + } + + @Override + public String getUsername() { + return email; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + public boolean hasRole(String roleName) { + for(Role role: roles) { + if(role.getAuthority().equals(roleName)) { + return true; + } + } + return false; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/repositories/GenreRepository.java b/src/main/java/com/devsuperior/movieflix/repositories/GenreRepository.java new file mode 100644 index 00000000..de3e6de9 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/repositories/GenreRepository.java @@ -0,0 +1,9 @@ +package com.devsuperior.movieflix.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.devsuperior.movieflix.entities.Genre; + +public interface GenreRepository extends JpaRepository { + +} diff --git a/src/main/java/com/devsuperior/movieflix/repositories/MovieRepository.java b/src/main/java/com/devsuperior/movieflix/repositories/MovieRepository.java new file mode 100644 index 00000000..f64f3bb2 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/repositories/MovieRepository.java @@ -0,0 +1,9 @@ +package com.devsuperior.movieflix.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.devsuperior.movieflix.entities.Movie; + +public interface MovieRepository extends JpaRepository { + +} diff --git a/src/main/java/com/devsuperior/movieflix/repositories/ReviewRepository.java b/src/main/java/com/devsuperior/movieflix/repositories/ReviewRepository.java new file mode 100644 index 00000000..73bfccef --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/repositories/ReviewRepository.java @@ -0,0 +1,9 @@ +package com.devsuperior.movieflix.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.devsuperior.movieflix.entities.Review; + +public interface ReviewRepository extends JpaRepository { + +} diff --git a/src/main/java/com/devsuperior/movieflix/repositories/RoleRepository.java b/src/main/java/com/devsuperior/movieflix/repositories/RoleRepository.java new file mode 100644 index 00000000..4c460621 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/repositories/RoleRepository.java @@ -0,0 +1,9 @@ +package com.devsuperior.movieflix.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.devsuperior.movieflix.entities.Role; + +public interface RoleRepository extends JpaRepository { + +} diff --git a/src/main/java/com/devsuperior/movieflix/repositories/UserRepository.java b/src/main/java/com/devsuperior/movieflix/repositories/UserRepository.java new file mode 100644 index 00000000..af1d2dc1 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/repositories/UserRepository.java @@ -0,0 +1,11 @@ +package com.devsuperior.movieflix.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.devsuperior.movieflix.entities.User; + +public interface UserRepository extends JpaRepository { + + User findByEmail(String email); + +} diff --git a/src/main/java/com/devsuperior/movieflix/services/UserService.java b/src/main/java/com/devsuperior/movieflix/services/UserService.java new file mode 100644 index 00000000..553f6635 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/services/UserService.java @@ -0,0 +1,51 @@ +package com.devsuperior.movieflix.services; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.devsuperior.movieflix.dto.UserDTO; +import com.devsuperior.movieflix.entities.User; +import com.devsuperior.movieflix.repositories.UserRepository; +import com.devsuperior.movieflix.services.exceptions.UnauthorizedException; + + +@Service +public class UserService implements UserDetailsService{ + + private static Logger logger = LoggerFactory.getLogger(UserService.class); + + @Autowired + private UserRepository repository; + + + @Transactional(readOnly = true) + public UserDTO findCurrentUser() { + try { + String username = SecurityContextHolder.getContext().getAuthentication().getName(); + User entity = repository.findByEmail(username); + return new UserDTO(entity); + } catch (Exception e) { + throw new UnauthorizedException("Invalid user"); + } + } + + + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + User user = repository.findByEmail(username); + if (user == null) { + logger.error("User not found " + username); + throw new UsernameNotFoundException("Email não encontrado"); + } + logger.info("User found " + username); + return user; + } +} diff --git a/src/main/java/com/devsuperior/movieflix/services/exceptions/DatabaseException.java b/src/main/java/com/devsuperior/movieflix/services/exceptions/DatabaseException.java new file mode 100644 index 00000000..3e748d27 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/services/exceptions/DatabaseException.java @@ -0,0 +1,10 @@ +package com.devsuperior.movieflix.services.exceptions; + +public class DatabaseException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public DatabaseException(String msg) { + super(msg); + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/services/exceptions/ForbiddenException.java b/src/main/java/com/devsuperior/movieflix/services/exceptions/ForbiddenException.java new file mode 100644 index 00000000..922b2d2b --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/services/exceptions/ForbiddenException.java @@ -0,0 +1,12 @@ +package com.devsuperior.movieflix.services.exceptions; + +public class ForbiddenException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public ForbiddenException(String message) { + super(message); + } + + + +} diff --git a/src/main/java/com/devsuperior/movieflix/services/exceptions/ResourceNotFoundException.java b/src/main/java/com/devsuperior/movieflix/services/exceptions/ResourceNotFoundException.java new file mode 100644 index 00000000..dfe7dcb1 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/services/exceptions/ResourceNotFoundException.java @@ -0,0 +1,10 @@ +package com.devsuperior.movieflix.services.exceptions; + +public class ResourceNotFoundException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public ResourceNotFoundException(String msg) { + super(msg); + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/services/exceptions/UnauthorizedException.java b/src/main/java/com/devsuperior/movieflix/services/exceptions/UnauthorizedException.java new file mode 100644 index 00000000..98314539 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/services/exceptions/UnauthorizedException.java @@ -0,0 +1,10 @@ +package com.devsuperior.movieflix.services.exceptions; + +public class UnauthorizedException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public UnauthorizedException(String msg) { + super(msg); + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a7dcd8af..ca3c13ab 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,9 @@ -spring.profiles.active=test +spring.profiles.active=${APP_PROFILE:test} spring.jpa.open-in-view=false + +security.oauth2.client.client-id=${CLIENT_ID:myclientid} +security.oauth2.client.client-secret=${CLIENT_SECRET:myclientsecret} + +jwt.secret=${JWT_SECRET:MY-JWT-SECRET} +jwt.duration=${JWT_DURATION:240} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 00000000..82cf0908 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,34 @@ +INSERT INTO tb_user (name, email, password) VALUES ('Bob Smith', 'bob@gmail.com', '$2a$10$eACCYoNOHEqXve8aIWT8Nu3PkMXWBaOxJ9aORUYzfMQCbVBIhZ8tG'); +INSERT INTO tb_user (name, email, password) VALUES ('Ana Green', 'ana@gmail.com', '$2a$10$eACCYoNOHEqXve8aIWT8Nu3PkMXWBaOxJ9aORUYzfMQCbVBIhZ8tG'); + +INSERT INTO tb_role (authority) VALUES ('ROLE_VISITOR'); +INSERT INTO tb_role (authority) VALUES ('ROLE_MEMBER'); + +INSERT INTO tb_user_role (user_id, role_id) VALUES (1, 1); +INSERT INTO tb_user_role (user_id, role_id) VALUES (2, 2); + +INSERT INTO tb_genre (name) VALUES ('DRAMA'); +INSERT INTO tb_genre (name) VALUES ('COMEDIA'); +INSERT INTO tb_genre (name) VALUES ('AVENTURA'); +INSERT INTO tb_genre (name) VALUES ('TERROR'); +INSERT INTO tb_genre (name) VALUES ('SUSPENSE'); +INSERT INTO tb_genre (name) VALUES ('FICCAO CIENTIFICA'); + +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('MARIGHELLA', null, '2021', 'https://m.media-amazon.com/images/M/MV5BMmZkNjg3MTgtY2E3OC00YTBmLWI3YTktZWVlZDIxMjAwOTcwXkEyXkFqcGdeQXVyMTkzODUwNzk@._V1_FMjpg_UX1000_.jpg', 'Neste filme biográfico, acompanhamos a história de Carlos Marighella, em 1969, um homem que não teve tempo pra ter medo.', 1); +INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('HOMEM-ARANHA: SEM VOLTA PARA CASA', null, 2021, 'https://s2.glbimg.com/TxQm7TbPjtdv99GcVGFgroItgxU=/e.glbimg.com/og/ed/f/original/2021/11/16/hasvc_cartaz.posted_1080x1350px_data.jpg', 'Em Homem-Aranha: Sem Volta para Casa, Peter Parker (Tom Holland) precisará lidar com as consequências da sua identidade como o herói mais querido do mundo. após ter sido revelada pela reportagem do Clarim Diário, com uma gravação feita por Mysterio (Jake Gyllenhaal) no filme anterior', 3); +INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('DEBI LOIDE 2', null, 2014, 'https://br.web.img2.acsta.net/pictures/14/10/23/13/15/276424.jpg', 'Mais nova aventura dos inseparáveis Lloyd Christmas (Jim Carrey) e Harry Dunne (Jeff Daniels). Desta vez, Harry descobre que teve uma filha ilegítima, que hoje precisa dele para um transplante de rim. Ele leva o amigo Lloyd para conhecer a garota, e os dois percebem que não têm a responsabilidade necessária para serem pais.', 2); +INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('AVATAR', null, 2010, 'https://br.web.img3.acsta.net/medias/nmedia/18/87/30/40/20028676.jpg', 'Jake Sully (Sam Worthington) ficou paraplégico após um combate na Terra. Ele é selecionado para participar do programa Avatar em substituição ao seu irmão gêmeo, falecido. Jake viaja a Pandora, uma lua extraterrestre, onde encontra diversas e estranhas formas de vida. O local é também o lar dos NaVi, seres humanóides que, apesar de primitivos, possuem maior capacidade física que os humanos.', 6); +INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('OS FAROFEIROS', null, 2018, 'https://br.web.img3.acsta.net/pictures/18/01/03/19/24/3938254.jpg', 'Quatro colegas de trabalho se programam para curtir o feriado prolongado em uma casa de praia e, chegando lá, descobrem que se meteram em uma tremenda roubada. Para começar o destino não é Búzios, mas Maringuaba; a residência alugada é encontrada caindo aos pedaços, bem diferente do prometido; a praia está sempre cheia; e as confusões são inúmeras.', 2); +INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('SOBRENATURAL', null, 2011, 'https://maniacosporfilme.files.wordpress.com/2011/08/insidious.jpg', 'O professor Josh Lambert e sua esposa Renai se mudam com seus três filhos – os garotos Dalton e Foster e o bebê Cali – para uma casa muito grande. Quando Dalton está explorando o sótão, ele cai da escada e bate com a cabeça no chão. Na manhã seguinte, Dalton não acorda e fica em coma, mas os médicos não conseguem diagnosticar o seu problema.', 4); +INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('A ILHA DO MEDO', null, 2010, 'http://2.bp.blogspot.com/-M0R0KFo-kOc/U778Byzi-bI/AAAAAAAANMI/POj94JZQPTc/s1600/review-a-ilha-do-medo1.jpg', '1954. Teddy Daniels (Leonardo DiCaprio) investiga o desaparecimento de um paciente no Shutter Island Ashecliffe Hospital, em Boston. No local, ele descobre que os médicos realizam experiências radicais com os pacientes, envolvendo métodos ilegais e anti-éticos. Teddy tenta buscar mais informações, mas enfrenta a resistência dos médicos em lhe fornecer os arquivos que possam permitir que o caso seja aberto.', 5); + + + +INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Muito bom!', 2, 1); +INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Emocionante', 2, 1); +INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Super Heroir favorito. Filmes Sensacional', 2, 2); +INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Altas risadas', 2, 3); +INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Lindo Filme. Cores vibrantes.', 2, 4); +INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Para rir muito', 2, 5); +INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Terror SObrenatural', 2, 6); +INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Frio na espinha', 2, 7); diff --git a/src/test/java/com/devsuperior/movieflix/controllers/GenreControllerIT.java b/src/test/java/com/devsuperior/movieflix/controllers/GenreControllerIT.java new file mode 100644 index 00000000..67cc3500 --- /dev/null +++ b/src/test/java/com/devsuperior/movieflix/controllers/GenreControllerIT.java @@ -0,0 +1,91 @@ +package com.devsuperior.movieflix.controllers; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.transaction.annotation.Transactional; + +import com.devsuperior.movieflix.tests.TokenUtil; + +@SpringBootTest +@AutoConfigureMockMvc +@Transactional +public class GenreControllerIT { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private TokenUtil tokenUtil; + + private String visitorUsername; + private String visitorPassword; + private String memberUsername; + private String memberPassword; + + @BeforeEach + void setUp() throws Exception { + + visitorUsername = "bob@gmail.com"; + visitorPassword = "123456"; + memberUsername = "ana@gmail.com"; + memberPassword = "123456"; + } + + @Test + public void findAllShouldReturnUnauthorizedWhenNotValidToken() throws Exception { + + ResultActions result = + mockMvc.perform(get("/genres") + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isUnauthorized()); + } + + @Test + public void findAllShouldReturnAllGenresWhenVisitorAuthenticated() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, visitorUsername, visitorPassword); + + ResultActions result = + mockMvc.perform(get("/genres") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isOk()); + result.andExpect(jsonPath("$[0].id").value(1L)); + result.andExpect(jsonPath("$[0].name").value("Comédia")); + result.andExpect(jsonPath("$[1].id").value(2L)); + result.andExpect(jsonPath("$[1].name").value("Terror")); + result.andExpect(jsonPath("$[2].id").value(3L)); + result.andExpect(jsonPath("$[2].name").value("Drama")); + } + + @Test + public void findAllShouldReturnAllGenresWhenMemberAuthenticated() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, memberUsername, memberPassword); + + ResultActions result = + mockMvc.perform(get("/genres") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isOk()); + result.andExpect(jsonPath("$[0].id").value(1L)); + result.andExpect(jsonPath("$[0].name").value("Comédia")); + result.andExpect(jsonPath("$[1].id").value(2L)); + result.andExpect(jsonPath("$[1].name").value("Terror")); + result.andExpect(jsonPath("$[2].id").value(3L)); + result.andExpect(jsonPath("$[2].name").value("Drama")); + } +} diff --git a/src/test/java/com/devsuperior/movieflix/controllers/MovieControllerIT.java b/src/test/java/com/devsuperior/movieflix/controllers/MovieControllerIT.java new file mode 100644 index 00000000..eab3ad72 --- /dev/null +++ b/src/test/java/com/devsuperior/movieflix/controllers/MovieControllerIT.java @@ -0,0 +1,198 @@ +package com.devsuperior.movieflix.controllers; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.transaction.annotation.Transactional; + +import com.devsuperior.movieflix.tests.TokenUtil; + +@SpringBootTest +@AutoConfigureMockMvc +@Transactional +public class MovieControllerIT { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private TokenUtil tokenUtil; + + private long existingId; + private long nonExistingId; + + private String visitorUsername; + private String visitorPassword; + private String memberUsername; + private String memberPassword; + + @BeforeEach + void setUp() throws Exception { + + existingId = 1L; + nonExistingId = 100000L; + + visitorUsername = "bob@gmail.com"; + visitorPassword = "123456"; + memberUsername = "ana@gmail.com"; + memberPassword = "123456"; + } + + @Test + public void findByIdShouldReturnUnauthorizedWhenNoTokenGiven() throws Exception { + + ResultActions result = + mockMvc.perform(get("/movies/{id}", existingId) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isUnauthorized()); + } + + @Test + public void findByIdShouldReturnMovieWhenUserVisitorAuthenticated() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, visitorUsername, visitorPassword); + + ResultActions result = + mockMvc.perform(get("/movies/{id}", existingId) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isOk()); + result.andExpect(jsonPath("$.id").value(existingId)); + result.andExpect(jsonPath("$.title").isNotEmpty()); + result.andExpect(jsonPath("$.subTitle").isNotEmpty()); + result.andExpect(jsonPath("$.year").isNotEmpty()); + result.andExpect(jsonPath("$.imgUrl").isNotEmpty()); + result.andExpect(jsonPath("$.synopsis").isNotEmpty()); + result.andExpect(jsonPath("$.genre").isNotEmpty()); + result.andExpect(jsonPath("$.genre.id").isNotEmpty()); + result.andExpect(jsonPath("$.genre.name").isNotEmpty()); + } + + @Test + public void findByIdShouldReturnMovieWhenMemberAuthenticated() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, memberUsername, memberPassword); + + ResultActions result = + mockMvc.perform(get("/movies/{id}", existingId) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isOk()); + result.andExpect(jsonPath("$.id").value(existingId)); + result.andExpect(jsonPath("$.title").isNotEmpty()); + result.andExpect(jsonPath("$.subTitle").isNotEmpty()); + result.andExpect(jsonPath("$.year").isNotEmpty()); + result.andExpect(jsonPath("$.imgUrl").isNotEmpty()); + result.andExpect(jsonPath("$.synopsis").isNotEmpty()); + result.andExpect(jsonPath("$.genre").isNotEmpty()); + result.andExpect(jsonPath("$.genre.id").isNotEmpty()); + result.andExpect(jsonPath("$.genre.name").isNotEmpty()); + } + + @Test + public void findByIdShouldReturnNotFoundWhenIdDoesNotExist() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, visitorUsername, visitorPassword); + + ResultActions result = + mockMvc.perform(get("/movies/{id}", nonExistingId) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isNotFound()); + } + + @Test + public void findByGenreShouldReturnUnauthorizedWhenNoTokenGiven() throws Exception { + + ResultActions result = + mockMvc.perform(get("/movies") + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isUnauthorized()); + } + + @Test + public void findByGenreShouldReturnOrderedPageWhenVisitorAuthenticated() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, visitorUsername, visitorPassword); + + ResultActions result = + mockMvc.perform(get("/movies") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isOk()); + + result.andExpect(jsonPath("$.content[0].id").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].title").value("A Voz do Silêncio")); + result.andExpect(jsonPath("$.content[0].subTitle").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].year").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].imgUrl").isNotEmpty()); + + result.andExpect(jsonPath("$.content[1].title").value("Bob Esponja")); + result.andExpect(jsonPath("$.content[2].title").value("Código de Conduta")); + result.andExpect(jsonPath("$.content[3].title").value("Kingsman")); + result.andExpect(jsonPath("$.content[4].title").value("O Labirinto do Fauno")); + } + + @Test + public void findByGenreShouldReturnOrderedPageWhenMemberAuthenticated() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, memberUsername, memberPassword); + + ResultActions result = + mockMvc.perform(get("/movies") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isOk()); + + result.andExpect(jsonPath("$.content[0].id").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].title").value("A Voz do Silêncio")); + result.andExpect(jsonPath("$.content[0].subTitle").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].year").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].imgUrl").isNotEmpty()); + + result.andExpect(jsonPath("$.content[1].title").value("Bob Esponja")); + result.andExpect(jsonPath("$.content[2].title").value("Código de Conduta")); + result.andExpect(jsonPath("$.content[3].title").value("Kingsman")); + result.andExpect(jsonPath("$.content[4].title").value("O Labirinto do Fauno")); + } + + @Test + public void findByGenreShouldReturnFilteredMoviesWhenGenreIsInformed() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, visitorUsername, visitorPassword); + + long genreId = 1L; + + ResultActions result = + mockMvc.perform(get("/movies?genreId=" + genreId) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isOk()); + + result.andExpect(jsonPath("$.content[0].id").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].title").value("Bob Esponja")); + result.andExpect(jsonPath("$.content[0].subTitle").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].year").isNotEmpty()); + result.andExpect(jsonPath("$.content[0].imgUrl").isNotEmpty()); + + result.andExpect(jsonPath("$.content[1].title").value("Kingsman")); + result.andExpect(jsonPath("$.content[2].title").value("Sonic")); + } +} diff --git a/src/test/java/com/devsuperior/movieflix/controllers/ReviewResourceIT.java b/src/test/java/com/devsuperior/movieflix/controllers/ReviewResourceIT.java new file mode 100644 index 00000000..bd31e6aa --- /dev/null +++ b/src/test/java/com/devsuperior/movieflix/controllers/ReviewResourceIT.java @@ -0,0 +1,141 @@ +package com.devsuperior.movieflix.controllers; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.transaction.annotation.Transactional; + +import com.devsuperior.movieflix.dto.ReviewDTO; +import com.devsuperior.movieflix.tests.TokenUtil; +import com.fasterxml.jackson.databind.ObjectMapper; + +@SpringBootTest +@AutoConfigureMockMvc +@Transactional +public class ReviewResourceIT { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private TokenUtil tokenUtil; + + @Autowired + private ObjectMapper objectMapper; + + private String visitorUsername; + private String visitorPassword; + private String memberUsername; + private String memberPassword; + + @BeforeEach + void setUp() throws Exception { + + visitorUsername = "bob@gmail.com"; + visitorPassword = "123456"; + memberUsername = "ana@gmail.com"; + memberPassword = "123456"; + } + + @Test + public void insertShouldReturnUnauthorizedWhenNotValidToken() throws Exception { + + ReviewDTO reviewDTO = new ReviewDTO(); + reviewDTO.setText("Gostei do filme!"); + reviewDTO.setMovieId(1L); + + String jsonBody = objectMapper.writeValueAsString(reviewDTO); + + ResultActions result = + mockMvc.perform(post("/reviews") + .content(jsonBody) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isUnauthorized()); + } + + @Test + public void insertShouldReturnForbiddenWhenVisitorAuthenticated() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, visitorUsername, visitorPassword); + + ReviewDTO reviewDTO = new ReviewDTO(); + reviewDTO.setText("Gostei do filme!"); + reviewDTO.setMovieId(1L); + + String jsonBody = objectMapper.writeValueAsString(reviewDTO); + + ResultActions result = + mockMvc.perform(post("/reviews") + .header("Authorization", "Bearer " + accessToken) + .content(jsonBody) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isForbidden()); + } + + @Test + public void insertShouldInsertReviewWhenMemberAuthenticatedAndValidData() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, memberUsername, memberPassword); + + String reviewText = "Gostei do filme!"; + long movieId = 1L; + + ReviewDTO reviewDTO = new ReviewDTO(); + reviewDTO.setText(reviewText); + reviewDTO.setMovieId(movieId); + + String jsonBody = objectMapper.writeValueAsString(reviewDTO); + + ResultActions result = + mockMvc.perform(post("/reviews") + .header("Authorization", "Bearer " + accessToken) + .content(jsonBody) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isCreated()); + + result.andExpect(jsonPath("$.id").isNotEmpty()); + result.andExpect(jsonPath("$.text").value(reviewText)); + result.andExpect(jsonPath("$.movieId").value(movieId)); + + result.andExpect(jsonPath("$.user").isNotEmpty()); + result.andExpect(jsonPath("$.user.id").isNotEmpty()); + result.andExpect(jsonPath("$.user.name").isNotEmpty()); + result.andExpect(jsonPath("$.user.email").value(memberUsername)); + } + + @Test + public void insertShouldReturnUnproccessableEntityWhenMemberAuthenticatedAndInvalidData() throws Exception { + + String accessToken = tokenUtil.obtainAccessToken(mockMvc, memberUsername, memberPassword); + + ReviewDTO reviewDTO = new ReviewDTO(); + reviewDTO.setText(" "); + reviewDTO.setMovieId(1L); + + String jsonBody = objectMapper.writeValueAsString(reviewDTO); + + ResultActions result = + mockMvc.perform(post("/reviews") + .header("Authorization", "Bearer " + accessToken) + .content(jsonBody) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + + result.andExpect(status().isUnprocessableEntity()); + } +} diff --git a/src/test/java/com/devsuperior/movieflix/entities/RoleTests.java b/src/test/java/com/devsuperior/movieflix/entities/RoleTests.java index 8d4d2a8d..adef5cf7 100644 --- a/src/test/java/com/devsuperior/movieflix/entities/RoleTests.java +++ b/src/test/java/com/devsuperior/movieflix/entities/RoleTests.java @@ -7,7 +7,7 @@ public class RoleTests { @Test public void roleShouldHaveCorrectStructure() { - + Role entity = new Role(); entity.setId(1L); entity.setAuthority("ROLE_MEMBER"); diff --git a/src/test/java/com/devsuperior/movieflix/entities/UserTests.java b/src/test/java/com/devsuperior/movieflix/entities/UserTests.java index 590976c9..abde48d0 100644 --- a/src/test/java/com/devsuperior/movieflix/entities/UserTests.java +++ b/src/test/java/com/devsuperior/movieflix/entities/UserTests.java @@ -7,7 +7,7 @@ public class UserTests { @Test public void userShouldHaveCorrectStructure() { - + User entity = new User(); entity.setId(1L); entity.setName("Name"); From b777b939a4a70923671c8181e915b291b5055d41 Mon Sep 17 00:00:00 2001 From: Everton Souza Date: Fri, 7 Jan 2022 11:15:04 -0300 Subject: [PATCH 5/5] GenreControllerIT Tests --- .../controllers/GenreController.java | 26 +++++++++ .../devsuperior/movieflix/dto/GenreDTO.java | 42 +++++++++++++++ .../devsuperior/movieflix/dto/ReviewDTO.java | 53 +++++++++++++++++++ .../movieflix/services/GenreService.java | 26 +++++++++ src/main/resources/data.sql | 43 +++++++-------- 5 files changed, 165 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/devsuperior/movieflix/controllers/GenreController.java create mode 100644 src/main/java/com/devsuperior/movieflix/dto/GenreDTO.java create mode 100644 src/main/java/com/devsuperior/movieflix/dto/ReviewDTO.java create mode 100644 src/main/java/com/devsuperior/movieflix/services/GenreService.java diff --git a/src/main/java/com/devsuperior/movieflix/controllers/GenreController.java b/src/main/java/com/devsuperior/movieflix/controllers/GenreController.java new file mode 100644 index 00000000..9f4f1584 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/controllers/GenreController.java @@ -0,0 +1,26 @@ +package com.devsuperior.movieflix.controllers; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.devsuperior.movieflix.dto.GenreDTO; +import com.devsuperior.movieflix.services.GenreService; + +@RestController +@RequestMapping(value = "/genres") +public class GenreController { + + @Autowired + private GenreService service; + + @GetMapping + public ResponseEntity> findAll(){ + List list = service.findAll(); + return ResponseEntity.ok().body(list); + } +} \ No newline at end of file diff --git a/src/main/java/com/devsuperior/movieflix/dto/GenreDTO.java b/src/main/java/com/devsuperior/movieflix/dto/GenreDTO.java new file mode 100644 index 00000000..93d01b8e --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/dto/GenreDTO.java @@ -0,0 +1,42 @@ +package com.devsuperior.movieflix.dto; + +import java.io.Serializable; + +import com.devsuperior.movieflix.entities.Genre; + +public class GenreDTO implements Serializable{ + private static final long serialVersionUID = 1L; + + private Long id; + private String name; + + public GenreDTO() { + } + + public GenreDTO(Long id, String name) { + this.id = id; + this.name = name; + } + + public GenreDTO(Genre entity) { + id = entity.getId(); + name = entity.getName(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/dto/ReviewDTO.java b/src/main/java/com/devsuperior/movieflix/dto/ReviewDTO.java new file mode 100644 index 00000000..b7dfe709 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/dto/ReviewDTO.java @@ -0,0 +1,53 @@ +package com.devsuperior.movieflix.dto; + +import java.io.Serializable; + +import com.devsuperior.movieflix.entities.Review; + +public class ReviewDTO implements Serializable{ + private static final long serialVersionUID = 1L; + + private Long id; + private String text; + private Long movieId; + + public ReviewDTO() { + } + + public ReviewDTO(Long id, String text, Long movieId) { + this.id = id; + this.text = text; + this.movieId = movieId; + } + + public ReviewDTO(Review entity) { + id = entity.getId(); + text = entity.getText(); + movieId = entity.getMovie().getId(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public Long getMovieId() { + return movieId; + } + + public void setMovieId(Long movieId) { + this.movieId = movieId; + } + +} diff --git a/src/main/java/com/devsuperior/movieflix/services/GenreService.java b/src/main/java/com/devsuperior/movieflix/services/GenreService.java new file mode 100644 index 00000000..0c6e9a33 --- /dev/null +++ b/src/main/java/com/devsuperior/movieflix/services/GenreService.java @@ -0,0 +1,26 @@ +package com.devsuperior.movieflix.services; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.devsuperior.movieflix.dto.GenreDTO; +import com.devsuperior.movieflix.entities.Genre; +import com.devsuperior.movieflix.repositories.GenreRepository; + + +@Service +public class GenreService { + + @Autowired + private GenreRepository repository; + + @Transactional(readOnly = true) + public List findAll(){ + List list = repository.findAll(); + return list.stream().map(GenreDTO::new).collect(Collectors.toList()); + } +} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 82cf0908..8752e066 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,5 +1,5 @@ -INSERT INTO tb_user (name, email, password) VALUES ('Bob Smith', 'bob@gmail.com', '$2a$10$eACCYoNOHEqXve8aIWT8Nu3PkMXWBaOxJ9aORUYzfMQCbVBIhZ8tG'); -INSERT INTO tb_user (name, email, password) VALUES ('Ana Green', 'ana@gmail.com', '$2a$10$eACCYoNOHEqXve8aIWT8Nu3PkMXWBaOxJ9aORUYzfMQCbVBIhZ8tG'); +INSERT INTO tb_user (name, email, password) VALUES ('Bob', 'bob@gmail.com', '$2a$10$eACCYoNOHEqXve8aIWT8Nu3PkMXWBaOxJ9aORUYzfMQCbVBIhZ8tG'); +INSERT INTO tb_user (name, email, password) VALUES ('Ana', 'ana@gmail.com', '$2a$10$eACCYoNOHEqXve8aIWT8Nu3PkMXWBaOxJ9aORUYzfMQCbVBIhZ8tG'); INSERT INTO tb_role (authority) VALUES ('ROLE_VISITOR'); INSERT INTO tb_role (authority) VALUES ('ROLE_MEMBER'); @@ -7,28 +7,21 @@ INSERT INTO tb_role (authority) VALUES ('ROLE_MEMBER'); INSERT INTO tb_user_role (user_id, role_id) VALUES (1, 1); INSERT INTO tb_user_role (user_id, role_id) VALUES (2, 2); -INSERT INTO tb_genre (name) VALUES ('DRAMA'); -INSERT INTO tb_genre (name) VALUES ('COMEDIA'); -INSERT INTO tb_genre (name) VALUES ('AVENTURA'); -INSERT INTO tb_genre (name) VALUES ('TERROR'); -INSERT INTO tb_genre (name) VALUES ('SUSPENSE'); -INSERT INTO tb_genre (name) VALUES ('FICCAO CIENTIFICA'); +INSERT INTO tb_genre (name) VALUES ('Comédia'); +INSERT INTO tb_genre (name) VALUES ('Terror'); +INSERT INTO tb_genre (name) VALUES ('Drama'); -INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('MARIGHELLA', null, '2021', 'https://m.media-amazon.com/images/M/MV5BMmZkNjg3MTgtY2E3OC00YTBmLWI3YTktZWVlZDIxMjAwOTcwXkEyXkFqcGdeQXVyMTkzODUwNzk@._V1_FMjpg_UX1000_.jpg', 'Neste filme biográfico, acompanhamos a história de Carlos Marighella, em 1969, um homem que não teve tempo pra ter medo.', 1); -INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('HOMEM-ARANHA: SEM VOLTA PARA CASA', null, 2021, 'https://s2.glbimg.com/TxQm7TbPjtdv99GcVGFgroItgxU=/e.glbimg.com/og/ed/f/original/2021/11/16/hasvc_cartaz.posted_1080x1350px_data.jpg', 'Em Homem-Aranha: Sem Volta para Casa, Peter Parker (Tom Holland) precisará lidar com as consequências da sua identidade como o herói mais querido do mundo. após ter sido revelada pela reportagem do Clarim Diário, com uma gravação feita por Mysterio (Jake Gyllenhaal) no filme anterior', 3); -INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('DEBI LOIDE 2', null, 2014, 'https://br.web.img2.acsta.net/pictures/14/10/23/13/15/276424.jpg', 'Mais nova aventura dos inseparáveis Lloyd Christmas (Jim Carrey) e Harry Dunne (Jeff Daniels). Desta vez, Harry descobre que teve uma filha ilegítima, que hoje precisa dele para um transplante de rim. Ele leva o amigo Lloyd para conhecer a garota, e os dois percebem que não têm a responsabilidade necessária para serem pais.', 2); -INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('AVATAR', null, 2010, 'https://br.web.img3.acsta.net/medias/nmedia/18/87/30/40/20028676.jpg', 'Jake Sully (Sam Worthington) ficou paraplégico após um combate na Terra. Ele é selecionado para participar do programa Avatar em substituição ao seu irmão gêmeo, falecido. Jake viaja a Pandora, uma lua extraterrestre, onde encontra diversas e estranhas formas de vida. O local é também o lar dos NaVi, seres humanóides que, apesar de primitivos, possuem maior capacidade física que os humanos.', 6); -INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('OS FAROFEIROS', null, 2018, 'https://br.web.img3.acsta.net/pictures/18/01/03/19/24/3938254.jpg', 'Quatro colegas de trabalho se programam para curtir o feriado prolongado em uma casa de praia e, chegando lá, descobrem que se meteram em uma tremenda roubada. Para começar o destino não é Búzios, mas Maringuaba; a residência alugada é encontrada caindo aos pedaços, bem diferente do prometido; a praia está sempre cheia; e as confusões são inúmeras.', 2); -INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('SOBRENATURAL', null, 2011, 'https://maniacosporfilme.files.wordpress.com/2011/08/insidious.jpg', 'O professor Josh Lambert e sua esposa Renai se mudam com seus três filhos – os garotos Dalton e Foster e o bebê Cali – para uma casa muito grande. Quando Dalton está explorando o sótão, ele cai da escada e bate com a cabeça no chão. Na manhã seguinte, Dalton não acorda e fica em coma, mas os médicos não conseguem diagnosticar o seu problema.', 4); -INSERT INTO tb_movie (title, sub_Title, year, img_Url, synopsis, genre_id) VALUES ('A ILHA DO MEDO', null, 2010, 'http://2.bp.blogspot.com/-M0R0KFo-kOc/U778Byzi-bI/AAAAAAAANMI/POj94JZQPTc/s1600/review-a-ilha-do-medo1.jpg', '1954. Teddy Daniels (Leonardo DiCaprio) investiga o desaparecimento de um paciente no Shutter Island Ashecliffe Hospital, em Boston. No local, ele descobre que os médicos realizam experiências radicais com os pacientes, envolvendo métodos ilegais e anti-éticos. Teddy tenta buscar mais informações, mas enfrenta a resistência dos médicos em lhe fornecer os arquivos que possam permitir que o caso seja aberto.', 5); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('Bob Esponja', 'O Incrível Resgate', 2020, 'https://image.tmdb.org/t/p/w533_and_h300_bestv2/wu1uilmhM4TdluKi2ytfz8gidHf.jpg', 'Onde está Gary? Segundo Bob Esponja, Gary foi "caracolstrado" pelo temível Rei Poseidon e levado para a cidade perdida de Atlantic City. Junto a Patrick Estrela, ele sai em uma missão de resgate ao querido amigo, e nesta jornada os dois vão conhecer novos personagens e viver inimagináveis aventuras.', 1); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('O Orfanato', null, 2007, 'https://image.tmdb.org/t/p/w533_and_h300_bestv2/2AlVaQDH67RgulE2AqXBSPr2POF.jpg', 'Laura (Belén Rueda) passou os anos mais felizes de sua vida em um orfanato, onde recebeu os cuidados de uma equipe e de outros companheiros órfãos, a quem considerava como se fossem seus irmãos e irmãs verdadeiros. Agora, 30 anos depois, ela retornou ao local com seu marido Carlos (Fernando Cayo) e seu filho Simón (Roger Príncep), de 7 anos. Ela deseja restaurar e reabrir o orfanato, que está abandonado há vários anos. O local logo desperta a imaginação de Simón, que passa a criar contos fantásticos. Entretanto à medida que os contos ficam mais estranhos Laura começa a desconfiar que há algo à espreita na casa.', 2); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('O Labirinto do Fauno', null, 2006, 'https://image.tmdb.org/t/p/w500_and_h282_face/oXMfT5OM6HAgQ9sGANB8cs1ifCG.jpg', 'Em 1944, na Espanha, a jovem Ofélia e sua mãe doente chegam ao posto do novo marido de sua mãe, um sádico oficial do exército que está tentando reprimir uma guerrilheira. Enquanto explorava um labirinto antigo, Ofélia encontra o Pan fauno, que diz que a menina é uma lendária princesa perdida e que ela precisa completar três tarefas perigosas a fim de se tornar imortal.', 3); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('Your Name', null, 2016, 'https://image.tmdb.org/t/p/w533_and_h300_bestv2/wqZapHpXyZEaCkpsLVszmEQcDIy.jpg', 'Mitsuha é a filha do prefeito de uma pequena cidade, mas sonha em tentar a sorte em Tóquio. Taki trabalha em um restaurante em Tóquio e deseja largar o seu emprego. Os dois não se conhecem, mas estão conectados pelas imagens de seus sonhos.', 3); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('Código de Conduta', null , 2009, 'https://image.tmdb.org/t/p/w533_and_h300_bestv2/mwlLjL3jTDmTdLWe2PyUVqYQTuK.jpg', 'Quando um dos suspeitos do assassinato de sua mulher e filha é solto, Clyde quer vingança e decide fazer justiça com as próprias mãos. Clyde é preso e dentro da cadeia organiza uma matança para desmascarar o sistema judicial corrupto.', 3); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('A Voz do Silêncio', 'Koe no Katachi', 2016, 'https://image.tmdb.org/t/p/w533_and_h300_bestv2/5lAMQMWpXMsirvtLLvW7cJgEPkU.jpg', 'Nishimiya Shouko é uma estudante com deficiência auditiva. Durante o ensino fundamental, após se transferir para uma nova escola, Shouko passa a ser alvo de bullying e em pouco tempo precisa se transferir. O que ela não esperava é que alguns anos depois, Ishida Shouya, um dos valentões que tanto a fez sofrer no passado surgisse de novo em sua vida com um novo propósito.', 3); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('Kingsman', 'Serviço Secreto', 2014, 'https://image.tmdb.org/t/p/w533_and_h300_bestv2/qzUIOTk0E3F1zjvYjcBRTKUTgf9.jpg','Eggsy (Taron Egerton) é um jovem com problemas de disciplina que parece perto de se tornar um criminoso. Determinado dia, ele entra em contato com Harry (Colin Firth), que lhe apresenta à agência de espionagem Kingsman. O jovem se une a um time de recrutas em busca de uma vaga na agência. Ao mesmo tempo, Harry tenta impedir a ascensão do vilão Valentine (Samuel L. Jackson). Adaptação da série de quadrinhos criada por Mark Millar e Dave Gibbons.',1); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('Sonic', 'O Filme', 2020, 'https://image.tmdb.org/t/p/w533_and_h300_bestv2/diFNHa3SXaGSSFovGatNWxLz2tn.jpg','Sonic, o porco-espinho azul mais famoso do mundo, se junta com os seus amigos para derrotar o terrível Doutor Eggman, um cientista louco que planeja dominar o mundo, e o Doutor Robotnik, responsável por aprisionar animais inocentes em robôs.',1); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('Uma Noite de Crime', 'Anarquia', 2014, 'https://image.tmdb.org/t/p/w500_and_h282_face/ecD9hT8odHzFCDeGDy4N2IKh0LN.jpg', 'O governo dos Estados Unidos sanciona uma lei em que os assassinatos são permitidos durante uma noite, para que os cidadãos liberem seus instintos violentos. Cinco desconhecidos se unem para tentar sobreviver a essa verdadeira noite de terror.', 2); +INSERT INTO tb_movie (title, sub_title, year, img_url, synopsis, genre_id) VALUES ('O Segredo da Cabana', null, 2012, 'https://image.tmdb.org/t/p/w533_and_h300_bestv2/5iiVfPS6LsAqmVQVOzhyCHhCFgU.jpg', 'Cinco amigos fazem uma pausa em uma cabana remota, onde conseguem mais do que esperavam, descobrindo a verdade atrás da cabana na floresta.', 2); - - -INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Muito bom!', 2, 1); -INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Emocionante', 2, 1); -INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Super Heroir favorito. Filmes Sensacional', 2, 2); -INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Altas risadas', 2, 3); -INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Lindo Filme. Cores vibrantes.', 2, 4); -INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Para rir muito', 2, 5); -INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Terror SObrenatural', 2, 6); -INSERT INTO tb_review (text, user_id, movie_id) VALUES ('Frio na espinha', 2, 7); +INSERT INTO tb_review (text, movie_id, user_id) VALUES ('Meh, filme OK', 1, 1); +INSERT INTO tb_review (text, movie_id, user_id) VALUES ('Gostei e recomendo!', 1, 1); +INSERT INTO tb_review (text, movie_id, user_id) VALUES ('Que Filme!!!', 2, 1); \ No newline at end of file