From 26bcff330c3b12ec9b24076ffed8ad5e032e6869 Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Wed, 24 Aug 2022 19:20:09 -0300 Subject: [PATCH 01/13] Created repositories --- .../bds04/repositories/CityRepository.java | 11 +++++++++++ .../bds04/repositories/EventRepository.java | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/main/java/com/devsuperior/bds04/repositories/CityRepository.java create mode 100644 src/main/java/com/devsuperior/bds04/repositories/EventRepository.java diff --git a/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java b/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java new file mode 100644 index 00000000..49ede7d9 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java @@ -0,0 +1,11 @@ +package com.devsuperior.bds04.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.devsuperior.bds04.entities.Event; + +@Repository +public interface CityRepository extends JpaRepository{ + +} diff --git a/src/main/java/com/devsuperior/bds04/repositories/EventRepository.java b/src/main/java/com/devsuperior/bds04/repositories/EventRepository.java new file mode 100644 index 00000000..a9635ae4 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/repositories/EventRepository.java @@ -0,0 +1,11 @@ +package com.devsuperior.bds04.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.devsuperior.bds04.entities.Event; + +@Repository +public interface EventRepository extends JpaRepository{ + +} From a01fd355467001b36a8da78c9b688ec69ab344dd Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Wed, 24 Aug 2022 19:24:17 -0300 Subject: [PATCH 02/13] Services implementation --- .../bds04/repositories/CityRepository.java | 4 +- .../bds04/services/CityService.java | 71 +++++++++++++++++++ .../exceptions/DatabaseException.java | 10 +++ .../exceptions/ResourceNotFoundException.java | 10 +++ 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/devsuperior/bds04/services/CityService.java create mode 100644 src/main/java/com/devsuperior/bds04/services/exceptions/DatabaseException.java create mode 100644 src/main/java/com/devsuperior/bds04/services/exceptions/ResourceNotFoundException.java diff --git a/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java b/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java index 49ede7d9..668313b3 100644 --- a/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java +++ b/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java @@ -3,9 +3,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import com.devsuperior.bds04.entities.Event; +import com.devsuperior.bds04.entities.City; @Repository -public interface CityRepository extends JpaRepository{ +public interface CityRepository extends JpaRepository{ } diff --git a/src/main/java/com/devsuperior/bds04/services/CityService.java b/src/main/java/com/devsuperior/bds04/services/CityService.java new file mode 100644 index 00000000..cd0877b0 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/CityService.java @@ -0,0 +1,71 @@ +package com.devsuperior.bds04.services; + +import java.util.Optional; + +import javax.persistence.EntityNotFoundException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.devsuperior.bds04.dto.CityDTO; +import com.devsuperior.bds04.entities.City; +import com.devsuperior.bds04.repositories.CityRepository; +import com.devsuperior.bds04.services.exceptions.DatabaseException; +import com.devsuperior.bds04.services.exceptions.ResourceNotFoundException; + +@Service +public class CityService { + + @Autowired + private CityRepository repository; + + @Transactional(readOnly = true) + public Page findAllPaged(Pageable pageable) { + Page list = repository.findAll(pageable); + + return list.map(x -> new CityDTO(x)); + } + + @Transactional(readOnly = true) + public CityDTO findById(Long id) { + Optional obj = repository.findById(id); + City entity = obj.orElseThrow(() -> new ResourceNotFoundException("Entity Not Found!")); + return new CityDTO(entity); + } + + @Transactional + public CityDTO insert(CityDTO dto) { + City entity = new City(); + entity.setName(dto.getName()); + entity = repository.save(entity); + return new CityDTO(entity); + } + + @Transactional + public CityDTO update(Long id, CityDTO dto) { + try { + City entity = repository.getOne(id); + entity.setName(dto.getName()); + entity = repository.save(entity); + return new CityDTO(entity); + } catch (EntityNotFoundException e) { + throw new ResourceNotFoundException("ID Not Found! ID: " + id); + } + } + + public void delete(Long id) { + try { + repository.deleteById(id); + } catch (EmptyResultDataAccessException e) { + throw new ResourceNotFoundException("ID Not Found! ID: " + id); + } catch (DataIntegrityViolationException e) { + throw new DatabaseException("Integrity Violation!"); + } + } + +} diff --git a/src/main/java/com/devsuperior/bds04/services/exceptions/DatabaseException.java b/src/main/java/com/devsuperior/bds04/services/exceptions/DatabaseException.java new file mode 100644 index 00000000..45a00636 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/exceptions/DatabaseException.java @@ -0,0 +1,10 @@ +package com.devsuperior.bds04.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/bds04/services/exceptions/ResourceNotFoundException.java b/src/main/java/com/devsuperior/bds04/services/exceptions/ResourceNotFoundException.java new file mode 100644 index 00000000..1b9f352e --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/exceptions/ResourceNotFoundException.java @@ -0,0 +1,10 @@ +package com.devsuperior.bds04.services.exceptions; + +public class ResourceNotFoundException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public ResourceNotFoundException(String msg) { + super(msg); + } + +} From 6ff4e98a6880d4c6d00a6d980c5a636937a0e65c Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Wed, 24 Aug 2022 19:27:34 -0300 Subject: [PATCH 03/13] Services implementation 2 --- .../java/com/devsuperior/bds04/services/EventService.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/java/com/devsuperior/bds04/services/EventService.java diff --git a/src/main/java/com/devsuperior/bds04/services/EventService.java b/src/main/java/com/devsuperior/bds04/services/EventService.java new file mode 100644 index 00000000..b57dd9e9 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/EventService.java @@ -0,0 +1,5 @@ +package com.devsuperior.bds04.services; + +public class EventService { + +} From 7dd3dfbe9ef9c5e54d3e44052ed1c40f0f4dae90 Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Mon, 5 Sep 2022 21:03:59 -0300 Subject: [PATCH 04/13] Controllers implementation --- .../bds04/controllers/CityController.java | 61 +++++++++++++++++ .../bds04/controllers/EventController.java | 62 +++++++++++++++++ .../controllers/exceptions/FieldMessage.java | 37 ++++++++++ .../exceptions/ResourceExceptionHandler.java | 67 +++++++++++++++++++ .../controllers/exceptions/StandardError.java | 57 ++++++++++++++++ .../exceptions/ValidationError.java | 19 ++++++ .../bds04/services/EventService.java | 66 ++++++++++++++++++ 7 files changed, 369 insertions(+) create mode 100644 src/main/java/com/devsuperior/bds04/controllers/CityController.java create mode 100644 src/main/java/com/devsuperior/bds04/controllers/EventController.java create mode 100644 src/main/java/com/devsuperior/bds04/controllers/exceptions/FieldMessage.java create mode 100644 src/main/java/com/devsuperior/bds04/controllers/exceptions/ResourceExceptionHandler.java create mode 100644 src/main/java/com/devsuperior/bds04/controllers/exceptions/StandardError.java create mode 100644 src/main/java/com/devsuperior/bds04/controllers/exceptions/ValidationError.java diff --git a/src/main/java/com/devsuperior/bds04/controllers/CityController.java b/src/main/java/com/devsuperior/bds04/controllers/CityController.java new file mode 100644 index 00000000..dc55bb6e --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/controllers/CityController.java @@ -0,0 +1,61 @@ +package com.devsuperior.bds04.controllers; + +import java.net.URI; + +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.devsuperior.bds04.dto.CityDTO; +import com.devsuperior.bds04.services.CityService; + +@RestController +@RequestMapping(value = "/users") +public class CityController { + + @Autowired + private CityService service; + + @GetMapping + public ResponseEntity> findAll(Pageable pageable) { + Page list = service.findAllPaged(pageable); + return ResponseEntity.ok().body(list); + } + + @GetMapping(value = "/{id}") + public ResponseEntity findById(@PathVariable Long id) { + CityDTO dto = service.findById(id); + return ResponseEntity.ok().body(dto); + } + + @PostMapping + public ResponseEntity insert(@Valid @RequestBody CityDTO dto) { + CityDTO newDto = service.insert(dto); + URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(newDto.getId()).toUri(); + return ResponseEntity.created(uri).body(newDto); + } + + @PutMapping(value = "/{id}") + public ResponseEntity update(@PathVariable Long id,@Valid @RequestBody CityDTO dto) { + CityDTO newDto = service.update(id, dto); + return ResponseEntity.ok().body(newDto); + } + + @DeleteMapping(value = "/{id}") + public ResponseEntity delete(@PathVariable Long id) { + service.delete(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/devsuperior/bds04/controllers/EventController.java b/src/main/java/com/devsuperior/bds04/controllers/EventController.java new file mode 100644 index 00000000..5b5e4cd1 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/controllers/EventController.java @@ -0,0 +1,62 @@ +package com.devsuperior.bds04.controllers; + +import java.net.URI; + +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.devsuperior.bds04.dto.EventDTO; +import com.devsuperior.bds04.services.EventService; + +@RestController +@RequestMapping(value = "/events") +public class EventController { + + @Autowired + private EventService service; + + @GetMapping + public ResponseEntity> findAll(Pageable pageable) { + Page list = service.findAllPaged(pageable); + return ResponseEntity.ok().body(list); + } + + @GetMapping(value = "/{id}") + public ResponseEntity findById(@PathVariable Long id) { + EventDTO dto = service.findById(id); + return ResponseEntity.ok().body(dto); + } + + @PostMapping + public ResponseEntity insert(@Valid @RequestBody EventDTO dto) { + EventDTO newDto = service.insert(dto); + URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(newDto.getId()).toUri(); + return ResponseEntity.created(uri).body(newDto); + } + + @PutMapping(value = "/{id}") + public ResponseEntity update(@PathVariable Long id,@Valid @RequestBody EventDTO dto) { + EventDTO newDto = service.update(id, dto); + return ResponseEntity.ok().body(newDto); + } + + @DeleteMapping(value = "/{id}") + public ResponseEntity delete(@PathVariable Long id) { + service.delete(id); + return ResponseEntity.noContent().build(); + } + +} diff --git a/src/main/java/com/devsuperior/bds04/controllers/exceptions/FieldMessage.java b/src/main/java/com/devsuperior/bds04/controllers/exceptions/FieldMessage.java new file mode 100644 index 00000000..2084ce6f --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/controllers/exceptions/FieldMessage.java @@ -0,0 +1,37 @@ +package com.devsuperior.bds04.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) { + super(); + 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/bds04/controllers/exceptions/ResourceExceptionHandler.java b/src/main/java/com/devsuperior/bds04/controllers/exceptions/ResourceExceptionHandler.java new file mode 100644 index 00000000..a503b053 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/controllers/exceptions/ResourceExceptionHandler.java @@ -0,0 +1,67 @@ +package com.devsuperior.bds04.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.bds04.services.exceptions.DatabaseException; +import com.devsuperior.bds04.services.exceptions.ResourceNotFoundException; + +@ControllerAdvice +public class ResourceExceptionHandler { + + @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); + } + +} diff --git a/src/main/java/com/devsuperior/bds04/controllers/exceptions/StandardError.java b/src/main/java/com/devsuperior/bds04/controllers/exceptions/StandardError.java new file mode 100644 index 00000000..6c58cde9 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/controllers/exceptions/StandardError.java @@ -0,0 +1,57 @@ +package com.devsuperior.bds04.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/bds04/controllers/exceptions/ValidationError.java b/src/main/java/com/devsuperior/bds04/controllers/exceptions/ValidationError.java new file mode 100644 index 00000000..708df12c --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/controllers/exceptions/ValidationError.java @@ -0,0 +1,19 @@ +package com.devsuperior.bds04.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/bds04/services/EventService.java b/src/main/java/com/devsuperior/bds04/services/EventService.java index b57dd9e9..4ee8e5fb 100644 --- a/src/main/java/com/devsuperior/bds04/services/EventService.java +++ b/src/main/java/com/devsuperior/bds04/services/EventService.java @@ -1,5 +1,71 @@ package com.devsuperior.bds04.services; +import java.util.Optional; + +import javax.persistence.EntityNotFoundException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.devsuperior.bds04.dto.EventDTO; +import com.devsuperior.bds04.entities.Event; +import com.devsuperior.bds04.repositories.EventRepository; +import com.devsuperior.bds04.services.exceptions.DatabaseException; +import com.devsuperior.bds04.services.exceptions.ResourceNotFoundException; + +@Service public class EventService { + @Autowired + private EventRepository repository; + + @Transactional(readOnly = true) + public Page findAllPaged(Pageable pageable) { + Page list = repository.findAll(pageable); + + return list.map(x -> new EventDTO(x)); + } + + @Transactional(readOnly = true) + public EventDTO findById(Long id) { + Optional obj = repository.findById(id); + Event entity = obj.orElseThrow(() -> new ResourceNotFoundException("Entity Not Found!")); + return new EventDTO(entity); + } + + @Transactional + public EventDTO insert(EventDTO dto) { + Event entity = new Event(); + entity.setName(dto.getName()); + entity = repository.save(entity); + return new EventDTO(entity); + } + + @Transactional + public EventDTO update(Long id, EventDTO dto) { + try { + Event entity = repository.getOne(id); + entity.setName(dto.getName()); + entity = repository.save(entity); + return new EventDTO(entity); + } catch (EntityNotFoundException e) { + throw new ResourceNotFoundException("ID Not Found! ID: " + id); + } + } + + public void delete(Long id) { + try { + repository.deleteById(id); + } catch (EmptyResultDataAccessException e) { + throw new ResourceNotFoundException("ID Not Found! ID: " + id); + } catch (DataIntegrityViolationException e) { + throw new DatabaseException("Integrity Violation!"); + } + } + } From 3751dc5219daab4e3928e379fcd4f58fe3b73626 Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Mon, 5 Sep 2022 21:35:40 -0300 Subject: [PATCH 05/13] User CRUD Implementation --- pom.xml | 6 + .../devsuperior/bds04/config/AppConfig.java | 14 +++ .../bds04/config/SecurityConfig.java | 16 +++ .../bds04/controllers/UserController.java | 59 +++++++++ .../bds04/controllers/UserInsertDTO.java | 22 ++++ .../com/devsuperior/bds04/dto/RoleDTO.java | 46 +++++++ .../com/devsuperior/bds04/dto/UserDTO.java | 74 +++++++++++ .../com/devsuperior/bds04/entities/Role.java | 67 ++++++++++ .../com/devsuperior/bds04/entities/User.java | 115 ++++++++++++++++++ .../bds04/repositories/RoleRepository.java | 11 ++ .../bds04/repositories/UserRepository.java | 11 ++ .../bds04/services/UserService.java | 97 +++++++++++++++ 12 files changed, 538 insertions(+) create mode 100644 src/main/java/com/devsuperior/bds04/config/AppConfig.java create mode 100644 src/main/java/com/devsuperior/bds04/config/SecurityConfig.java create mode 100644 src/main/java/com/devsuperior/bds04/controllers/UserController.java create mode 100644 src/main/java/com/devsuperior/bds04/controllers/UserInsertDTO.java create mode 100644 src/main/java/com/devsuperior/bds04/dto/RoleDTO.java create mode 100644 src/main/java/com/devsuperior/bds04/dto/UserDTO.java create mode 100644 src/main/java/com/devsuperior/bds04/entities/Role.java create mode 100644 src/main/java/com/devsuperior/bds04/entities/User.java create mode 100644 src/main/java/com/devsuperior/bds04/repositories/RoleRepository.java create mode 100644 src/main/java/com/devsuperior/bds04/repositories/UserRepository.java create mode 100644 src/main/java/com/devsuperior/bds04/services/UserService.java diff --git a/pom.xml b/pom.xml index 58acb216..f291e95e 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,12 @@ + + + org.springframework.boot + spring-boot-starter-security + + org.springframework.boot spring-boot-starter-web diff --git a/src/main/java/com/devsuperior/bds04/config/AppConfig.java b/src/main/java/com/devsuperior/bds04/config/AppConfig.java new file mode 100644 index 00000000..0ef21a32 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/config/AppConfig.java @@ -0,0 +1,14 @@ +package com.devsuperior.bds04.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +@Configuration +public class AppConfig { + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/devsuperior/bds04/config/SecurityConfig.java b/src/main/java/com/devsuperior/bds04/config/SecurityConfig.java new file mode 100644 index 00000000..a32bf3ad --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/config/SecurityConfig.java @@ -0,0 +1,16 @@ +package com.devsuperior.bds04.config; + +import org.springframework.context.annotation.Configuration; +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; + +@Configuration +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring().antMatchers("/**"); + } +} diff --git a/src/main/java/com/devsuperior/bds04/controllers/UserController.java b/src/main/java/com/devsuperior/bds04/controllers/UserController.java new file mode 100644 index 00000000..68d22af2 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/controllers/UserController.java @@ -0,0 +1,59 @@ +package com.devsuperior.bds04.controllers; + +import java.net.URI; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.devsuperior.bds04.dto.UserDTO; +import com.devsuperior.bds04.services.UserService; + +@RestController +@RequestMapping(value = "/users") +public class UserController { + + @Autowired + private UserService service; + + @GetMapping + public ResponseEntity> findAll(Pageable pageable) { + Page list = service.findAllPaged(pageable); + return ResponseEntity.ok().body(list); + } + + @GetMapping(value = "/{id}") + public ResponseEntity findById(@PathVariable Long id) { + UserDTO dto = service.findById(id); + return ResponseEntity.ok().body(dto); + } + + @PostMapping + public ResponseEntity insert(@RequestBody UserInsertDTO dto) { + UserDTO newDto = service.insert(dto); + URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(newDto.getId()).toUri(); + return ResponseEntity.created(uri).body(newDto); + } + + @PutMapping(value = "/{id}") + public ResponseEntity update(@PathVariable Long id,@RequestBody UserDTO dto) { + dto = service.update(id, dto); + return ResponseEntity.ok().body(dto); + } + + @DeleteMapping(value = "/{id}") + public ResponseEntity delete(@PathVariable Long id) { + service.delete(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/devsuperior/bds04/controllers/UserInsertDTO.java b/src/main/java/com/devsuperior/bds04/controllers/UserInsertDTO.java new file mode 100644 index 00000000..eedfdeac --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/controllers/UserInsertDTO.java @@ -0,0 +1,22 @@ +package com.devsuperior.bds04.controllers; + +import com.devsuperior.bds04.dto.UserDTO; + + public class UserInsertDTO extends UserDTO{ + private static final long serialVersionUID = 1L; + + private String password; + + UserInsertDTO() { + super(); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + } diff --git a/src/main/java/com/devsuperior/bds04/dto/RoleDTO.java b/src/main/java/com/devsuperior/bds04/dto/RoleDTO.java new file mode 100644 index 00000000..0b0de5ca --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/dto/RoleDTO.java @@ -0,0 +1,46 @@ +package com.devsuperior.bds04.dto; + +import java.io.Serializable; +import java.util.Set; + +import com.devsuperior.bds04.entities.Role; +import com.devsuperior.bds04.entities.User; + +public class RoleDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private Long id; + private String authority; + + public RoleDTO() { + } + + public RoleDTO(Long id, String authority, Set users) { + super(); + this.id = id; + this.authority = authority; + } + + public RoleDTO(Role role) { + super(); + id = role.getId(); + authority = role.getAuthhority(); + } + + 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; + } + +} diff --git a/src/main/java/com/devsuperior/bds04/dto/UserDTO.java b/src/main/java/com/devsuperior/bds04/dto/UserDTO.java new file mode 100644 index 00000000..1a319b73 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/dto/UserDTO.java @@ -0,0 +1,74 @@ +package com.devsuperior.bds04.dto; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +import com.devsuperior.bds04.entities.User; + +public class UserDTO implements Serializable{ + private static final long serialVersionUID = 1L; + + private Long id; + private String firstName; + private String lastName; + private String email; + + Set roles = new HashSet<>(); + + public UserDTO() { + } + + public UserDTO(Long id, String firstName, String lastName, String email) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + + } + + public UserDTO(User entity) { + id = entity.getId(); + firstName = entity.getFirstName(); + lastName = entity.getLastName(); + email = entity.getEmail(); + entity.getRoles().forEach(role -> this.roles.add(new RoleDTO(role))); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Set getRoles() { + return roles; + } + +} diff --git a/src/main/java/com/devsuperior/bds04/entities/Role.java b/src/main/java/com/devsuperior/bds04/entities/Role.java new file mode 100644 index 00000000..6b061702 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/entities/Role.java @@ -0,0 +1,67 @@ +package com.devsuperior.bds04.entities; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.Table; + +@Entity +@Table(name="tb_user") +public class Role implements Serializable { + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String authority; + + @ManyToMany(mappedBy = "roles") + private Set users = new HashSet<>(); + + public Role() { + super(); + } + + 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 getAuthhority() { + return authority; + } + public void setAuthhority(String authhority) { + this.authority = authhority; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @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; + return Objects.equals(id, other.id); + } + +} diff --git a/src/main/java/com/devsuperior/bds04/entities/User.java b/src/main/java/com/devsuperior/bds04/entities/User.java new file mode 100644 index 00000000..0823c075 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/entities/User.java @@ -0,0 +1,115 @@ +package com.devsuperior.bds04.entities; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import javax.persistence.Column; +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.Table; + +@Entity +@Table(name="tb_user") +public class User implements Serializable { + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String firstName; + private String lastName; + + @Column(unique=true) + 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<>(); + + public User() { + super(); + } + + public User(Long id, String firstName, String lastName, String email, String password, Set roles) { + super(); + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.password = password; + this.roles = roles; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + 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; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @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; + return Objects.equals(id, other.id); + } + +} diff --git a/src/main/java/com/devsuperior/bds04/repositories/RoleRepository.java b/src/main/java/com/devsuperior/bds04/repositories/RoleRepository.java new file mode 100644 index 00000000..7bff0264 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/repositories/RoleRepository.java @@ -0,0 +1,11 @@ +package com.devsuperior.bds04.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.devsuperior.bds04.entities.Role; + +@Repository +public interface RoleRepository extends JpaRepository{ + +} diff --git a/src/main/java/com/devsuperior/bds04/repositories/UserRepository.java b/src/main/java/com/devsuperior/bds04/repositories/UserRepository.java new file mode 100644 index 00000000..145ae749 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/repositories/UserRepository.java @@ -0,0 +1,11 @@ +package com.devsuperior.bds04.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.devsuperior.bds04.entities.User; + +@Repository +public interface UserRepository extends JpaRepository{ + +} diff --git a/src/main/java/com/devsuperior/bds04/services/UserService.java b/src/main/java/com/devsuperior/bds04/services/UserService.java new file mode 100644 index 00000000..34876a91 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/UserService.java @@ -0,0 +1,97 @@ +package com.devsuperior.bds04.services; + +import java.util.Optional; + +import javax.persistence.EntityNotFoundException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.devsuperior.bds04.controllers.UserInsertDTO; +import com.devsuperior.bds04.dto.RoleDTO; +import com.devsuperior.bds04.dto.UserDTO; +import com.devsuperior.bds04.entities.Role; +import com.devsuperior.bds04.entities.User; +import com.devsuperior.bds04.repositories.RoleRepository; +import com.devsuperior.bds04.repositories.UserRepository; +import com.devsuperior.bds04.services.exceptions.DatabaseException; +import com.devsuperior.bds04.services.exceptions.ResourceNotFoundException; + +@Service +public class UserService { + + @Autowired + private BCryptPasswordEncoder passwordEncoder; + + @Autowired + private UserRepository repository; + + @Autowired + private RoleRepository roleRepository; + + @Transactional(readOnly = true) + public Page findAllPaged(Pageable pageable) { + Page list = repository.findAll(pageable); + + return list.map(x -> new UserDTO(x)); + } + + @Transactional(readOnly = true) + public UserDTO findById(Long id) { + Optional obj = repository.findById(id); + User entity = obj.orElseThrow(() -> new ResourceNotFoundException("Entity Not Found!")); + return new UserDTO(entity); + } + + @Transactional + public UserDTO insert(UserInsertDTO dto) { + User entity = new User(); + copyDtoToEntity(dto, entity); + entity.setPassword(passwordEncoder.encode(dto.getPassword())); + entity = repository.save(entity); + return new UserDTO(entity); + } + + @Transactional + public UserDTO update(Long id, UserDTO dto) { + try { + User entity = repository.getOne(id); + copyDtoToEntity(dto, entity); + entity = repository.save(entity); + return new UserDTO(entity); + } catch (EntityNotFoundException e) { + throw new ResourceNotFoundException("ID Not Found! ID: " + id); + } + } + + public void delete(Long id) { + try { + repository.deleteById(id); + }catch(EmptyResultDataAccessException e) { + throw new ResourceNotFoundException("ID Not Found! ID: " + id ); + }catch(DataIntegrityViolationException e) { + throw new DatabaseException("Integrity Violation!"); + } + } + + + private void copyDtoToEntity(UserDTO dto, User entity) { + entity.setFirstName(dto.getFirstName()); + entity.setLastName(dto.getLastName()); + entity.setEmail(dto.getEmail()); + + entity.getRoles().clear(); + for (RoleDTO roleDto : dto.getRoles()) { + Role role = roleRepository.getOne(roleDto.getId()); + entity.getRoles().add(role); + } + + } + +} From 4a425fc589c2a146484d1347f4e28ebf67c3ed3c Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Fri, 9 Sep 2022 22:15:44 -0300 Subject: [PATCH 06/13] First Validation (Bean Configuration) --- .../bds04/controllers/UserController.java | 1 + .../bds04/controllers/UserInsertDTO.java | 22 ------------------- .../com/devsuperior/bds04/dto/CityDTO.java | 3 +++ .../com/devsuperior/bds04/dto/EventDTO.java | 7 ++++++ .../com/devsuperior/bds04/dto/UserDTO.java | 5 +++++ .../devsuperior/bds04/dto/UserInsertDTO.java | 22 +++++++++++++++++++ .../bds04/services/UserService.java | 2 +- 7 files changed, 39 insertions(+), 23 deletions(-) delete mode 100644 src/main/java/com/devsuperior/bds04/controllers/UserInsertDTO.java create mode 100644 src/main/java/com/devsuperior/bds04/dto/UserInsertDTO.java diff --git a/src/main/java/com/devsuperior/bds04/controllers/UserController.java b/src/main/java/com/devsuperior/bds04/controllers/UserController.java index 68d22af2..0f1217cb 100644 --- a/src/main/java/com/devsuperior/bds04/controllers/UserController.java +++ b/src/main/java/com/devsuperior/bds04/controllers/UserController.java @@ -17,6 +17,7 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import com.devsuperior.bds04.dto.UserDTO; +import com.devsuperior.bds04.dto.UserInsertDTO; import com.devsuperior.bds04.services.UserService; @RestController diff --git a/src/main/java/com/devsuperior/bds04/controllers/UserInsertDTO.java b/src/main/java/com/devsuperior/bds04/controllers/UserInsertDTO.java deleted file mode 100644 index eedfdeac..00000000 --- a/src/main/java/com/devsuperior/bds04/controllers/UserInsertDTO.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.devsuperior.bds04.controllers; - -import com.devsuperior.bds04.dto.UserDTO; - - public class UserInsertDTO extends UserDTO{ - private static final long serialVersionUID = 1L; - - private String password; - - UserInsertDTO() { - super(); - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - } diff --git a/src/main/java/com/devsuperior/bds04/dto/CityDTO.java b/src/main/java/com/devsuperior/bds04/dto/CityDTO.java index d7cf8420..a3100cf9 100644 --- a/src/main/java/com/devsuperior/bds04/dto/CityDTO.java +++ b/src/main/java/com/devsuperior/bds04/dto/CityDTO.java @@ -2,12 +2,15 @@ import java.io.Serializable; +import javax.validation.constraints.NotBlank; + import com.devsuperior.bds04.entities.City; public class CityDTO implements Serializable { private static final long serialVersionUID = 1L; private Long id; + @NotBlank (message = "Campo requerido") private String name; public CityDTO() { diff --git a/src/main/java/com/devsuperior/bds04/dto/EventDTO.java b/src/main/java/com/devsuperior/bds04/dto/EventDTO.java index 0a3024d3..a442d160 100644 --- a/src/main/java/com/devsuperior/bds04/dto/EventDTO.java +++ b/src/main/java/com/devsuperior/bds04/dto/EventDTO.java @@ -3,15 +3,22 @@ import java.io.Serializable; import java.time.LocalDate; +import javax.validation.constraints.FutureOrPresent; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + import com.devsuperior.bds04.entities.Event; public class EventDTO implements Serializable { private static final long serialVersionUID = 1L; private Long id; + @NotBlank (message = "Campo requerido") private String name; + @FutureOrPresent private LocalDate date; private String url; + @NotNull private Long cityId; public EventDTO() { diff --git a/src/main/java/com/devsuperior/bds04/dto/UserDTO.java b/src/main/java/com/devsuperior/bds04/dto/UserDTO.java index 1a319b73..103af434 100644 --- a/src/main/java/com/devsuperior/bds04/dto/UserDTO.java +++ b/src/main/java/com/devsuperior/bds04/dto/UserDTO.java @@ -4,14 +4,19 @@ import java.util.HashSet; import java.util.Set; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; + import com.devsuperior.bds04.entities.User; public class UserDTO implements Serializable{ private static final long serialVersionUID = 1L; private Long id; + @NotBlank(message = "Campo obrigatório") private String firstName; private String lastName; + @Email(message = "Digite um e-mail válido") private String email; Set roles = new HashSet<>(); diff --git a/src/main/java/com/devsuperior/bds04/dto/UserInsertDTO.java b/src/main/java/com/devsuperior/bds04/dto/UserInsertDTO.java new file mode 100644 index 00000000..4cd36bb7 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/dto/UserInsertDTO.java @@ -0,0 +1,22 @@ +package com.devsuperior.bds04.dto; + +import javax.validation.constraints.NotBlank; + +public class UserInsertDTO extends UserDTO { + private static final long serialVersionUID = 1L; + + @NotBlank(message = "Campo requerido") + private String password; + + UserInsertDTO() { + super(); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/com/devsuperior/bds04/services/UserService.java b/src/main/java/com/devsuperior/bds04/services/UserService.java index 34876a91..425cad0c 100644 --- a/src/main/java/com/devsuperior/bds04/services/UserService.java +++ b/src/main/java/com/devsuperior/bds04/services/UserService.java @@ -13,9 +13,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.devsuperior.bds04.controllers.UserInsertDTO; import com.devsuperior.bds04.dto.RoleDTO; import com.devsuperior.bds04.dto.UserDTO; +import com.devsuperior.bds04.dto.UserInsertDTO; import com.devsuperior.bds04.entities.Role; import com.devsuperior.bds04.entities.User; import com.devsuperior.bds04.repositories.RoleRepository; From 67be1df38be4d3a34af61d393d9d9d110e83a7f7 Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Fri, 9 Sep 2022 22:32:14 -0300 Subject: [PATCH 07/13] Email validation with Constrain Validator --- .../com/devsuperior/bds04/controllers/UserController.java | 6 ++++-- .../bds04/services/validation/UserInsertValid.java | 5 +++++ .../bds04/services/validation/UserInsertValidator.java | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/devsuperior/bds04/services/validation/UserInsertValid.java create mode 100644 src/main/java/com/devsuperior/bds04/services/validation/UserInsertValidator.java diff --git a/src/main/java/com/devsuperior/bds04/controllers/UserController.java b/src/main/java/com/devsuperior/bds04/controllers/UserController.java index 0f1217cb..4f566525 100644 --- a/src/main/java/com/devsuperior/bds04/controllers/UserController.java +++ b/src/main/java/com/devsuperior/bds04/controllers/UserController.java @@ -2,6 +2,8 @@ import java.net.URI; +import javax.validation.Valid; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -40,14 +42,14 @@ public ResponseEntity findById(@PathVariable Long id) { } @PostMapping - public ResponseEntity insert(@RequestBody UserInsertDTO dto) { + public ResponseEntity insert(@Valid @RequestBody UserInsertDTO dto) { UserDTO newDto = service.insert(dto); URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(newDto.getId()).toUri(); return ResponseEntity.created(uri).body(newDto); } @PutMapping(value = "/{id}") - public ResponseEntity update(@PathVariable Long id,@RequestBody UserDTO dto) { + public ResponseEntity update(@PathVariable Long id,@Valid @RequestBody UserDTO dto) { dto = service.update(id, dto); return ResponseEntity.ok().body(dto); } diff --git a/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValid.java b/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValid.java new file mode 100644 index 00000000..ca6dd3b0 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValid.java @@ -0,0 +1,5 @@ +package com.devsuperior.bds04.services.validation; + +public class UserInsertValid { + +} diff --git a/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValidator.java b/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValidator.java new file mode 100644 index 00000000..fb793685 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValidator.java @@ -0,0 +1,5 @@ +package com.devsuperior.bds04.services.validation; + +public class UserInsertValidator { + +} From 537df8a651cc19d1f20f05224f21e7f99afec1e4 Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Fri, 9 Sep 2022 22:47:49 -0300 Subject: [PATCH 08/13] User update validations (UserUpdateValidator) --- src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java | 5 +++++ .../bds04/services/validation/UserUpdateValid.java | 5 +++++ .../bds04/services/validation/UserUpdateValidator.java | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java create mode 100644 src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValid.java create mode 100644 src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValidator.java diff --git a/src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java b/src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java new file mode 100644 index 00000000..17a10f61 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java @@ -0,0 +1,5 @@ +package com.devsuperior.bds04.dto; + +public class UserUpdateDTO { + +} diff --git a/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValid.java b/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValid.java new file mode 100644 index 00000000..035a1d06 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValid.java @@ -0,0 +1,5 @@ +package com.devsuperior.bds04.services.validation; + +public class UserUpdateValid { + +} diff --git a/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValidator.java b/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValidator.java new file mode 100644 index 00000000..4bdcffa9 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValidator.java @@ -0,0 +1,5 @@ +package com.devsuperior.bds04.services.validation; + +public class UserUpdateValidator { + +} From dbd8363d284b1c51529367ee384229c2cb37160f Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Fri, 9 Sep 2022 22:52:01 -0300 Subject: [PATCH 09/13] Spring Security Configs (UserDetails, Web Security class) --- ...rityConfig.java => WebSecurityConfig.java} | 2 +- .../bds04/controllers/UserController.java | 7 +-- .../exceptions/ResourceExceptionHandler.java | 5 +- .../devsuperior/bds04/dto/UserInsertDTO.java | 3 ++ .../devsuperior/bds04/dto/UserUpdateDTO.java | 6 ++- .../bds04/repositories/UserRepository.java | 2 + .../bds04/services/UserService.java | 3 +- .../services/validation/UserInsertValid.java | 18 ++++++- .../validation/UserInsertValidator.java | 39 ++++++++++++++- .../services/validation/UserUpdateValid.java | 18 ++++++- .../validation/UserUpdateValidator.java | 49 ++++++++++++++++++- 11 files changed, 139 insertions(+), 13 deletions(-) rename src/main/java/com/devsuperior/bds04/config/{SecurityConfig.java => WebSecurityConfig.java} (88%) diff --git a/src/main/java/com/devsuperior/bds04/config/SecurityConfig.java b/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java similarity index 88% rename from src/main/java/com/devsuperior/bds04/config/SecurityConfig.java rename to src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java index a32bf3ad..7233b69f 100644 --- a/src/main/java/com/devsuperior/bds04/config/SecurityConfig.java +++ b/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java @@ -7,7 +7,7 @@ @Configuration @EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(WebSecurity web) throws Exception { diff --git a/src/main/java/com/devsuperior/bds04/controllers/UserController.java b/src/main/java/com/devsuperior/bds04/controllers/UserController.java index 4f566525..70b30850 100644 --- a/src/main/java/com/devsuperior/bds04/controllers/UserController.java +++ b/src/main/java/com/devsuperior/bds04/controllers/UserController.java @@ -20,6 +20,7 @@ import com.devsuperior.bds04.dto.UserDTO; import com.devsuperior.bds04.dto.UserInsertDTO; +import com.devsuperior.bds04.dto.UserUpdateDTO; import com.devsuperior.bds04.services.UserService; @RestController @@ -49,9 +50,9 @@ public ResponseEntity insert(@Valid @RequestBody UserInsertDTO dto) { } @PutMapping(value = "/{id}") - public ResponseEntity update(@PathVariable Long id,@Valid @RequestBody UserDTO dto) { - dto = service.update(id, dto); - return ResponseEntity.ok().body(dto); + public ResponseEntity update(@PathVariable Long id,@Valid @RequestBody UserUpdateDTO dto) { + UserDTO newDto = service.update(id, dto); + return ResponseEntity.ok().body(newDto); } @DeleteMapping(value = "/{id}") diff --git a/src/main/java/com/devsuperior/bds04/controllers/exceptions/ResourceExceptionHandler.java b/src/main/java/com/devsuperior/bds04/controllers/exceptions/ResourceExceptionHandler.java index a503b053..50a4981c 100644 --- a/src/main/java/com/devsuperior/bds04/controllers/exceptions/ResourceExceptionHandler.java +++ b/src/main/java/com/devsuperior/bds04/controllers/exceptions/ResourceExceptionHandler.java @@ -56,12 +56,11 @@ public ResponseEntity validation(MethodArgumentNotValidExceptio 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); } - } diff --git a/src/main/java/com/devsuperior/bds04/dto/UserInsertDTO.java b/src/main/java/com/devsuperior/bds04/dto/UserInsertDTO.java index 4cd36bb7..1ec8de95 100644 --- a/src/main/java/com/devsuperior/bds04/dto/UserInsertDTO.java +++ b/src/main/java/com/devsuperior/bds04/dto/UserInsertDTO.java @@ -2,6 +2,9 @@ import javax.validation.constraints.NotBlank; +import com.devsuperior.bds04.services.validation.UserInsertValid; + +@UserInsertValid public class UserInsertDTO extends UserDTO { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java b/src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java index 17a10f61..c28dfee3 100644 --- a/src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java +++ b/src/main/java/com/devsuperior/bds04/dto/UserUpdateDTO.java @@ -1,5 +1,9 @@ package com.devsuperior.bds04.dto; -public class UserUpdateDTO { +import com.devsuperior.bds04.services.validation.UserUpdateValid; + +@UserUpdateValid +public class UserUpdateDTO extends UserDTO { + private static final long serialVersionUID = 1L; } diff --git a/src/main/java/com/devsuperior/bds04/repositories/UserRepository.java b/src/main/java/com/devsuperior/bds04/repositories/UserRepository.java index 145ae749..cd9769c3 100644 --- a/src/main/java/com/devsuperior/bds04/repositories/UserRepository.java +++ b/src/main/java/com/devsuperior/bds04/repositories/UserRepository.java @@ -8,4 +8,6 @@ @Repository public interface UserRepository extends JpaRepository{ + User findByEmail(String email); + } diff --git a/src/main/java/com/devsuperior/bds04/services/UserService.java b/src/main/java/com/devsuperior/bds04/services/UserService.java index 425cad0c..3c82df84 100644 --- a/src/main/java/com/devsuperior/bds04/services/UserService.java +++ b/src/main/java/com/devsuperior/bds04/services/UserService.java @@ -16,6 +16,7 @@ import com.devsuperior.bds04.dto.RoleDTO; import com.devsuperior.bds04.dto.UserDTO; import com.devsuperior.bds04.dto.UserInsertDTO; +import com.devsuperior.bds04.dto.UserUpdateDTO; import com.devsuperior.bds04.entities.Role; import com.devsuperior.bds04.entities.User; import com.devsuperior.bds04.repositories.RoleRepository; @@ -59,7 +60,7 @@ public UserDTO insert(UserInsertDTO dto) { } @Transactional - public UserDTO update(Long id, UserDTO dto) { + public UserDTO update(Long id, UserUpdateDTO dto) { try { User entity = repository.getOne(id); copyDtoToEntity(dto, entity); diff --git a/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValid.java b/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValid.java index ca6dd3b0..2cce42d0 100644 --- a/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValid.java +++ b/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValid.java @@ -1,5 +1,21 @@ package com.devsuperior.bds04.services.validation; -public class UserInsertValid { +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.validation.Constraint; +import javax.validation.Payload; + +@Constraint(validatedBy = UserInsertValidator.class) +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) + +public @interface UserInsertValid { + String message() default "Validation error"; + + Class[] groups() default {}; + + Class[] payload() default {}; } diff --git a/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValidator.java b/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValidator.java index fb793685..7b889547 100644 --- a/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValidator.java +++ b/src/main/java/com/devsuperior/bds04/services/validation/UserInsertValidator.java @@ -1,5 +1,42 @@ package com.devsuperior.bds04.services.validation; -public class UserInsertValidator { +import java.util.ArrayList; +import java.util.List; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.devsuperior.bds04.controllers.exceptions.FieldMessage; +import com.devsuperior.bds04.dto.UserInsertDTO; +import com.devsuperior.bds04.entities.User; +import com.devsuperior.bds04.repositories.UserRepository; + +public class UserInsertValidator implements ConstraintValidator { + + @Autowired + private UserRepository repository; + + @Override + public void initialize(UserInsertValid ann) { + } + + @Override + public boolean isValid(UserInsertDTO dto, ConstraintValidatorContext context) { + + List list = new ArrayList<>(); + + User user = repository.findByEmail(dto.getEmail()); + if (user != null) { + list.add(new FieldMessage("email", "Este e mail já está cadastrado!")); + } + + for (FieldMessage e : list) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(e.getMessage()).addPropertyNode(e.getFieldName()) + .addConstraintViolation(); + } + return list.isEmpty(); + } } diff --git a/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValid.java b/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValid.java index 035a1d06..95003d0a 100644 --- a/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValid.java +++ b/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValid.java @@ -1,5 +1,21 @@ package com.devsuperior.bds04.services.validation; -public class UserUpdateValid { +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.validation.Constraint; +import javax.validation.Payload; + +@Constraint(validatedBy = UserUpdateValidator.class) +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) + +public @interface UserUpdateValid { + String message() default "Validation error"; + + Class[] groups() default {}; + + Class[] payload() default {}; } diff --git a/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValidator.java b/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValidator.java index 4bdcffa9..7354b961 100644 --- a/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValidator.java +++ b/src/main/java/com/devsuperior/bds04/services/validation/UserUpdateValidator.java @@ -1,5 +1,52 @@ package com.devsuperior.bds04.services.validation; -public class UserUpdateValidator { +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.servlet.HandlerMapping; + +import com.devsuperior.bds04.controllers.exceptions.FieldMessage; +import com.devsuperior.bds04.dto.UserUpdateDTO; +import com.devsuperior.bds04.entities.User; +import com.devsuperior.bds04.repositories.UserRepository; + +public class UserUpdateValidator implements ConstraintValidator { + + @Autowired + private HttpServletRequest request; + + @Autowired + private UserRepository repository; + + @Override + public void initialize(UserUpdateValid ann) { + } + + @Override + public boolean isValid(UserUpdateDTO dto, ConstraintValidatorContext context) { + + @SuppressWarnings("unchecked") + var uriVars = (Map)request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + long userId = Long.parseLong(uriVars.get("id")); + + List list = new ArrayList<>(); + + User user = repository.findByEmail(dto.getEmail()); + if(user != null && userId != user.getId()) { + list.add(new FieldMessage("email", "Este e mail já está cadastrado!")); + } + + for (FieldMessage e : list) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(e.getMessage()).addPropertyNode(e.getFieldName()) + .addConstraintViolation(); + } + return list.isEmpty(); + } } From 26c47928dc95be8a271c92d6c10ff083b891f156 Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Fri, 9 Sep 2022 23:31:37 -0300 Subject: [PATCH 10/13] Spring OAuth 2 (AuthenticationServer) --- .../devsuperior/bds04/config/AuthorizationServerConfig.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java diff --git a/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java b/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java new file mode 100644 index 00000000..9e61703a --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java @@ -0,0 +1,5 @@ +package com.devsuperior.bds04.config; + +public class AuthorizationServerConfig { + +} From 3122906dfab33e0bd654f04168f5183bb8a3b814 Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Fri, 9 Sep 2022 23:42:50 -0300 Subject: [PATCH 11/13] Setting environment variables --- .../devsuperior/bds04/config/AppConfig.java | 18 ++++++ .../config/AuthorizationServerConfig.java | 60 ++++++++++++++++++- .../bds04/config/WebSecurityConfig.java | 28 ++++++++- .../com/devsuperior/bds04/dto/RoleDTO.java | 2 +- .../com/devsuperior/bds04/entities/Role.java | 4 +- .../com/devsuperior/bds04/entities/User.java | 43 ++++++++++++- .../bds04/services/UserService.java | 21 ++++++- src/main/resources/application.properties | 8 ++- 8 files changed, 175 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/devsuperior/bds04/config/AppConfig.java b/src/main/java/com/devsuperior/bds04/config/AppConfig.java index 0ef21a32..95d0f7fc 100644 --- a/src/main/java/com/devsuperior/bds04/config/AppConfig.java +++ b/src/main/java/com/devsuperior/bds04/config/AppConfig.java @@ -1,14 +1,32 @@ package com.devsuperior.bds04.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/bds04/config/AuthorizationServerConfig.java b/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java index 9e61703a..9b6e66e4 100644 --- a/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java +++ b/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java @@ -1,5 +1,63 @@ package com.devsuperior.bds04.config; -public class AuthorizationServerConfig { +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.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.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; +@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 JwtTokenStore tokenStore; + + @Autowired + private AuthenticationManager authenticatorManager; + + + @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 { + endpoints.authenticationManager(authenticatorManager) + .tokenStore(tokenStore) + .accessTokenConverter(accessTokenConverter); + } } diff --git a/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java b/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java index 7233b69f..f4055140 100644 --- a/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java +++ b/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java @@ -1,16 +1,40 @@ package com.devsuperior.bds04.config; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +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.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 +@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private BCryptPasswordEncoder passwordEncoder; + + @Autowired + private UserDetailsService userDetailsService; + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); + } @Override public void configure(WebSecurity web) throws Exception { - web.ignoring().antMatchers("/**"); + web.ignoring().antMatchers("/actuator"); + } + + @Override + @Bean + protected AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); } } diff --git a/src/main/java/com/devsuperior/bds04/dto/RoleDTO.java b/src/main/java/com/devsuperior/bds04/dto/RoleDTO.java index 0b0de5ca..0f7fa7b0 100644 --- a/src/main/java/com/devsuperior/bds04/dto/RoleDTO.java +++ b/src/main/java/com/devsuperior/bds04/dto/RoleDTO.java @@ -24,7 +24,7 @@ public RoleDTO(Long id, String authority, Set users) { public RoleDTO(Role role) { super(); id = role.getId(); - authority = role.getAuthhority(); + authority = role.getAuthority(); } public Long getId() { diff --git a/src/main/java/com/devsuperior/bds04/entities/Role.java b/src/main/java/com/devsuperior/bds04/entities/Role.java index 6b061702..a2c341a3 100644 --- a/src/main/java/com/devsuperior/bds04/entities/Role.java +++ b/src/main/java/com/devsuperior/bds04/entities/Role.java @@ -40,10 +40,10 @@ public Long getId() { public void setId(Long id) { this.id = id; } - public String getAuthhority() { + public String getAuthority() { return authority; } - public void setAuthhority(String authhority) { + public void setAuthority(String authhority) { this.authority = authhority; } diff --git a/src/main/java/com/devsuperior/bds04/entities/User.java b/src/main/java/com/devsuperior/bds04/entities/User.java index 0823c075..81a43a0f 100644 --- a/src/main/java/com/devsuperior/bds04/entities/User.java +++ b/src/main/java/com/devsuperior/bds04/entities/User.java @@ -1,9 +1,11 @@ package com.devsuperior.bds04.entities; import java.io.Serializable; +import java.util.Collection; import java.util.HashSet; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import javax.persistence.Column; import javax.persistence.Entity; @@ -16,9 +18,13 @@ import javax.persistence.ManyToMany; 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 Serializable { +public class User implements UserDetails, Serializable { private static final long serialVersionUID = 1L; @Id @@ -111,5 +117,40 @@ public boolean equals(Object obj) { User other = (User) obj; return Objects.equals(id, other.id); } + + @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() { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean isAccountNonLocked() { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean isEnabled() { + // TODO Auto-generated method stub + return true; + } } diff --git a/src/main/java/com/devsuperior/bds04/services/UserService.java b/src/main/java/com/devsuperior/bds04/services/UserService.java index 3c82df84..97ce9e8c 100644 --- a/src/main/java/com/devsuperior/bds04/services/UserService.java +++ b/src/main/java/com/devsuperior/bds04/services/UserService.java @@ -4,11 +4,16 @@ import javax.persistence.EntityNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -25,8 +30,10 @@ import com.devsuperior.bds04.services.exceptions.ResourceNotFoundException; @Service -public class UserService { +public class UserService implements UserDetailsService{ + private static Logger logger = LoggerFactory.getLogger(UserService.class); + @Autowired private BCryptPasswordEncoder passwordEncoder; @@ -95,4 +102,16 @@ private void copyDtoToEntity(UserDTO dto, User entity) { } + @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 not found!"); + } + logger.info("User Found: " + username); + return user; + } + } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a7dcd8af..ecc056c6 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:myapp} +security.oauth2.client.client-secret=${CLIENT_SECRET:myapp123} + +jwt.secret=${JWT_SECRET:MY-JWT-SECRET} +jwt.duration=${JWT_DURATION:86400} \ No newline at end of file From 9ddf375e7181bdf2bd3cd6470872d2ae31f0b917 Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Fri, 9 Sep 2022 23:59:45 -0300 Subject: [PATCH 12/13] Aditional Token Informations --- .../bds04/components/JwtTokenEnhancer.java | 34 +++++++++++++++++++ .../config/AuthorizationServerConfig.java | 14 +++++++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/devsuperior/bds04/components/JwtTokenEnhancer.java diff --git a/src/main/java/com/devsuperior/bds04/components/JwtTokenEnhancer.java b/src/main/java/com/devsuperior/bds04/components/JwtTokenEnhancer.java new file mode 100644 index 00000000..33352605 --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/components/JwtTokenEnhancer.java @@ -0,0 +1,34 @@ +package com.devsuperior.bds04.components; + +import java.util.HashMap; +import java.util.Map; + +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 com.devsuperior.bds04.entities.User; +import com.devsuperior.bds04.repositories.UserRepository; + +public class JwtTokenEnhancer implements TokenEnhancer { + + private UserRepository userRepository; + + @Override + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { + + User user = userRepository.findByEmail(authentication.getName()); + + Map map = new HashMap<>(); + map.put("userFirstName", user.getFirstName()); + map.put("userId", user.getId()); + + DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken; + token.setAdditionalInformation(map); + + return accessToken; + + } + +} diff --git a/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java b/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java index 9b6e66e4..c5fd4561 100644 --- a/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java +++ b/src/main/java/com/devsuperior/bds04/config/AuthorizationServerConfig.java @@ -1,5 +1,7 @@ package com.devsuperior.bds04.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; @@ -10,9 +12,12 @@ 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.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; +import com.devsuperior.bds04.components.JwtTokenEnhancer; + @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @@ -38,6 +43,8 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap @Autowired private AuthenticationManager authenticatorManager; + @Autowired + private JwtTokenEnhancer tokenEnhancer; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { @@ -56,8 +63,13 @@ public void configure(ClientDetailsServiceConfigurer clients) throws Exception { @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { + + TokenEnhancerChain chain = new TokenEnhancerChain(); + chain.setTokenEnhancers(Arrays.asList(accessTokenConverter, tokenEnhancer)); + endpoints.authenticationManager(authenticatorManager) .tokenStore(tokenStore) - .accessTokenConverter(accessTokenConverter); + .accessTokenConverter(accessTokenConverter) + .tokenEnhancer(chain); } } From 0c58f804149f7c9d65073831d27849b9fefe87ed Mon Sep 17 00:00:00 2001 From: Gabriel Santos de Almeida <1gabrielsantosdealmeida@gmail.com> Date: Sat, 10 Sep 2022 03:22:53 -0300 Subject: [PATCH 13/13] Refactor and Adjusts --- .../bds04/components/JwtTokenEnhancer.java | 4 ++ .../bds04/config/ResourceServerConfig.java | 49 +++++++++++++++++++ .../bds04/config/WebSecurityConfig.java | 1 - .../bds04/controllers/CityController.java | 5 +- .../com/devsuperior/bds04/dto/EventDTO.java | 13 +++-- .../com/devsuperior/bds04/entities/Event.java | 6 ++- .../com/devsuperior/bds04/entities/Role.java | 2 +- .../bds04/repositories/CityRepository.java | 2 + .../bds04/services/CityService.java | 2 +- .../bds04/services/EventService.java | 9 +++- src/main/resources/data.sql | 10 ++++ .../bds04/controllers/CityControllerIT.java | 6 +-- .../bds04/controllers/EventControllerIT.java | 12 ++--- 13 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/devsuperior/bds04/config/ResourceServerConfig.java diff --git a/src/main/java/com/devsuperior/bds04/components/JwtTokenEnhancer.java b/src/main/java/com/devsuperior/bds04/components/JwtTokenEnhancer.java index 33352605..83199b80 100644 --- a/src/main/java/com/devsuperior/bds04/components/JwtTokenEnhancer.java +++ b/src/main/java/com/devsuperior/bds04/components/JwtTokenEnhancer.java @@ -3,16 +3,20 @@ 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.bds04.entities.User; import com.devsuperior.bds04.repositories.UserRepository; +@Component public class JwtTokenEnhancer implements TokenEnhancer { + @Autowired private UserRepository userRepository; @Override diff --git a/src/main/java/com/devsuperior/bds04/config/ResourceServerConfig.java b/src/main/java/com/devsuperior/bds04/config/ResourceServerConfig.java new file mode 100644 index 00000000..b0c0c01f --- /dev/null +++ b/src/main/java/com/devsuperior/bds04/config/ResourceServerConfig.java @@ -0,0 +1,49 @@ +package com.devsuperior.bds04.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.http.HttpMethod; +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/**" }; + private static final String[] PUBLIC_GET = { "/cities/**", "/events/**" }; + private static final String[] CLIENT_POST = { "/events/**" }; + + @Override + public void configure(ResourceServerSecurityConfigurer resources) throws Exception { + resources.tokenStore(tokenStore); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + if(Arrays.asList(env.getActiveProfiles()).contains("test")) { + http.headers().frameOptions().disable(); + } + + http.authorizeRequests() + .antMatchers(PUBLIC).permitAll() + .antMatchers(HttpMethod.GET, PUBLIC_GET).permitAll() + .antMatchers(HttpMethod.POST, CLIENT_POST).hasAnyRole("CLIENT") + .anyRequest().hasAnyRole("ADMIN"); + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java b/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java index f4055140..ad9a3cd9 100644 --- a/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java +++ b/src/main/java/com/devsuperior/bds04/config/WebSecurityConfig.java @@ -1,7 +1,6 @@ package com.devsuperior.bds04.config; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; diff --git a/src/main/java/com/devsuperior/bds04/controllers/CityController.java b/src/main/java/com/devsuperior/bds04/controllers/CityController.java index dc55bb6e..966540b2 100644 --- a/src/main/java/com/devsuperior/bds04/controllers/CityController.java +++ b/src/main/java/com/devsuperior/bds04/controllers/CityController.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -22,14 +23,14 @@ import com.devsuperior.bds04.services.CityService; @RestController -@RequestMapping(value = "/users") +@RequestMapping(value = "/cities") public class CityController { @Autowired private CityService service; @GetMapping - public ResponseEntity> findAll(Pageable pageable) { + public ResponseEntity> findAll(@PageableDefault(sort= {"name"}) Pageable pageable) { Page list = service.findAllPaged(pageable); return ResponseEntity.ok().body(list); } diff --git a/src/main/java/com/devsuperior/bds04/dto/EventDTO.java b/src/main/java/com/devsuperior/bds04/dto/EventDTO.java index a442d160..cb1535da 100644 --- a/src/main/java/com/devsuperior/bds04/dto/EventDTO.java +++ b/src/main/java/com/devsuperior/bds04/dto/EventDTO.java @@ -2,23 +2,28 @@ import java.io.Serializable; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import javax.validation.constraints.FutureOrPresent; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import com.devsuperior.bds04.entities.City; import com.devsuperior.bds04.entities.Event; public class EventDTO implements Serializable { private static final long serialVersionUID = 1L; private Long id; - @NotBlank (message = "Campo requerido") + + @NotBlank(message = "Campo requerido") private String name; - @FutureOrPresent + @FutureOrPresent(message = "A data do evento não pode ser passada") private LocalDate date; private String url; - @NotNull + @NotNull(message = "Campo requerido") private Long cityId; public EventDTO() { @@ -79,4 +84,4 @@ public Long getCityId() { public void setCityId(Long cityId) { this.cityId = cityId; } -} +} \ No newline at end of file diff --git a/src/main/java/com/devsuperior/bds04/entities/Event.java b/src/main/java/com/devsuperior/bds04/entities/Event.java index 72d3edc1..11a8b4f1 100644 --- a/src/main/java/com/devsuperior/bds04/entities/Event.java +++ b/src/main/java/com/devsuperior/bds04/entities/Event.java @@ -1,6 +1,7 @@ package com.devsuperior.bds04.entities; import java.time.LocalDate; +import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -25,11 +26,12 @@ public class Event { @JoinColumn(name = "city_id") private City city; + public Event() { } - public Event(Long id, String name, LocalDate date, String url, City city) { - this.id = id; + public Event(String name, LocalDate date, String url, City city) { + super(); this.name = name; this.date = date; this.url = url; diff --git a/src/main/java/com/devsuperior/bds04/entities/Role.java b/src/main/java/com/devsuperior/bds04/entities/Role.java index a2c341a3..9a21343b 100644 --- a/src/main/java/com/devsuperior/bds04/entities/Role.java +++ b/src/main/java/com/devsuperior/bds04/entities/Role.java @@ -13,7 +13,7 @@ import javax.persistence.Table; @Entity -@Table(name="tb_user") +@Table(name="tb_role") public class Role implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java b/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java index 668313b3..fbdd8b73 100644 --- a/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java +++ b/src/main/java/com/devsuperior/bds04/repositories/CityRepository.java @@ -8,4 +8,6 @@ @Repository public interface CityRepository extends JpaRepository{ + + } diff --git a/src/main/java/com/devsuperior/bds04/services/CityService.java b/src/main/java/com/devsuperior/bds04/services/CityService.java index cd0877b0..d1fe60b4 100644 --- a/src/main/java/com/devsuperior/bds04/services/CityService.java +++ b/src/main/java/com/devsuperior/bds04/services/CityService.java @@ -27,8 +27,8 @@ public class CityService { @Transactional(readOnly = true) public Page findAllPaged(Pageable pageable) { Page list = repository.findAll(pageable); - return list.map(x -> new CityDTO(x)); + } @Transactional(readOnly = true) diff --git a/src/main/java/com/devsuperior/bds04/services/EventService.java b/src/main/java/com/devsuperior/bds04/services/EventService.java index 4ee8e5fb..2c445c38 100644 --- a/src/main/java/com/devsuperior/bds04/services/EventService.java +++ b/src/main/java/com/devsuperior/bds04/services/EventService.java @@ -13,7 +13,9 @@ import org.springframework.transaction.annotation.Transactional; import com.devsuperior.bds04.dto.EventDTO; +import com.devsuperior.bds04.entities.City; import com.devsuperior.bds04.entities.Event; +import com.devsuperior.bds04.repositories.CityRepository; import com.devsuperior.bds04.repositories.EventRepository; import com.devsuperior.bds04.services.exceptions.DatabaseException; import com.devsuperior.bds04.services.exceptions.ResourceNotFoundException; @@ -23,6 +25,9 @@ public class EventService { @Autowired private EventRepository repository; + + @Autowired + private CityRepository cityRepository; @Transactional(readOnly = true) public Page findAllPaged(Pageable pageable) { @@ -42,6 +47,9 @@ public EventDTO findById(Long id) { public EventDTO insert(EventDTO dto) { Event entity = new Event(); entity.setName(dto.getName()); + entity.setDate(dto.getDate()); + entity.setUrl(dto.getUrl()); + entity.setCity(new City(dto.getCityId(), null)); entity = repository.save(entity); return new EventDTO(entity); } @@ -67,5 +75,4 @@ public void delete(Long id) { throw new DatabaseException("Integrity Violation!"); } } - } diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 0b897e20..b16c7fa3 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,3 +1,13 @@ +INSERT INTO tb_user (first_name, last_name, email, password) VALUES ('Ana', 'Brown', 'ana@gmail.com', '$2a$10$eACCYoNOHEqXve8aIWT8Nu3PkMXWBaOxJ9aORUYzfMQCbVBIhZ8tG'); +INSERT INTO tb_user (first_name, last_name, email, password) VALUES ('Bob', 'Green', 'bob@gmail.com', '$2a$10$eACCYoNOHEqXve8aIWT8Nu3PkMXWBaOxJ9aORUYzfMQCbVBIhZ8tG'); + +INSERT INTO tb_role (authority) VALUES ('ROLE_CLIENT'); +INSERT INTO tb_role (authority) VALUES ('ROLE_ADMIN'); + +INSERT INTO tb_user_role (user_id, role_id) VALUES (1, 1); +INSERT INTO tb_user_role (user_id, role_id) VALUES (2, 1); +INSERT INTO tb_user_role (user_id, role_id) VALUES (2, 2); + INSERT INTO tb_city(name) VALUES ('São Paulo'); INSERT INTO tb_city(name) VALUES ('Brasília'); INSERT INTO tb_city(name) VALUES ('Fortaleza'); diff --git a/src/test/java/com/devsuperior/bds04/controllers/CityControllerIT.java b/src/test/java/com/devsuperior/bds04/controllers/CityControllerIT.java index 2173b40c..f1f077c2 100644 --- a/src/test/java/com/devsuperior/bds04/controllers/CityControllerIT.java +++ b/src/test/java/com/devsuperior/bds04/controllers/CityControllerIT.java @@ -128,8 +128,8 @@ public void findAllShouldReturnAllResourcesSortedByName() throws Exception { .contentType(MediaType.APPLICATION_JSON)); result.andExpect(status().isOk()); - result.andExpect(jsonPath("$[0].name").value("Belo Horizonte")); - result.andExpect(jsonPath("$[1].name").value("Belém")); - result.andExpect(jsonPath("$[2].name").value("Brasília")); + result.andExpect(jsonPath("$.content.[0].name").value("Belo Horizonte")); + result.andExpect(jsonPath("$.content.[1].name").value("Belém")); + result.andExpect(jsonPath("$.content.[2].name").value("Brasília")); } } diff --git a/src/test/java/com/devsuperior/bds04/controllers/EventControllerIT.java b/src/test/java/com/devsuperior/bds04/controllers/EventControllerIT.java index 890033fc..7f449683 100644 --- a/src/test/java/com/devsuperior/bds04/controllers/EventControllerIT.java +++ b/src/test/java/com/devsuperior/bds04/controllers/EventControllerIT.java @@ -129,8 +129,8 @@ public void insertShouldReturn422WhenAdminLoggedAndBlankName() throws Exception .accept(MediaType.APPLICATION_JSON)); result.andExpect(status().isUnprocessableEntity()); - result.andExpect(jsonPath("$.errors[0].fieldName").value("name")); - result.andExpect(jsonPath("$.errors[0].message").value("Campo requerido")); + result.andExpect(jsonPath("$.errors.[0].fieldName").value("name")); + result.andExpect(jsonPath("$.errors.[0].message").value("Campo requerido")); } @Test @@ -150,8 +150,8 @@ public void insertShouldReturn422WhenAdminLoggedAndPastDate() throws Exception { .accept(MediaType.APPLICATION_JSON)); result.andExpect(status().isUnprocessableEntity()); - result.andExpect(jsonPath("$.errors[0].fieldName").value("date")); - result.andExpect(jsonPath("$.errors[0].message").value("A data do evento não pode ser passada")); + result.andExpect(jsonPath("$.errors.[0].fieldName").value("date")); + result.andExpect(jsonPath("$.errors.[0].message").value("A data do evento não pode ser passada")); } @Test @@ -171,8 +171,8 @@ public void insertShouldReturn422WhenAdminLoggedAndNullCity() throws Exception { .accept(MediaType.APPLICATION_JSON)); result.andExpect(status().isUnprocessableEntity()); - result.andExpect(jsonPath("$.errors[0].fieldName").value("cityId")); - result.andExpect(jsonPath("$.errors[0].message").value("Campo requerido")); + result.andExpect(jsonPath("$.errors.[0].fieldName").value("cityId")); + result.andExpect(jsonPath("$.errors.[0].message").value("Campo requerido")); } @Test