Use typed backend errors for translations

This commit is contained in:
n200534
2026-08-20 01:11:30 +05:30
parent eff8bb16a0
commit 3efec5ce58
38 changed files with 164 additions and 79 deletions

View File

@@ -0,0 +1,20 @@
package com.commafeed;
import java.io.Serial;
import java.util.Objects;
public class CommaFeedApplicationException extends RuntimeException {
@Serial private static final long serialVersionUID = 1L;
private final CommaFeedExceptionType type;
public CommaFeedApplicationException(CommaFeedExceptionType type) {
super(Objects.requireNonNull(type).message());
this.type = type;
}
public CommaFeedExceptionType type() {
return type;
}
}

View File

@@ -0,0 +1,23 @@
package com.commafeed;
import org.jboss.resteasy.reactive.RestResponse.Status;
public enum CommaFeedExceptionType {
WRONG_USERNAME_OR_PASSWORD(Status.UNAUTHORIZED, "wrong username or password");
private final Status status;
private final String message;
CommaFeedExceptionType(Status status, String message) {
this.status = status;
this.message = message;
}
public Status status() {
return status;
}
public String message() {
return message;
}
}

View File

@@ -26,6 +26,18 @@ public class ExceptionMappers {
private final CookieService cookieService;
private final CommaFeedConfiguration config;
@ServerExceptionMapper(CommaFeedApplicationException.class)
public RestResponse<CommaFeedApplicationError> applicationError(
CommaFeedApplicationException e) {
ResponseBuilder<CommaFeedApplicationError> response =
ResponseBuilder.create(
e.type().status(), new CommaFeedApplicationError(e.type(), e.getMessage()));
if (e.type().status() == Status.UNAUTHORIZED) {
response.cookie(cookieService.buildLogoutCookie());
}
return response.build();
}
@ServerExceptionMapper(UnauthorizedException.class)
public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) {
return RestResponse.status(
@@ -55,4 +67,7 @@ public class ExceptionMappers {
@RegisterForReflection
public record ValidationFailed(String message) {}
@RegisterForReflection
public record CommaFeedApplicationError(CommaFeedExceptionType type, String message) {}
}

View File

@@ -1,11 +1,12 @@
package com.commafeed.security.identity;
import com.commafeed.CommaFeedApplicationException;
import com.commafeed.CommaFeedExceptionType;
import com.commafeed.backend.dao.UnitOfWork;
import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.service.UserService;
import io.quarkus.security.AuthenticationFailedException;
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.quarkus.security.identity.IdentityProvider;
import io.quarkus.security.identity.SecurityIdentity;
@@ -48,7 +49,8 @@ public class DatabaseUsernamePasswordIdentityProvider
new String(
request.getPassword().getPassword())));
if (user.isEmpty()) {
throw new AuthenticationFailedException("wrong username or password");
throw new CommaFeedApplicationException(
CommaFeedExceptionType.WRONG_USERNAME_OR_PASSWORD);
}
Set<Role> roles = unitOfWork.call(() -> userService.getRoles(user.get()));

View File

@@ -1,5 +1,7 @@
package com.commafeed.integration;
import com.commafeed.CommaFeedExceptionType;
import com.commafeed.ExceptionMappers.CommaFeedApplicationError;
import com.commafeed.ExceptionMappers.UnauthorizedResponse;
import com.commafeed.TestConstants;
import com.commafeed.frontend.model.Entries;
@@ -57,6 +59,27 @@ class SecurityIT extends BaseIT {
.statusCode(HttpStatus.SC_OK);
}
@Test
void formLoginWrongPassword() {
CommaFeedApplicationError error =
RestAssured.given()
.auth()
.none()
.formParams(
"j_username",
TestConstants.ADMIN_USERNAME,
"j_password",
"wrong-password")
.post("j_security_check")
.then()
.statusCode(HttpStatus.SC_UNAUTHORIZED)
.extract()
.as(CommaFeedApplicationError.class);
Assertions.assertEquals(CommaFeedExceptionType.WRONG_USERNAME_OR_PASSWORD, error.type());
Assertions.assertEquals("wrong username or password", error.message());
}
@Test
void basicAuthLogin() {
RestAssured.given()