Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.pointtils.pointtils.src.application.clients;

import com.pointtils.pointtils.src.application.dto.CityIbgeResponseDTO;
import com.pointtils.pointtils.src.application.dto.StateDataDTO;
import com.pointtils.pointtils.src.application.dto.StateIbgeResponseDTO;
import com.pointtils.pointtils.src.core.domain.exceptions.ClientTimeoutException;
import jakarta.persistence.EntityNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;

@Slf4j
@Component
public class IbgeClient {

private final RestTemplate restTemplate;
private final String stateUrl;
private final String cityUrl;

public IbgeClient(@Qualifier("ibgeRestTemplate") RestTemplate restTemplate,
@Value("${client.ibge.state-url}") String stateUrl,
@Value("${client.ibge.city-url}") String cityUrl) {
this.restTemplate = restTemplate;
this.stateUrl = stateUrl;
this.cityUrl = cityUrl;
}

public List<StateDataDTO> getStateList() {
try {
log.info("Iniciando uma requisicao para a API do IBGE para buscar a lista de UFs");
ResponseEntity<StateIbgeResponseDTO[]> stateResponse = restTemplate.getForEntity(stateUrl, StateIbgeResponseDTO[].class);
Function<StateIbgeResponseDTO, StateDataDTO> mapper = state -> new StateDataDTO(state.getAbbreviation());
return formatResponseData(stateResponse.getBody(), mapper, "UFs não encontradas");
} catch (ResourceAccessException ex) {
log.error("Timeout na requisicao para a API do IBGE para buscar a lista de UFs", ex);
throw new ClientTimeoutException("Timeout ao acessar o serviço de UFs");
}
}

public List<StateDataDTO> getCityListByState(String state) {
try {
log.info("Iniciando uma requisicao para a API do IBGE para buscar a lista de municípios da UF {}", state);
ResponseEntity<CityIbgeResponseDTO[]> cityResponse = restTemplate.getForEntity(cityUrl, CityIbgeResponseDTO[].class, state);
Function<CityIbgeResponseDTO, StateDataDTO> mapper = city -> new StateDataDTO(city.getName());
return formatResponseData(cityResponse.getBody(), mapper, "Municípios não encontrados");
} catch (ResourceAccessException ex) {
log.error("Timeout na requisicao para a API do IBGE para buscar a lista de municípios da UF {}", state, ex);
throw new ClientTimeoutException("Timeout ao acessar o serviço de municípios");
}
}

private <T> List<StateDataDTO> formatResponseData(T[] responseBody,
Function<? super T, StateDataDTO> mapper,
String errorMessage) {
if (ArrayUtils.isEmpty(responseBody)) {
throw new EntityNotFoundException(errorMessage);
}
return Arrays.stream(responseBody)
.map(mapper)
.sorted(Comparator.comparing(StateDataDTO::getName))
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.pointtils.pointtils.src.application.controllers;

import com.pointtils.pointtils.src.application.dto.StateResponseDTO;
import com.pointtils.pointtils.src.application.services.StateService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/v1/states")
@SecurityRequirement(name = "bearerAuth")
@Tag(name = "State Controller", description = "Endpoints para gerenciar dados de UFs brasileiras")
public class StateController {

private final StateService stateService;

@GetMapping
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "Busca todas as UFs brasileiras")
public StateResponseDTO getStates() {
return stateService.getAllStates();
}

@GetMapping("/{stateId}/cities")
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "Busca todos os municípios de uma determinada UF brasileira")
public StateResponseDTO getCitiesByState(@PathVariable String stateId) {
return stateService.getCitiesByState(stateId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.pointtils.pointtils.src.application.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class CityIbgeResponseDTO {

private Long id;

@JsonProperty("nome")
private String name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.pointtils.pointtils.src.application.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class StateDataDTO {

private String name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.pointtils.pointtils.src.application.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class StateIbgeResponseDTO {

private Long id;

@JsonProperty("sigla")
private String abbreviation;

@JsonProperty("nome")
private String name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.pointtils.pointtils.src.application.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class StateResponseDTO {

private boolean success;
private String message;
private List<StateDataDTO> data;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.pointtils.pointtils.src.application.services;

import java.util.UUID;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.pointtils.pointtils.src.application.services;

import com.pointtils.pointtils.src.application.clients.IbgeClient;
import com.pointtils.pointtils.src.application.dto.StateResponseDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class StateService {

private final IbgeClient ibgeClient;

public StateResponseDTO getAllStates() {
return new StateResponseDTO(true, "UFs encontradas com sucesso", ibgeClient.getStateList());
}

public StateResponseDTO getCitiesByState(String state) {
return new StateResponseDTO(true, "Municípios encontrados com sucesso",
ibgeClient.getCityListByState(state));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.pointtils.pointtils.src.core.domain.entities;

import java.util.UUID;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
Expand All @@ -11,6 +9,8 @@
import jakarta.persistence.Table;
import org.hibernate.annotations.UuidGenerator;

import java.util.UUID;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "user_account")
Expand All @@ -32,18 +32,54 @@ public abstract class User {
private String status;

public abstract String getDisplayName();

public abstract String getType();

public UUID getId() { return id; }
public String getEmail() { return email; }
public String getPassword() { return password; }
public String getPhone() { return phone; }
public String getPicture() { return picture; }
public String getStatus() { return status; }
public void setId(UUID id) { this.id = id; }
public void setEmail(String email) { this.email = email; }
public void setPassword(String password) { this.password = password; }
public void setPhone(String phone) { this.phone = phone; }
public void setPicture(String picture) { this.picture = picture; }
public void setStatus(String status) { this.status = status; }
public UUID getId() {
return id;
}

public String getEmail() {
return email;
}

public String getPassword() {
return password;
}

public String getPhone() {
return phone;
}

public String getPicture() {
return picture;
}

public String getStatus() {
return status;
}

public void setId(UUID id) {
this.id = id;
}

public void setEmail(String email) {
this.email = email;
}

public void setPassword(String password) {
this.password = password;
}

public void setPhone(String phone) {
this.phone = phone;
}

public void setPicture(String picture) {
this.picture = picture;
}

public void setStatus(String status) {
this.status = status;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.pointtils.pointtils.src.core.domain.exceptions;

public class ClientTimeoutException extends RuntimeException {
public ClientTimeoutException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@

package com.pointtils.pointtils.src.infrastructure.configs;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

import com.pointtils.pointtils.src.core.domain.exceptions.AuthenticationException;
import com.pointtils.pointtils.src.core.domain.exceptions.ClientTimeoutException;
import com.pointtils.pointtils.src.core.domain.exceptions.UserSpecialtyException;

import jakarta.persistence.EntityNotFoundException;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleEntityNotFoundException(
EntityNotFoundException ex, WebRequest request) {

ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage(),
System.currentTimeMillis());

return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(
Exception ex, WebRequest request) {

ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"An unexpected error occurred",
System.currentTimeMillis());

return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}

Expand Down Expand Up @@ -108,6 +107,16 @@ public ResponseEntity<ErrorResponse> handleAuthentication(AuthenticationExceptio
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}

@ExceptionHandler(ClientTimeoutException.class)
public ResponseEntity<ErrorResponse> handleClientTimeoutException(ClientTimeoutException ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.GATEWAY_TIMEOUT.value(),
ex.getMessage(),
System.currentTimeMillis());

return new ResponseEntity<>(errorResponse, HttpStatus.GATEWAY_TIMEOUT);
}

@ExceptionHandler(UserSpecialtyException.class)
public ResponseEntity<ErrorResponse> handleUserSpecialty(UserSpecialtyException ex) {
ErrorResponse errorResponse = new ErrorResponse(
Expand Down
Loading