update exceptions
This commit is contained in:
parent
f23737662a
commit
bcf4fcaca6
Binary file not shown.
@ -1,7 +1,6 @@
|
|||||||
package com.banesco.common.application.helper;
|
package com.banesco.common.application.helper;
|
||||||
|
|
||||||
import com.banesco.common.domain.exception.BaseApiException;
|
import com.banesco.common.domain.exception.HttpStatusCodeException;
|
||||||
import com.banesco.common.domain.exception.InternalServerException;
|
|
||||||
import com.banesco.common.domain.model.ApiResponse;
|
import com.banesco.common.domain.model.ApiResponse;
|
||||||
import com.banesco.common.domain.model.ErrorMapping;
|
import com.banesco.common.domain.model.ErrorMapping;
|
||||||
import com.banesco.common.domain.model.StatusResponse;
|
import com.banesco.common.domain.model.StatusResponse;
|
||||||
@ -22,7 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
@RegisterForReflection
|
@RegisterForReflection
|
||||||
public class MessageResponseHelper {
|
public class MessageHelper {
|
||||||
|
|
||||||
private final MessagesConfig messagesConfig;
|
private final MessagesConfig messagesConfig;
|
||||||
private final Map<String, ErrorMapping> errorMappings;
|
private final Map<String, ErrorMapping> errorMappings;
|
||||||
@ -32,7 +31,7 @@ public class MessageResponseHelper {
|
|||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MessageResponseHelper(
|
public MessageHelper(
|
||||||
ObjectMapper objectMapper,
|
ObjectMapper objectMapper,
|
||||||
MessagesConfig messagesConfig
|
MessagesConfig messagesConfig
|
||||||
) {
|
) {
|
||||||
@ -41,16 +40,21 @@ public class MessageResponseHelper {
|
|||||||
this.errorMappings = initializeErrorMappings();
|
this.errorMappings = initializeErrorMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response handleException(BaseApiException exception) {
|
public Response handleException(HttpStatusCodeException exception) {
|
||||||
|
log.error(
|
||||||
|
"Error interno controlado: {} -> {}",
|
||||||
|
exception.getStatusCode(),
|
||||||
|
exception.getErrorCode()
|
||||||
|
);
|
||||||
return buildErrorResponse(exception);
|
return buildErrorResponse(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response handleGenericException(Exception exception) {
|
public Response handleGenericException(Exception exception) {
|
||||||
log.error("Error interno no controlado: {}", exception.getMessage(), exception);
|
log.error("Error interno no controlado: {}", exception.getMessage());
|
||||||
return buildErrorResponse(new InternalServerException("500", null));
|
return buildErrorResponse(HttpStatusCodeException.internalServer("500"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatusResponse createSuccessResponse(String code) {
|
public StatusResponse createStatusResponse(String code) {
|
||||||
ErrorMapping successMapping = getError(code);
|
ErrorMapping successMapping = getError(code);
|
||||||
|
|
||||||
return StatusResponse.builder()
|
return StatusResponse.builder()
|
||||||
@ -59,7 +63,7 @@ public class MessageResponseHelper {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatusResponse createErrorResponse(
|
public StatusResponse createError(
|
||||||
ErrorMapping mapping,
|
ErrorMapping mapping,
|
||||||
String fieldPath
|
String fieldPath
|
||||||
) {
|
) {
|
||||||
@ -76,7 +80,7 @@ public class MessageResponseHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T> ApiResponse<T> buildServiceUnavailableResponse() {
|
public <T> ApiResponse<T> buildServiceUnavailableResponse() {
|
||||||
return new ApiResponse<>(null, createSuccessResponse("503"));
|
return new ApiResponse<>(createStatusResponse("503"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ErrorMapping getError(String errorCode) {
|
private ErrorMapping getError(String errorCode) {
|
||||||
@ -85,14 +89,14 @@ public class MessageResponseHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response buildErrorResponse(BaseApiException exception) {
|
private Response buildErrorResponse(HttpStatusCodeException exception) {
|
||||||
ErrorMapping mapping = errorMappings.getOrDefault(
|
ErrorMapping mapping = errorMappings.getOrDefault(
|
||||||
exception.getErrorCode(),
|
exception.getErrorCode(), errorMappings.getOrDefault(
|
||||||
errorMappings.getOrDefault(ERROR_DEFAULT, createDefaultMapping())
|
String.valueOf(exception.getStatusCode()),
|
||||||
);
|
createDefaultMapping()
|
||||||
StatusResponse status = createErrorResponse(
|
)
|
||||||
mapping, exception.getFieldPath()
|
|
||||||
);
|
);
|
||||||
|
StatusResponse status = createError(mapping, exception.getFieldPath());
|
||||||
|
|
||||||
log.error(
|
log.error(
|
||||||
"[{}] Message {} -> {}",
|
"[{}] Message {} -> {}",
|
||||||
@ -102,7 +106,7 @@ public class MessageResponseHelper {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return Response.status(mapping.getHttpCode())
|
return Response.status(mapping.getHttpCode())
|
||||||
.entity(new ApiResponse<>(null, status))
|
.entity(new ApiResponse<>(status))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +151,7 @@ public class MessageResponseHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String loadFromJsonFile() {
|
private String loadFromJsonFile() {
|
||||||
try (InputStream is = MessageResponseHelper.class.getClassLoader().getResourceAsStream(ERROR_FILE_PATH)) {
|
try (InputStream is = MessageHelper.class.getClassLoader().getResourceAsStream(ERROR_FILE_PATH)) {
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
log.warn("No se encontró el archivo de errores: {}", ERROR_FILE_PATH);
|
log.warn("No se encontró el archivo de errores: {}", ERROR_FILE_PATH);
|
||||||
return "";
|
return "";
|
||||||
@ -169,9 +173,9 @@ public class MessageResponseHelper {
|
|||||||
private ErrorMapping createDefaultMapping() {
|
private ErrorMapping createDefaultMapping() {
|
||||||
ErrorMapping mapping = new ErrorMapping();
|
ErrorMapping mapping = new ErrorMapping();
|
||||||
mapping.setBackendCode(ERROR_DEFAULT);
|
mapping.setBackendCode(ERROR_DEFAULT);
|
||||||
mapping.setHttpCode(500);
|
mapping.setHttpCode(409);
|
||||||
mapping.setStatusCode("500");
|
mapping.setStatusCode("409");
|
||||||
mapping.setDescription("Error interno del servidor");
|
mapping.setDescription("Conflicto");
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +183,7 @@ public class MessageResponseHelper {
|
|||||||
ErrorMapping mapping = new ErrorMapping();
|
ErrorMapping mapping = new ErrorMapping();
|
||||||
mapping.setBackendCode(SUCCESS_DEFAULT);
|
mapping.setBackendCode(SUCCESS_DEFAULT);
|
||||||
mapping.setHttpCode(200);
|
mapping.setHttpCode(200);
|
||||||
mapping.setStatusCode("000");
|
mapping.setStatusCode("200");
|
||||||
mapping.setDescription("Operación exitosa");
|
mapping.setDescription("Operación exitosa");
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
@ -187,4 +191,17 @@ public class MessageResponseHelper {
|
|||||||
public boolean isReadingFromProps() {
|
public boolean isReadingFromProps() {
|
||||||
return messagesConfig.isReadFromProps();
|
return messagesConfig.isReadFromProps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSuccessStatusCode(StatusResponse statusResponse) {
|
||||||
|
if (statusResponse == null || statusResponse.getStatusCode() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int statusCode = Integer.parseInt(statusResponse.getStatusCode());
|
||||||
|
return statusCode >= 200 && statusCode < 300;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.banesco.common.domain.exception;
|
|
||||||
|
|
||||||
public class BadRequestException extends BaseApiException {
|
|
||||||
public BadRequestException(String errorCode, String message, String fieldPath) {
|
|
||||||
super(errorCode, message, fieldPath, "bad-request");
|
|
||||||
}
|
|
||||||
|
|
||||||
public BadRequestException(String errorCode, String fieldPath) {
|
|
||||||
super(errorCode, fieldPath, "bad-request");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package com.banesco.common.domain.exception;
|
||||||
|
|
||||||
|
import com.banesco.common.domain.model.ApiResponse;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class HttpApiResponseException extends RuntimeException {
|
||||||
|
private final int statusCode;
|
||||||
|
private final transient ApiResponse<?> apiResponse;
|
||||||
|
|
||||||
|
public HttpApiResponseException(int statusCode, ApiResponse<?> apiResponse) {
|
||||||
|
super(String.format(
|
||||||
|
"HTTP %d: %s", statusCode,
|
||||||
|
apiResponse.getStatusResponse() != null ?
|
||||||
|
apiResponse.getStatusResponse().getMessage() : "Error sin mensaje"
|
||||||
|
));
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
this.apiResponse = apiResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.banesco.common.domain.exception;
|
||||||
|
|
||||||
|
public class HttpClientException extends RuntimeException {
|
||||||
|
public HttpClientException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpClientException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,322 @@
|
|||||||
|
package com.banesco.common.domain.exception;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@Builder
|
||||||
|
public class HttpStatusCodeException extends BaseApiException {
|
||||||
|
private final int statusCode;
|
||||||
|
|
||||||
|
private static final Map<Integer, String> STATUS_CATEGORIES = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
STATUS_CATEGORIES.put(100, "continue");
|
||||||
|
STATUS_CATEGORIES.put(101, "switching-protocols");
|
||||||
|
STATUS_CATEGORIES.put(102, "processing");
|
||||||
|
STATUS_CATEGORIES.put(103, "early-hints");
|
||||||
|
STATUS_CATEGORIES.put(200, "ok");
|
||||||
|
STATUS_CATEGORIES.put(201, "created");
|
||||||
|
STATUS_CATEGORIES.put(202, "accepted");
|
||||||
|
STATUS_CATEGORIES.put(203, "non-authoritative-information");
|
||||||
|
STATUS_CATEGORIES.put(204, "no-content");
|
||||||
|
STATUS_CATEGORIES.put(205, "reset-content");
|
||||||
|
STATUS_CATEGORIES.put(206, "partial-content");
|
||||||
|
STATUS_CATEGORIES.put(207, "multi-status");
|
||||||
|
STATUS_CATEGORIES.put(208, "already-reported");
|
||||||
|
STATUS_CATEGORIES.put(226, "im-used");
|
||||||
|
STATUS_CATEGORIES.put(300, "multiple-choices");
|
||||||
|
STATUS_CATEGORIES.put(301, "moved-permanently");
|
||||||
|
STATUS_CATEGORIES.put(302, "found");
|
||||||
|
STATUS_CATEGORIES.put(303, "see-other");
|
||||||
|
STATUS_CATEGORIES.put(304, "not-modified");
|
||||||
|
STATUS_CATEGORIES.put(305, "use-proxy");
|
||||||
|
STATUS_CATEGORIES.put(307, "temporary-redirect");
|
||||||
|
STATUS_CATEGORIES.put(308, "permanent-redirect");
|
||||||
|
STATUS_CATEGORIES.put(400, "bad-request");
|
||||||
|
STATUS_CATEGORIES.put(401, "unauthorized");
|
||||||
|
STATUS_CATEGORIES.put(402, "payment-required");
|
||||||
|
STATUS_CATEGORIES.put(403, "forbidden");
|
||||||
|
STATUS_CATEGORIES.put(404, "not-found");
|
||||||
|
STATUS_CATEGORIES.put(405, "method-not-allowed");
|
||||||
|
STATUS_CATEGORIES.put(406, "not-acceptable");
|
||||||
|
STATUS_CATEGORIES.put(407, "proxy-authentication-required");
|
||||||
|
STATUS_CATEGORIES.put(408, "request-timeout");
|
||||||
|
STATUS_CATEGORIES.put(409, "conflict");
|
||||||
|
STATUS_CATEGORIES.put(410, "gone");
|
||||||
|
STATUS_CATEGORIES.put(411, "length-required");
|
||||||
|
STATUS_CATEGORIES.put(412, "precondition-failed");
|
||||||
|
STATUS_CATEGORIES.put(413, "payload-too-large");
|
||||||
|
STATUS_CATEGORIES.put(414, "uri-too-long");
|
||||||
|
STATUS_CATEGORIES.put(415, "unsupported-media-type");
|
||||||
|
STATUS_CATEGORIES.put(416, "range-not-satisfiable");
|
||||||
|
STATUS_CATEGORIES.put(417, "expectation-failed");
|
||||||
|
STATUS_CATEGORIES.put(418, "im-a-teapot");
|
||||||
|
STATUS_CATEGORIES.put(421, "misdirected-request");
|
||||||
|
STATUS_CATEGORIES.put(422, "unprocessable-entity");
|
||||||
|
STATUS_CATEGORIES.put(423, "locked");
|
||||||
|
STATUS_CATEGORIES.put(424, "failed-dependency");
|
||||||
|
STATUS_CATEGORIES.put(425, "too-early");
|
||||||
|
STATUS_CATEGORIES.put(426, "upgrade-required");
|
||||||
|
STATUS_CATEGORIES.put(428, "precondition-required");
|
||||||
|
STATUS_CATEGORIES.put(429, "too-many-requests");
|
||||||
|
STATUS_CATEGORIES.put(431, "request-header-fields-too-large");
|
||||||
|
STATUS_CATEGORIES.put(451, "unavailable-for-legal-reasons");
|
||||||
|
STATUS_CATEGORIES.put(500, "internal-server-error");
|
||||||
|
STATUS_CATEGORIES.put(501, "not-implemented");
|
||||||
|
STATUS_CATEGORIES.put(502, "bad-gateway");
|
||||||
|
STATUS_CATEGORIES.put(503, "service-unavailable");
|
||||||
|
STATUS_CATEGORIES.put(504, "gateway-timeout");
|
||||||
|
STATUS_CATEGORIES.put(505, "http-version-not-supported");
|
||||||
|
STATUS_CATEGORIES.put(506, "variant-also-negotiates");
|
||||||
|
STATUS_CATEGORIES.put(507, "insufficient-storage");
|
||||||
|
STATUS_CATEGORIES.put(508, "loop-detected");
|
||||||
|
STATUS_CATEGORIES.put(510, "not-extended");
|
||||||
|
STATUS_CATEGORIES.put(511, "network-authentication-required");
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpStatusCodeException(int statusCode, String errorCode, String message, String fieldPath) {
|
||||||
|
super(errorCode, message, fieldPath, getHttpStatusCategory(statusCode));
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpStatusCodeException(int statusCode, String errorCode, String message) {
|
||||||
|
this(statusCode, errorCode, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpStatusCodeException(int statusCode, String errorCode) {
|
||||||
|
this(statusCode, errorCode, getDefaultMessage(statusCode), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpStatusCodeException(int statusCode) {
|
||||||
|
this(statusCode, "HTTP_" + statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getHttpStatusCategory(int statusCode) {
|
||||||
|
String category = STATUS_CATEGORIES.get(statusCode);
|
||||||
|
|
||||||
|
if (category != null) {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statusCode >= 100 && statusCode < 200) return "informational";
|
||||||
|
if (statusCode >= 200 && statusCode < 300) return "success";
|
||||||
|
if (statusCode >= 300 && statusCode < 400) return "redirection";
|
||||||
|
if (statusCode >= 400 && statusCode < 500) return "client-error";
|
||||||
|
if (statusCode >= 500 && statusCode < 600) return "server-error";
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getDefaultMessage(int statusCode) {
|
||||||
|
return switch (statusCode) {
|
||||||
|
case 200 -> "OK";
|
||||||
|
case 201 -> "Created";
|
||||||
|
case 202 -> "Accepted";
|
||||||
|
case 204 -> "No Content";
|
||||||
|
case 400 -> "Bad Request";
|
||||||
|
case 401 -> "Unauthorized";
|
||||||
|
case 403 -> "Forbidden";
|
||||||
|
case 404 -> "Not Found";
|
||||||
|
case 405 -> "Method Not Allowed";
|
||||||
|
case 408 -> "Request Timeout";
|
||||||
|
case 409 -> "Conflict";
|
||||||
|
case 410 -> "Gone";
|
||||||
|
case 422 -> "Unprocessable Entity";
|
||||||
|
case 429 -> "Too Many Requests";
|
||||||
|
case 500 -> "Internal Server Error";
|
||||||
|
case 502 -> "Bad Gateway";
|
||||||
|
case 503 -> "Service Unavailable";
|
||||||
|
case 504 -> "Gateway Timeout";
|
||||||
|
default -> "HTTP " + statusCode;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException badRequest(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(400, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException badRequest(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(400, errorCode, getDefaultMessage(400), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException unauthorized(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(401, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException unauthorized(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(401, errorCode, getDefaultMessage(401), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException forbidden(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(403, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException forbidden(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(403, errorCode, getDefaultMessage(403), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException notFound(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(404, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException notFound(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(404, errorCode, getDefaultMessage(404), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException methodNotAllowed(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(405, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException methodNotAllowed(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(405, errorCode, getDefaultMessage(405), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException conflict(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(409, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException conflict(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(409, errorCode, getDefaultMessage(409), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException unprocessableEntity(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(422, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException unprocessableEntity(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(422, errorCode, getDefaultMessage(422), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException tooManyRequests(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(429, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException tooManyRequests(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(429, errorCode, getDefaultMessage(429), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException internalServer(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(500, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException internalServer(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(500, errorCode, getDefaultMessage(500), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException badGateway(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(502, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException badGateway(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(502, errorCode, getDefaultMessage(502), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException serviceUnavailable(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(503, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException serviceUnavailable(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(503, errorCode, getDefaultMessage(503), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException gatewayTimeout(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(504, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException gatewayTimeout(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(504, errorCode, getDefaultMessage(504), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException paymentRequired(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(402, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException paymentRequired(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(402, errorCode, getDefaultMessage(402), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException gone(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(410, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException gone(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(410, errorCode, getDefaultMessage(410), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException preconditionFailed(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(412, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException preconditionFailed(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(412, errorCode, getDefaultMessage(412), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException unsupportedMediaType(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(415, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException unsupportedMediaType(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(415, errorCode, getDefaultMessage(415), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException notImplemented(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(501, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException notImplemented(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(501, errorCode, getDefaultMessage(501), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException ok(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(200, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException ok(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(200, errorCode, getDefaultMessage(200), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException created(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(201, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException created(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(201, errorCode, getDefaultMessage(201), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException accepted(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(202, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException accepted(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(202, errorCode, getDefaultMessage(202), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException noContent(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(204, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException noContent(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(204, errorCode, getDefaultMessage(204), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException requestTimeout(String errorCode) {
|
||||||
|
return new HttpStatusCodeException(408, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException requestTimeout(String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(408, errorCode, getDefaultMessage(408), fieldPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException fromStatusCode(int statusCode, String errorCode) {
|
||||||
|
return new HttpStatusCodeException(statusCode, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpStatusCodeException fromStatusCode(int statusCode, String errorCode, String fieldPath) {
|
||||||
|
return new HttpStatusCodeException(statusCode, errorCode, getDefaultMessage(statusCode), fieldPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.banesco.common.domain.exception;
|
|
||||||
|
|
||||||
public class InternalServerException extends BaseApiException {
|
|
||||||
public InternalServerException(String errorCode, String message, String fieldPath) {
|
|
||||||
super(errorCode, message, fieldPath, "internal-server");
|
|
||||||
}
|
|
||||||
|
|
||||||
public InternalServerException(String errorCode, String fieldPath) {
|
|
||||||
super(errorCode, fieldPath, "internal-server");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.banesco.common.domain.exception;
|
|
||||||
|
|
||||||
public class NotFoundException extends BaseApiException {
|
|
||||||
public NotFoundException(String errorCode, String message, String fieldPath) {
|
|
||||||
super(errorCode, message, fieldPath, "not-found");
|
|
||||||
}
|
|
||||||
|
|
||||||
public NotFoundException(String errorCode, String fieldPath) {
|
|
||||||
super(errorCode, fieldPath, "not-found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.banesco.common.domain.exception;
|
|
||||||
|
|
||||||
public class ServiceUnavailableException extends BaseApiException {
|
|
||||||
public ServiceUnavailableException(String errorCode, String message, String fieldPath) {
|
|
||||||
super(errorCode, message, fieldPath, "service-unavailable");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceUnavailableException(String errorCode, String fieldPath) {
|
|
||||||
super(errorCode, fieldPath, "service-unavailable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.banesco.common.domain.exception;
|
|
||||||
|
|
||||||
public class SuccessException extends BaseApiException {
|
|
||||||
public SuccessException(String code, String message, String fieldPath) {
|
|
||||||
super(code, message, fieldPath, "ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
public SuccessException(String code, String fieldPath) {
|
|
||||||
super(code, fieldPath, "ok");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.banesco.common.domain.exception;
|
|
||||||
|
|
||||||
public class UnauthorizedException extends BaseApiException {
|
|
||||||
public UnauthorizedException(String errorCode, String message, String fieldPath) {
|
|
||||||
super(errorCode, message, fieldPath, "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnauthorizedException(String errorCode, String fieldPath) {
|
|
||||||
super(errorCode, fieldPath, "unauthorized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -10,4 +10,9 @@ import lombok.*;
|
|||||||
public class ApiResponse<T> {
|
public class ApiResponse<T> {
|
||||||
private T data;
|
private T data;
|
||||||
private StatusResponse statusResponse;
|
private StatusResponse statusResponse;
|
||||||
|
|
||||||
|
public ApiResponse(StatusResponse statusResponse) {
|
||||||
|
this.statusResponse = statusResponse;
|
||||||
|
this.data = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,24 +1,36 @@
|
|||||||
package com.banesco.common.domain.model;
|
package com.banesco.common.domain.model;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.*;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Builder
|
@Setter
|
||||||
@ToString
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
public class HttpRequest {
|
public class HttpRequest {
|
||||||
private String url;
|
private String url;
|
||||||
private HttpMethod method;
|
private HttpMethod method;
|
||||||
private Object body;
|
private Object body;
|
||||||
private Map<String, String> pathParams;
|
|
||||||
private Map<String, String> queryParams;
|
|
||||||
private Map<String, String> headers;
|
private Map<String, String> headers;
|
||||||
private Class<?> responseType;
|
private Map<String, String> queryParams;
|
||||||
private int connectTimeout;
|
private Map<String, String> pathParams;
|
||||||
private int readTimeout;
|
|
||||||
|
@Builder.Default
|
||||||
|
private Class<?> responseType = Object.class;
|
||||||
|
|
||||||
|
private Class<?> genericType;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private int connectTimeout = 5000;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private int readTimeout = 10000;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private boolean returnFullResponse = false;
|
||||||
|
|
||||||
public enum HttpMethod {
|
public enum HttpMethod {
|
||||||
GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
|
GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
|
||||||
|
|||||||
@ -13,7 +13,7 @@ public class MessagesConfig {
|
|||||||
private final String errorMessagesJson;
|
private final String errorMessagesJson;
|
||||||
private final String messagesKey;
|
private final String messagesKey;
|
||||||
|
|
||||||
private static final String KEY = "domLogalCustomerProductDirectory";
|
private static final String KEY = "dom-legal-customer-product-directory";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MessagesConfig(Config config) {
|
public MessagesConfig(Config config) {
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
package com.banesco.module.legal_customer_product_directory.application.service;
|
package com.banesco.module.legal_customer_product_directory.application.service;
|
||||||
|
|
||||||
import com.banesco.common.application.helper.MessageResponseHelper;
|
import com.banesco.common.application.helper.MessageHelper;
|
||||||
import com.banesco.common.domain.exception.*;
|
import com.banesco.common.domain.exception.*;
|
||||||
import com.banesco.common.domain.model.*;
|
import com.banesco.common.domain.model.*;
|
||||||
import com.banesco.module.account.domain.model.*;
|
|
||||||
import com.banesco.module.legal_customer_product_directory.application.repository.PersistenceRepository;
|
import com.banesco.module.legal_customer_product_directory.application.repository.PersistenceRepository;
|
||||||
import com.banesco.module.legal_customer_product_directory.application.usecase.LegalCustomerProductDirectoryUseCase;
|
import com.banesco.module.legal_customer_product_directory.application.usecase.LegalCustomerProductDirectoryUseCase;
|
||||||
import com.banesco.module.legal_customer_product_directory.domain.dto.request.LegalCustomerProductDirectoryRequest;
|
import com.banesco.module.legal_customer_product_directory.domain.dto.request.LegalCustomerProductDirectoryRequest;
|
||||||
@ -17,15 +16,15 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
public class LegalCustomerProductDirectoryService implements LegalCustomerProductDirectoryUseCase {
|
public class LegalCustomerProductDirectoryService implements LegalCustomerProductDirectoryUseCase {
|
||||||
|
|
||||||
private final MessageResponseHelper messageResponseHelper;
|
private final MessageHelper messageHelper;
|
||||||
private final PersistenceRepository persistenceRepository;
|
private final PersistenceRepository persistenceRepository;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LegalCustomerProductDirectoryService(
|
public LegalCustomerProductDirectoryService(
|
||||||
MessageResponseHelper messageResponseHelper,
|
MessageHelper messageHelper,
|
||||||
PersistenceRepository persistenceRepository
|
PersistenceRepository persistenceRepository
|
||||||
) {
|
) {
|
||||||
this.messageResponseHelper = messageResponseHelper;
|
this.messageHelper = messageHelper;
|
||||||
this.persistenceRepository = persistenceRepository;
|
this.persistenceRepository = persistenceRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,15 +36,15 @@ public class LegalCustomerProductDirectoryService implements LegalCustomerProduc
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return storeProcedure(request);
|
return storeProcedure(request);
|
||||||
} catch (BaseApiException e) {
|
|
||||||
log.warn("Excepción controlada del sp: {} -> {}", e.getErrorCode(), e.getMessage());
|
|
||||||
throw e;
|
|
||||||
} catch (PersistenceException e) {
|
} catch (PersistenceException e) {
|
||||||
log.warn("Excepción de la persistencia del sp: {} -> {}", e.getErrorCode(), e.getMessage());
|
log.warn("Excepción de la persistencia del sp: {} -> {}", e.getErrorCode(), e.getMessage());
|
||||||
throw new BadRequestException(e.getErrorCode(), null);
|
throw HttpStatusCodeException.badRequest(e.getErrorCode());
|
||||||
|
} catch (HttpStatusCodeException e) {
|
||||||
|
log.error("Excepción HTTP del api de dominio: {} - {}", e.getStatusCode(), e.getErrorCode());
|
||||||
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Excepción generica del sp: {}", e.getMessage());
|
log.error("Excepción genérica del api de dominio: {}", e.getMessage());
|
||||||
throw new ServiceUnavailableException("503", e.getMessage(), null);
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,14 +56,14 @@ public class LegalCustomerProductDirectoryService implements LegalCustomerProduc
|
|||||||
CustomerProductAndServiceDirectory response = persistenceRepository.execute(request);
|
CustomerProductAndServiceDirectory response = persistenceRepository.execute(request);
|
||||||
|
|
||||||
if(response == null) {
|
if(response == null) {
|
||||||
throw new BadRequestException("400", null);
|
throw HttpStatusCodeException.badRequest("400");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ApiResponse<>(
|
return new ApiResponse<>(
|
||||||
LegalCustomerProductDirectoryResponse.builder()
|
LegalCustomerProductDirectoryResponse.builder()
|
||||||
.customerProductAndServiceDirectory(response)
|
.customerProductAndServiceDirectory(response)
|
||||||
.build(),
|
.build(),
|
||||||
messageResponseHelper.createSuccessResponse("200")
|
messageHelper.createStatusResponse("200")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +237,7 @@ public class AccountMapper {
|
|||||||
return rs.getBigDecimal(columnName);
|
return rs.getBigDecimal(columnName);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
log.debug("Columna {} no encontrada como numérico, retornando null", columnName);
|
log.debug("Columna {} no encontrada como numérico, retornando null", columnName);
|
||||||
return null;
|
return BigDecimal.valueOf(0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.banesco.module.legal_customer_product_directory.infrastructure.resource;
|
package com.banesco.module.legal_customer_product_directory.infrastructure.resource;
|
||||||
|
|
||||||
import com.banesco.common.application.helper.MessageResponseHelper;
|
import com.banesco.common.application.helper.MessageHelper;
|
||||||
import com.banesco.common.domain.exception.BaseApiException;
|
import com.banesco.common.domain.exception.HttpStatusCodeException;
|
||||||
import com.banesco.common.domain.model.ApiResponse;
|
import com.banesco.common.domain.model.ApiResponse;
|
||||||
import com.banesco.common.domain.model.StatusResponse;
|
import com.banesco.common.domain.model.StatusResponse;
|
||||||
import com.banesco.module.legal_customer_product_directory.application.usecase.LegalCustomerProductDirectoryUseCase;
|
import com.banesco.module.legal_customer_product_directory.application.usecase.LegalCustomerProductDirectoryUseCase;
|
||||||
@ -30,14 +30,14 @@ import java.util.Objects;
|
|||||||
public class LegalCustomerProductDirectoryResource {
|
public class LegalCustomerProductDirectoryResource {
|
||||||
|
|
||||||
private final LegalCustomerProductDirectoryUseCase useCase;
|
private final LegalCustomerProductDirectoryUseCase useCase;
|
||||||
private final MessageResponseHelper messageResponseHelper;
|
private final MessageHelper messageHelper;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LegalCustomerProductDirectoryResource(
|
public LegalCustomerProductDirectoryResource(
|
||||||
MessageResponseHelper messageResponseHelper,
|
MessageHelper messageHelper,
|
||||||
LegalCustomerProductDirectoryUseCase useCase
|
LegalCustomerProductDirectoryUseCase useCase
|
||||||
) {
|
) {
|
||||||
this.messageResponseHelper = messageResponseHelper;
|
this.messageHelper = messageHelper;
|
||||||
this.useCase = useCase;
|
this.useCase = useCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,10 +393,10 @@ public class LegalCustomerProductDirectoryResource {
|
|||||||
.casheaIndicator(Objects.toString(casheaIndicator, ""))
|
.casheaIndicator(Objects.toString(casheaIndicator, ""))
|
||||||
.build()
|
.build()
|
||||||
)).build();
|
)).build();
|
||||||
} catch (BaseApiException e) {
|
} catch (HttpStatusCodeException e) {
|
||||||
return messageResponseHelper.handleException(e);
|
return messageHelper.handleException(e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return messageResponseHelper.handleGenericException(e);
|
return messageHelper.handleGenericException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -20,9 +20,9 @@ api:
|
|||||||
cachea-indicator: '^(SI|NO)$'
|
cachea-indicator: '^(SI|NO)$'
|
||||||
read-messages:
|
read-messages:
|
||||||
from-props: true
|
from-props: true
|
||||||
domLogalCustomerProductDirectory:
|
dom-legal-customer-product-directory:
|
||||||
messages:
|
messages:
|
||||||
key: 'domLogalCustomerProductDirectory'
|
key: 'dom-legal-customer-product-directory'
|
||||||
content: '[{"backendCode":"200","httpCode":200,"statusCode":"200","description":"Operacion exitosa"},{"backendCode":"R404","httpCode":404,"statusCode":"404","description":"Datos de validación no encontrado."},{"backendCode":"503","httpCode":503,"statusCode":"503","description":"Uso interno"},{"backendCode":"422","httpCode":422,"statusCode":"422","description":"Uso interno"},{"backendCode":"500","httpCode":500,"statusCode":"500","description":"Uso interno"},{"backendCode":"100","httpCode":503,"statusCode":"503","description":"VDR13 - OSB Disponible"},{"backendCode":"OSB-382505","httpCode":503,"statusCode":"503","description":"VDR13 - OSB Disponible"},{"backendCode":"OSB-380002","httpCode":503,"statusCode":"503","description":"VDR13 - OSB Disponible"},{"backendCode":"ERROR","httpCode":400,"statusCode":"400","description":"Uso interno"},{"backendCode":"400","httpCode":400,"statusCode":"400","description":"Uso interno"},{"backendCode":"401","httpCode":401,"statusCode":"401","description":"Uso interno"},{"backendCode":"403","httpCode":403,"statusCode":"403","description":"Uso interno"},{"backendCode":"404","httpCode":404,"statusCode":"404","description":"Uso interno"},{"backendCode":"default","httpCode":409,"statusCode":"409","description":"Conflicto"},{"backendCode":"424","httpCode":424,"statusCode":"424","description":"Error de dependencia"},{"backendCode":"VDE01","httpCode":400,"statusCode":"VDE01","description":"VDE01 - Error en dato de entrada obligatorio: %s"},{"backendCode":"VDE02","httpCode":400,"statusCode":"VDE02","description":"VDE02 - Error en valor permitido para campo: %s"},{"backend_code":"204","http_code":"200","status_code":"200","description":"Cliente sin productos","status":"ok"}]'
|
content: '[{"backendCode":"200","httpCode":200,"statusCode":"200","description":"Operacion exitosa"},{"backendCode":"R404","httpCode":404,"statusCode":"404","description":"Datos de validación no encontrado."},{"backendCode":"503","httpCode":503,"statusCode":"503","description":"Uso interno"},{"backendCode":"422","httpCode":422,"statusCode":"422","description":"Uso interno"},{"backendCode":"500","httpCode":500,"statusCode":"500","description":"Uso interno"},{"backendCode":"100","httpCode":503,"statusCode":"503","description":"VDR13 - OSB Disponible"},{"backendCode":"OSB-382505","httpCode":503,"statusCode":"503","description":"VDR13 - OSB Disponible"},{"backendCode":"OSB-380002","httpCode":503,"statusCode":"503","description":"VDR13 - OSB Disponible"},{"backendCode":"ERROR","httpCode":400,"statusCode":"400","description":"Uso interno"},{"backendCode":"400","httpCode":400,"statusCode":"400","description":"Uso interno"},{"backendCode":"401","httpCode":401,"statusCode":"401","description":"Uso interno"},{"backendCode":"403","httpCode":403,"statusCode":"403","description":"Uso interno"},{"backendCode":"404","httpCode":404,"statusCode":"404","description":"Uso interno"},{"backendCode":"default","httpCode":409,"statusCode":"409","description":"Conflicto"},{"backendCode":"424","httpCode":424,"statusCode":"424","description":"Error de dependencia"},{"backendCode":"VDE01","httpCode":400,"statusCode":"VDE01","description":"VDE01 - Error en dato de entrada obligatorio: %s"},{"backendCode":"VDE02","httpCode":400,"statusCode":"VDE02","description":"VDE02 - Error en valor permitido para campo: %s"},{"backend_code":"204","http_code":"200","status_code":"200","description":"Cliente sin productos","status":"ok"}]'
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user