Compare commits

...

2 commits

4 changed files with 42 additions and 15 deletions

View file

@ -14,6 +14,7 @@ dependencies {
implementation 'br.com.rayan:hd-commons-lib:1.0.0' implementation 'br.com.rayan:hd-commons-lib:1.0.0'
// Spring Boot Starters initial project
implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb' implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
@ -22,12 +23,18 @@ dependencies {
// Swagger / OpenAPI (compatível com Spring Boot 3.3.x) // Swagger / OpenAPI (compatível com Spring Boot 3.3.x)
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
// Lombok for code generation (at compile time)
compileOnly 'org.projectlombok:lombok' compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok'
// MapStruct for object mapping (at compile time)
implementation 'org.mapstruct:mapstruct:1.5.3.Final' implementation 'org.mapstruct:mapstruct:1.5.3.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final' annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
// Spring Security dependencies for authentication and authorization
implementation 'org.springframework.security:spring-security-crypto:6.4.7'
// Testing dependencies
testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-starter-test'
} }

View file

@ -0,0 +1,14 @@
package br.com.rayankonecny.userserviceapi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
public class BCryptConfig {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}

View file

@ -60,8 +60,10 @@ public interface UserController {
@ApiResponse(responseCode = "200", description = "User updated successfully", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = UserResponse.class))), @ApiResponse(responseCode = "200", description = "User updated successfully", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = UserResponse.class))),
@ApiResponse(responseCode = "400", description = "Bad request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))), @ApiResponse(responseCode = "400", description = "Bad request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
@ApiResponse(responseCode = "404", description = "User not found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))), @ApiResponse(responseCode = "404", description = "User not found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
@ApiResponse(responseCode = "500", description = "Internal server error", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))), @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))), })
})
@PutMapping("/{id}") @PutMapping("/{id}")
ResponseEntity<UserResponse> update(@PathVariable(name = "id") final String id, @Valid @RequestBody final UpdateUserRequest updateUserRequest); ResponseEntity<UserResponse> update(@PathVariable(name = "id")
final String id, @Valid
@RequestBody
final UpdateUserRequest updateUserRequest);
} }

View file

@ -3,6 +3,7 @@ package br.com.rayankonecny.userserviceapi.service;
import java.util.List; import java.util.List;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import br.com.rayankonecny.userserviceapi.entity.User; import br.com.rayankonecny.userserviceapi.entity.User;
@ -19,36 +20,39 @@ import models.requests.UpdateUserRequest;
@RequiredArgsConstructor @RequiredArgsConstructor
public class UserService { public class UserService {
private final UserRepository userRepository; private final UserRepository repository;
private final UserMapper userMapper; private final UserMapper mapper;
private final BCryptPasswordEncoder encoder;
public UserResponse findById(final String id) { public UserResponse findById(final String id) {
return userMapper.fromEntity(find(id)); return mapper.fromEntity(find(id));
} }
public void save(CreateUserRequest createUserRequest) { public void save(CreateUserRequest request) {
verifyIfEmailAlreadyEexists(createUserRequest.email(), null); verifyIfEmailAlreadyEexists(request.email(), null);
userRepository.save(userMapper.fromRequest(createUserRequest)); repository.save(mapper.fromRequest(request).withPassword(encoder.encode(request.password())));
} }
private void verifyIfEmailAlreadyEexists(final String email, final String id) { private void verifyIfEmailAlreadyEexists(final String email, final String id) {
userRepository.findByEmail(email).filter(user -> !user.getId().equals(id)).ifPresent(user -> { repository.findByEmail(email).filter(user -> !user.getId().equals(id)).ifPresent(user -> {
throw new DataIntegrityViolationException("Email [" + email + "] already exists"); throw new DataIntegrityViolationException("Email [" + email + "] already exists");
}); });
} }
public List<UserResponse> findAll() { public List<UserResponse> findAll() {
return userRepository.findAll().stream().map(user -> userMapper.fromEntity(user)).toList(); return repository.findAll().stream().map(user -> mapper.fromEntity(user)).toList();
} }
public UserResponse update(final String id, @Valid final UpdateUserRequest updateUserRequest) { public UserResponse update(final String id, @Valid
final UpdateUserRequest request) {
User entity = find(id); User entity = find(id);
verifyIfEmailAlreadyEexists(updateUserRequest.email(), id); verifyIfEmailAlreadyEexists(request.email(), id);
return userMapper.fromEntity(userRepository.save(userMapper.update(updateUserRequest, entity))); return mapper.fromEntity(repository.save(mapper.update(request, entity)
.withPassword(request.password() != null ? encoder.encode(request.password()) : entity.getPassword())));
} }
private User find(final String id) { private User find(final String id) {
return userRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException( return repository.findById(id).orElseThrow(() -> new ResourceNotFoundException(
"Object not found! Id: " + id + ", Type: " + UserResponse.class.getSimpleName())); "Object not found! Id: " + id + ", Type: " + UserResponse.class.getSimpleName()));
} }