Skip to content

Commit

Permalink
CIRC-2099 POST Api implementation (folio-org#1481)
Browse files Browse the repository at this point in the history
* CIRC-2099 POST Api implementation of print event logs
  • Loading branch information
SreejaMangarapu authored Jul 29, 2024
1 parent e7e2682 commit 4b4301b
Show file tree
Hide file tree
Showing 12 changed files with 402 additions and 0 deletions.
26 changes: 26 additions & 0 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,23 @@
}
]
},
{
"id": "print-events",
"version": "1.0",
"handlers": [
{
"methods": ["POST"],
"pathPattern": "/circulation/print-events-entry",
"permissionsRequired": [
"circulation.print-events-entry.item.post"
],
"modulePermissions": [
"print-events-storage.print-events-entry.item.post",
"circulation-storage.circulation-settings.collection.get"
]
}
]
},
{
"id": "_timer",
"version": "1.0",
Expand Down Expand Up @@ -1318,6 +1335,10 @@
{
"id": "circulation-settings-storage",
"version": "1.0"
},
{
"id": "print-events-storage",
"version": "1.0"
}
],
"optional": [
Expand All @@ -1327,6 +1348,11 @@
}
],
"permissionSets": [
{
"permissionName": "circulation.print-events-entry.item.post",
"displayName": "circulation - create print events",
"description": "create print event logs"
},
{
"permissionName": "circulation.requests.queue.reorder.collection.post",
"displayName": "circulation - reorder queue for an item",
Expand Down
9 changes: 9 additions & 0 deletions ramls/examples/print-events-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"requestIds": [
"059e54bb-53e5-4039-a2fb-b34358e88b0a",
"e70dcbae-30c6-47ac-94f8-4ffefd44a935"
],
"requesterId": "d51470ea-5daa-480b-a4aa-09c8c6d9940e",
"requesterName": "requester",
"printEventDate": "2024-06-25T20:00:00+05:30"
}
2 changes: 2 additions & 0 deletions src/main/java/org/folio/circulation/CirculationVerticle.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.folio.circulation.resources.OverdueFineCirculationRulesEngineResource;
import org.folio.circulation.resources.OverdueFineScheduledNoticeProcessingResource;
import org.folio.circulation.resources.PickSlipsResource;
import org.folio.circulation.resources.PrintEventsResource;
import org.folio.circulation.resources.RequestByInstanceIdResource;
import org.folio.circulation.resources.RequestCirculationRulesEngineResource;
import org.folio.circulation.resources.RequestCollectionResource;
Expand Down Expand Up @@ -152,6 +153,7 @@ public void start(Promise<Void> startFuture) {
new LoanRelatedFeeFineClosedHandlerResource(client).register(router);
new FeeFineBalanceChangedHandlerResource(client).register(router);
new CirculationSettingsResource(client).register(router);
new PrintEventsResource(client).register(router);

server.requestHandler(router)
.listen(config().getInteger("port"), result -> {
Expand Down
59 changes: 59 additions & 0 deletions src/main/java/org/folio/circulation/domain/PrintEventRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.folio.circulation.domain;

import io.vertx.core.json.JsonObject;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.invoke.MethodHandles;
import java.util.List;
import java.util.Set;

import static lombok.AccessLevel.PRIVATE;
import static org.folio.circulation.support.json.JsonPropertyFetcher.getArrayProperty;
import static org.folio.circulation.support.json.JsonPropertyFetcher.getProperty;

@AllArgsConstructor(access = PRIVATE)
@ToString(onlyExplicitlyIncluded = true)
public class PrintEventRequest {
private static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass());
public static final String REQUEST_IDS_FIELD = "requestIds";
public static final String REQUESTER_ID_FIELD = "requesterId";
public static final String REQUESTER_NAME_FIELD = "requesterName";
public static final String PRINT_DATE_FIELD = "printEventDate";

@ToString.Include
@Getter
private final JsonObject representation;

@Getter
private final List<String> requestIds;
@Getter
private final String requesterId;
@Getter
private final String requesterName;
@Getter
private final String printEventDate;

public static PrintEventRequest from(JsonObject representation) {
final var requestIds = getArrayProperty(representation, REQUEST_IDS_FIELD).stream()
.map(String.class::cast)
.toList();
final var requesterId = getProperty(representation, REQUESTER_ID_FIELD);
final var requesterName = getProperty(representation, REQUESTER_NAME_FIELD);
final var printEventDate = getProperty(representation, PRINT_DATE_FIELD);

if (requestIds.isEmpty() || null == requesterId || null == requesterName || null == printEventDate || !containsOnlyKnownFields(representation)) {
log.info("from:: Print Event Request JSON is invalid: {},{},{},{},{}", representation, requestIds, requesterName, requesterId, printEventDate);
return null;
}
return new PrintEventRequest(representation, requestIds, requesterId, requesterName, printEventDate);
}

private static boolean containsOnlyKnownFields(JsonObject representation) {
return Set.of(REQUEST_IDS_FIELD, REQUESTER_ID_FIELD, REQUESTER_NAME_FIELD, PRINT_DATE_FIELD)
.containsAll(representation.fieldNames());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.folio.circulation.infrastructure.storage;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.circulation.domain.PrintEventRequest;
import org.folio.circulation.support.Clients;
import org.folio.circulation.support.CollectionResourceClient;
import org.folio.circulation.support.http.client.ResponseInterpreter;
import org.folio.circulation.support.results.Result;

import java.lang.invoke.MethodHandles;
import java.util.concurrent.CompletableFuture;

import static org.folio.circulation.support.http.ResponseMapping.forwardOnFailure;
import static org.folio.circulation.support.results.Result.succeeded;

public class PrintEventsRepository {
private static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass());

private final CollectionResourceClient printEventsStorageClient;

public PrintEventsRepository(Clients clients) {
printEventsStorageClient = clients.printEventsStorageClient();
}

public CompletableFuture<Result<Void>> create(PrintEventRequest printEventRequest) {
log.info("create:: parameters printEvent: {}", printEventRequest);
final var storagePrintEventRequest = printEventRequest.getRepresentation();
final ResponseInterpreter<Void> interpreter = new ResponseInterpreter<Void>()
.on(201, succeeded(null))
.otherwise(forwardOnFailure());
return printEventsStorageClient.post(storagePrintEventRequest).thenApply(interpreter::flatMap);
}

}
111 changes: 111 additions & 0 deletions src/main/java/org/folio/circulation/resources/PrintEventsResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.folio.circulation.resources;

import io.vertx.core.http.HttpClient;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.circulation.domain.CirculationSetting;
import org.folio.circulation.domain.MultipleRecords;
import org.folio.circulation.domain.PrintEventRequest;
import org.folio.circulation.infrastructure.storage.CirculationSettingsRepository;
import org.folio.circulation.infrastructure.storage.PrintEventsRepository;
import org.folio.circulation.infrastructure.storage.requests.RequestRepository;
import org.folio.circulation.support.Clients;
import org.folio.circulation.support.RouteRegistration;
import org.folio.circulation.support.http.server.JsonHttpResponse;
import org.folio.circulation.support.http.server.WebContext;
import org.folio.circulation.support.results.Result;

import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

import static org.folio.circulation.support.ValidationErrorFailure.singleValidationError;
import static org.folio.circulation.support.json.JsonPropertyFetcher.getProperty;
import static org.folio.circulation.support.results.Result.ofAsync;
import static org.folio.circulation.support.results.Result.succeeded;

public class PrintEventsResource extends Resource {
private static final Logger log = LogManager.getLogger(MethodHandles.lookup().lookupClass());
private static final String PRINT_EVENT_FLAG_QUERY = "query=name=printEventLogFeature";
private static final String PRINT_EVENT_FEATURE_DISABLED_ERROR = "print event feature is disabled for this tenant";
private static final String NO_CONFIG_FOUND_ERROR = "No configuration found for print event feature";
private static final String MULTIPLE_CONFIGS_ERROR = "Multiple configurations found for print event feature";
private static final String PRINT_EVENT_FLAG_PROPERTY_NAME = "enablePrintLog";

public PrintEventsResource(HttpClient client) {
super(client);
}

@Override
public void register(Router router) {
new RouteRegistration("/circulation/print-events-entry", router)
.create(this::create);
}

void create(RoutingContext routingContext) {
final var context = new WebContext(routingContext);
final var clients = Clients.create(context, client);
final var printEventsRepository = new PrintEventsRepository(clients);
final var circulationSettingsRepository = new CirculationSettingsRepository(clients);
final var requestRepository = new RequestRepository(clients);
final var incomingRepresentation = routingContext.body().asJsonObject();
final var printEventRequest = PrintEventRequest.from(incomingRepresentation);

log.info("create:: Creating print event: {}", printEventRequest);

ofAsync(printEventRequest)
.thenApply(refuseWhenPrintEventRequestIsInvalid())
.thenCompose(r -> r.after(validatePrintEventFeatureFlag(circulationSettingsRepository)))
.thenCompose(r -> r.after(validateRequests(requestRepository)))
.thenCompose(r -> r.after(printEventsRepository::create))
.thenApply(r -> r.map(response -> JsonHttpResponse.created(null, null)))
.thenAccept(context::writeResultToHttpResponse);
}

private static Function<PrintEventRequest, CompletableFuture<Result<PrintEventRequest>>>
validateRequests(RequestRepository requestRepository) {
return printRequest -> requestRepository.fetchRequests(printRequest.getRequestIds())
.thenApply(printRequestList -> printRequestList.map(Collection::size)).thenApply(size -> {
if (size.value() != printRequest.getRequestIds().size()) {
return Result.failed(singleValidationError("invalid request found", "", ""));
}
return succeeded(printRequest);
});
}

private static Function<Result<PrintEventRequest>, Result<PrintEventRequest>>
refuseWhenPrintEventRequestIsInvalid() {
return r -> r.failWhen(printEventRequest -> succeeded(printEventRequest == null),
circulationSetting -> singleValidationError("Print Event Request JSON is invalid", "", ""));
}

private static Function<PrintEventRequest, CompletableFuture<Result<PrintEventRequest>>> validatePrintEventFeatureFlag(
CirculationSettingsRepository circulationSettingsRepository) {
return printEventRequest -> circulationSettingsRepository.findBy(PRINT_EVENT_FLAG_QUERY)
.thenApply(result ->
handleCirculationSettingResult(result.map(MultipleRecords::getRecords), printEventRequest)
);
}

private static Result<PrintEventRequest> handleCirculationSettingResult(Result<Collection<CirculationSetting>> result,
PrintEventRequest printEventRequest) {

int size = result.value().size();
if (size == 0) {
return Result.failed(singleValidationError(NO_CONFIG_FOUND_ERROR, "", ""));
} else if (size > 1) {
return Result.failed(singleValidationError(MULTIPLE_CONFIGS_ERROR, "", ""));
}
boolean isEnabled = result.value().stream()
.map(x -> Boolean.valueOf(getProperty(x.getValue(), PRINT_EVENT_FLAG_PROPERTY_NAME))).findFirst().orElse(true);

if (!isEnabled) {
return Result.failed(singleValidationError(PRINT_EVENT_FEATURE_DISABLED_ERROR, "", ""));
}
return succeeded(printEventRequest);
}

}
15 changes: 15 additions & 0 deletions src/main/java/org/folio/circulation/support/Clients.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public class Clients {
private final CollectionResourceClient circulationItemClient;
private final GetManyRecordsClient settingsStorageClient;
private final CollectionResourceClient circulationSettingsStorageClient;
private final CollectionResourceClient printEventsStorageClient;


public static Clients create(WebContext context, HttpClient httpClient) {
return new Clients(context.createHttpClient(httpClient), context);
Expand Down Expand Up @@ -138,6 +140,8 @@ private Clients(OkapiHttpClient client, WebContext context) {
settingsStorageClient = createSettingsStorageClient(client, context);
circulationItemClient = createCirculationItemClient(client, context);
circulationSettingsStorageClient = createCirculationSettingsStorageClient(client, context);
printEventsStorageClient = createPrintEventsStorageClient(client, context);

}
catch(MalformedURLException e) {
throw new InvalidOkapiLocationException(context.getOkapiLocation(), e);
Expand Down Expand Up @@ -380,6 +384,10 @@ public CollectionResourceClient circulationSettingsStorageClient() {
return circulationSettingsStorageClient;
}

public CollectionResourceClient printEventsStorageClient() {
return printEventsStorageClient;
}

private static CollectionResourceClient getCollectionResourceClient(
OkapiHttpClient client, WebContext context,
String path)
Expand Down Expand Up @@ -814,6 +822,13 @@ private CollectionResourceClient createCirculationSettingsStorageClient(
"/circulation-settings-storage/circulation-settings");
}

private CollectionResourceClient createPrintEventsStorageClient(
OkapiHttpClient client, WebContext context) throws MalformedURLException {

return getCollectionResourceClient(client, context,
"/print-events-storage/print-events-entry");
}

private GetManyRecordsClient createSettingsStorageClient(
OkapiHttpClient client, WebContext context)
throws MalformedURLException {
Expand Down
Loading

0 comments on commit 4b4301b

Please sign in to comment.