Skip to content
This repository has been archived by the owner on Jan 10, 2021. It is now read-only.

Api remove hibernate validator #17

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
16 changes: 16 additions & 0 deletions api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,19 @@ Some features will be not sufficiently tested and will only be enabled if you ad
--seedNodes=localhost:8000 --btcNodes=localhost:18445 --baseCurrencyNetwork=BTC_REGTEST --logLevel=info
--useDevPrivilegeKeys=true --bitcoinRegtestHost=NONE --myAddress=172.17.0.1:8003
--enableHttpApiExperimentalFeatures"

## Integration tests

Integration tests leverage Docker and run in headless mode. First you need to build docker images for the api:

cd api
docker-compose build
../gradlew testIntegration

IntelliJ Idea has awesome integration so just right click on `api/src/testIntegration` directory and select
`Debug All Tests`.

### Integration tests logging

Due to Travis log length limitations the log level is set to WARN, but if you need to see more details locally
go to `ContainerFactory` class and set `ENV_LOG_LEVEL_VALUE` property to `debug`.
35 changes: 35 additions & 0 deletions api/src/main/java/bisq/api/http/exceptions/ExceptionMappers.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,18 @@

package bisq.api.http.exceptions;

import bisq.api.http.model.ValidationErrorMessage;

import bisq.core.exceptions.ConstraintViolationException;
import bisq.core.exceptions.ValidationException;

import com.fasterxml.jackson.core.JsonParseException;

import com.google.common.collect.ImmutableList;

import java.util.List;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;


Expand All @@ -38,6 +48,7 @@ public static void register(ResourceConfig environment) {
environment.register(new ExceptionMappers.EofExceptionMapper(), 1);
environment.register(new ExceptionMappers.JsonParseExceptionMapper(), 1);
environment.register(new ExceptionMappers.UnauthorizedExceptionMapper());
environment.register(new ExceptionMappers.ValidationExceptionMapper());
}

public static class EofExceptionMapper implements ExceptionMapper<EofException> {
Expand All @@ -60,4 +71,28 @@ public Response toResponse(UnauthorizedException exception) {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}

public static class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {
@Override
public Response toResponse(ValidationException exception) {
Response.ResponseBuilder responseBuilder = Response.status(422);
String message = exception.getMessage();
if (exception instanceof ConstraintViolationException) {
List<String> messages = ((ConstraintViolationException) exception).getConstraintViolations().stream().map(constraintViolation -> {
StringBuilder stringBuilder = new StringBuilder();
String propertyPath = constraintViolation.getPropertyPath();
if (propertyPath != null) {
stringBuilder.append(propertyPath).append(" ");
}
return stringBuilder.append(constraintViolation.getMessage()).toString();
}).collect(Collectors.toList());
responseBuilder.entity(new ValidationErrorMessage(ImmutableList.copyOf(messages)));
} else if (message != null) {
responseBuilder.entity(new ValidationErrorMessage(ImmutableList.of(message)));
} else {
responseBuilder.entity(new ValidationErrorMessage(ImmutableList.of()));
}
return responseBuilder.build();
}
}
}
6 changes: 4 additions & 2 deletions api/src/main/java/bisq/api/http/model/ChangePassword.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@

package bisq.api.http.model;

public class ChangePassword {
public class ChangePassword implements Validatable {

public String newPassword;
public String oldPassword;

@SuppressWarnings("unused")
public ChangePassword() {
}

public ChangePassword(String newPassword, String oldPassword) {
this.newPassword = newPassword;
this.oldPassword = oldPassword;
}

public void validate() {
}
}
29 changes: 29 additions & 0 deletions api/src/main/java/bisq/api/http/model/PayloadValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.api.http.model;

import bisq.core.exceptions.ValidationException;

public class PayloadValidator {
public void validateRequiredRequestPayload(Validatable data) {
if (null == data) {
throw new ValidationException("Request payload is required");
}
data.validate();
}
}
22 changes: 22 additions & 0 deletions api/src/main/java/bisq/api/http/model/Validatable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.api.http.model;

public interface Validatable {
void validate();
}
37 changes: 37 additions & 0 deletions api/src/main/java/bisq/api/http/model/ValidationErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.api.http.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import com.google.common.collect.ImmutableList;

public class ValidationErrorMessage {
private final ImmutableList<String> errors;

@JsonCreator
public ValidationErrorMessage(@JsonProperty("errors") ImmutableList<String> errors) {
this.errors = errors;
}

@JsonProperty
public ImmutableList<String> getErrors() {
return errors;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package bisq.api.http.service.endpoint;

import bisq.api.http.model.ChangePassword;
import bisq.api.http.model.PayloadValidator;
import bisq.api.http.service.auth.ApiPasswordManager;

import bisq.common.UserThread;
Expand All @@ -28,7 +29,6 @@

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
Expand All @@ -45,18 +45,21 @@
public class UserEndpoint {

private final ApiPasswordManager apiPasswordManager;
private final PayloadValidator payloadValidator;

@Inject
public UserEndpoint(ApiPasswordManager apiPasswordManager) {
public UserEndpoint(ApiPasswordManager apiPasswordManager, PayloadValidator payloadValidator) {
this.apiPasswordManager = apiPasswordManager;
this.payloadValidator = payloadValidator;
}

@Operation(summary = "Change password")
@POST
@Path("/password")
public void changePassword(@Suspended AsyncResponse asyncResponse, @Valid ChangePassword data) {
public void changePassword(@Suspended AsyncResponse asyncResponse, ChangePassword data) {
UserThread.execute(() -> {
try {
payloadValidator.validateRequiredRequestPayload(data);
apiPasswordManager.changePassword(data.oldPassword, data.newPassword);
asyncResponse.resume(Response.noContent().build());
} catch (Throwable e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.api.http.exceptions;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;



import javax.ws.rs.core.Response;
import org.eclipse.jetty.io.EofException;

public class EofExceptionMapperTest {

@Test
public void toResponse_always_statusIs400() {
// Given
ExceptionMappers.EofExceptionMapper mapper = new ExceptionMappers.EofExceptionMapper();

// When
Response response = mapper.toResponse(new EofException());

// Then
assertEquals(400, response.getStatus());
}

@Test
public void toResponse_always_noBody() {
// Given
ExceptionMappers.EofExceptionMapper mapper = new ExceptionMappers.EofExceptionMapper();

// When
Response response = mapper.toResponse(new EofException());

// Then
Object entity = response.getEntity();
assertNull(entity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.api.http.exceptions;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;



import javax.ws.rs.core.Response;

public class JsonParseExceptionMapperTest {

@Test
public void toResponse_always_statusIs400() {
// Given
ExceptionMappers.JsonParseExceptionMapper mapper = new ExceptionMappers.JsonParseExceptionMapper();

// When
Response response = mapper.toResponse(new JsonParseException((JsonParser) null, null));

// Then
assertEquals(400, response.getStatus());
}

@Test
public void toResponse_always_noBody() {
// Given
ExceptionMappers.JsonParseExceptionMapper mapper = new ExceptionMappers.JsonParseExceptionMapper();

// When
Response response = mapper.toResponse(new JsonParseException((JsonParser) null, null));

// Then
Object entity = response.getEntity();
assertNull(entity);
}
}
Loading