Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ public class JsonServerExceptionMappers {
public Response map(MismatchedInputException e) {
Log.warn(e);
// e.g. screenerName is object but DTO expects String
String field =
e.getPath() != null && !e.getPath().isEmpty()
? e.getPath().get(e.getPath().size() - 1).getFieldName()
: "request body";
String field = e.getPath() != null && !e.getPath().isEmpty()
? e.getPath().get(e.getPath().size() - 1).getFieldName()
: "request body";

return Response.status(Response.Status.BAD_REQUEST)
.type(MediaType.APPLICATION_JSON)
.entity(ApiError.of("Invalid type for field '" + field + "'."))
.build();
.entity(ApiError.of("Invalid type for field '" + field + "'.")).build();
}

@ServerExceptionMapper
Expand All @@ -32,16 +30,16 @@ public Response map(JsonParseException e) {
// malformed JSON like { "schema": }
return Response.status(Response.Status.BAD_REQUEST)
.type(MediaType.APPLICATION_JSON)
.entity(ApiError.of("Malformed JSON."))
.build();
.entity(ApiError.of("JsonParseException: Malformed JSON.")).build();
}

@ServerExceptionMapper
public Response map(WebApplicationException e) {
Log.info("Some malformed JSON");
Log.warn(e);
return Response.status(Response.Status.BAD_REQUEST)
.type(MediaType.APPLICATION_JSON)
.entity(ApiError.of("Malformed JSON."))
.entity(ApiError.of("WebApplicationException: Malformed JSON."))
.build();
}

Expand All @@ -51,7 +49,6 @@ public Response map(JsonMappingException e) {
// other mapping errors
return Response.status(Response.Status.BAD_REQUEST)
.type(MediaType.APPLICATION_JSON)
.entity(ApiError.of("Invalid request body."))
.build();
.entity(ApiError.of("Invalid request body.")).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.acme.controller;

import io.quarkus.security.identity.SecurityIdentity;
import jakarta.inject.Inject;
import jakarta.validation.Validator;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.*;

import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.acme.api.error.ApiError;
import org.acme.auth.AuthUtils;
import org.acme.enums.AccountHookAction;
import org.acme.functions.AccountHooks;
import org.acme.model.dto.Auth.AccountHookRequest;
import org.acme.model.dto.Auth.AccountHookResponse;

@Path("/api")
public class AccountResource {

@Inject
Validator validator;

@Inject
AccountHooks accountHooks;

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Path("/account-hooks")
public Response accountHooks(@Context SecurityIdentity identity,
AccountHookRequest request) {

Set<AccountHookAction> hooks = request.hooks();
String userId = AuthUtils.getUserId(identity);

if (userId == null) {
return Response.status(Response.Status.UNAUTHORIZED)
.entity(new ApiError(true, "Unauthorized.")).build();
}

// Map of AccountHookAction to a hook side-effect function
// The function returns whether the side-effect was successful
Map<AccountHookAction, Predicate<String>> hooksMap = Map.of(
AccountHookAction.ADD_EXAMPLE_SCREENER,
accountHooks::addExampleScreenerToAccount,
AccountHookAction.UNABLE_TO_DETERMINE,
(String uId) -> true);

// Run each action's function and determine whether successful
Map<String, Boolean> hookResults = hooks.stream()
.collect(Collectors.toMap(s -> s.toString(), s -> {
Predicate<String> fn = hooksMap.get(s);
return fn.test(userId);
}));

AccountHookResponse responseBody = new AccountHookResponse(true,
hookResults);

return Response.ok(responseBody).build();
}
}
30 changes: 30 additions & 0 deletions builder-api/src/main/java/org/acme/enums/AccountHookAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.acme.enums;

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

public enum AccountHookAction {
ADD_EXAMPLE_SCREENER("add example screener"),
UNABLE_TO_DETERMINE("UNABLE_TO_DETERMINE");

private final String label;

AccountHookAction(String label) {
this.label = label;
}

@JsonValue
public String getLabel() {
return label;
}

@JsonCreator
public static AccountHookAction fromValue(String value) {
for (AccountHookAction action : values()) {
if (action.label.equalsIgnoreCase(value)) {
return action;
}
}
return UNABLE_TO_DETERMINE;
}
}
28 changes: 28 additions & 0 deletions builder-api/src/main/java/org/acme/functions/AccountHooks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.acme.functions;

import io.quarkus.logging.Log;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import org.acme.service.ExampleScreenerImportService;

@ApplicationScoped
public class AccountHooks {
@Inject
ExampleScreenerImportService exampleScreenerImportService;

public Boolean addExampleScreenerToAccount(String userId) {
try {
Log.info("Running ADD_EXAMPLE_SCREENER hook for user: " + userId);
String screenerId = exampleScreenerImportService.importForUser(userId);
Log.info("Imported example screener " + screenerId + " for user " + userId);
return true;
} catch (Exception e) {
Log.error(
"Failed to run ADD_EXAMPLE_SCREENER hook for user: "
+ userId,
e);
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.acme.model.dto.Auth;

import java.util.Set;

import org.acme.enums.AccountHookAction;

public record AccountHookRequest(Set<AccountHookAction> hooks) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.acme.model.dto.Auth;

import java.util.Map;

public record AccountHookResponse(Boolean success,
Map<String, Boolean> actions) {
};
Loading
Loading