diff --git a/pom.xml b/pom.xml index 15bc0bbd..dfd27ced 100644 --- a/pom.xml +++ b/pom.xml @@ -32,12 +32,12 @@ UTF-8 - 6.2.1 - 3.4.0 - 4.5.13 - 2.24.3 + 7.0.1 + 4.1.1 + 5.0.8 + 2.25.3 + org.folio.eusage.reports.MainVerticle - @@ -101,19 +101,19 @@ io.vertx - vertx-web + vertx-launcher-application io.vertx - vertx-web-openapi + vertx-web io.vertx - vertx-rx-java2 + vertx-web-openapi-router io.vertx - vertx-web-api-contract + vertx-rx-java2 io.vertx @@ -190,7 +190,7 @@ org.mockito mockito-core - 5.16.0 + 5.23.0 test @@ -216,8 +216,8 @@ - io.vertx.core.Launcher - org.folio.eusage.reports.MainVerticle + io.vertx.launcher.application.VertxApplication + ${exec.mainClass} true diff --git a/src/main/java/org/folio/eusage/reports/api/CostPerUse.java b/src/main/java/org/folio/eusage/reports/api/CostPerUse.java index a32bfbea..afeefc45 100644 --- a/src/main/java/org/folio/eusage/reports/api/CostPerUse.java +++ b/src/main/java/org/folio/eusage/reports/api/CostPerUse.java @@ -134,7 +134,7 @@ static JsonObject titlesToJsonObject(RowSet rowSet, Periods usePeriods) { item = new JsonObject(); totalItems.put(itemKey, item); items.add(item); - item.put("kbId", kbId) + item.put("kbId", kbId.toString()) .put("title", row.getString("title")) .put("derivedTitle", kbPackageId != null); String printIssn = row.getString("printissn"); diff --git a/src/main/java/org/folio/eusage/reports/api/EusageReportsApi.java b/src/main/java/org/folio/eusage/reports/api/EusageReportsApi.java index 70ac1f9a..7fe844be 100644 --- a/src/main/java/org/folio/eusage/reports/api/EusageReportsApi.java +++ b/src/main/java/org/folio/eusage/reports/api/EusageReportsApi.java @@ -16,10 +16,12 @@ import io.vertx.ext.web.client.HttpResponse; import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.codec.BodyCodec; -import io.vertx.ext.web.openapi.RouterBuilder; -import io.vertx.ext.web.validation.RequestParameter; -import io.vertx.ext.web.validation.RequestParameters; -import io.vertx.ext.web.validation.ValidationHandler; +import io.vertx.ext.web.openapi.router.RouterBuilder; +import io.vertx.openapi.contract.OpenAPIContract; +import io.vertx.openapi.contract.Operation; +import io.vertx.openapi.contract.Parameter; +import io.vertx.openapi.validation.RequestParameter; +import io.vertx.openapi.validation.ValidatedRequest; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowIterator; import io.vertx.sqlclient.RowSet; @@ -33,13 +35,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.folio.okapi.common.GenericCompositeFuture; import org.folio.okapi.common.XOkapiHeaders; import org.folio.tlib.RouterCreator; import org.folio.tlib.TenantInitHooks; @@ -92,8 +94,9 @@ static String statusTable(TenantPgPool pool) { static void failHandler(RoutingContext ctx) { Throwable t = ctx.failure(); // both semantic errors and syntax errors are from same pile ... Choosing 400 over 422. - int statusCode = t.getClass().getName().startsWith("io.vertx.ext.web.validation") ? 400 : 500; - failHandler(statusCode, ctx, t.getMessage()); + int statusCode = t.getClass().getName().startsWith("io.vertx.ext.web.handler") ? 400 : 500; + failHandler(statusCode, ctx, + t.getCause() == null ? t.getMessage() : t.getCause().getMessage()); } static void failHandler(int statusCode, RoutingContext ctx, Throwable e) { @@ -115,7 +118,11 @@ private static JsonObject copyWithoutNulls(JsonObject obj) { JsonObject n = new JsonObject(); obj.getMap().forEach((key, value) -> { if (value != null) { - n.put(key, value); + if (value instanceof UUID) { + n.put(key, value.toString()); + } else { + n.put(key, value); + } } }); return n; @@ -191,7 +198,7 @@ static Future streamResult(RoutingContext ctx, SqlConnection sqlConnection log.error(f.getMessage(), f); resultFooter(ctx, null, facets, f.getMessage()); }) - .eventually(x -> tx.commit().compose(y -> sqlConnection.close()))); + .eventually(() -> tx.commit().compose(y -> sqlConnection.close()).mapEmpty())); stream.exceptionHandler(e -> { log.error("stream error {}", e.getMessage(), e); resultFooter(ctx, null, facets, e.getMessage()); @@ -214,10 +221,8 @@ static Future streamResult(RoutingContext ctx, TenantPgPool pool, List fromList, List facets, String orderByClause, String property, Function handler) { - - RequestParameters params = ctx.get(ValidationHandler.REQUEST_CONTEXT_KEY); - Integer offset = params.queryParameter("offset").getInteger(); - Integer limit = params.queryParameter("limit").getInteger(); + String offset = ctx.request().params().get("offset"); + String limit = ctx.request().params().get("limit"); String query = "SELECT " + (distinctMain != null ? "DISTINCT ON (" + distinctMain + ")" : "") + " * FROM " + fromList.get(0) + (orderByClause == null ? "" : " ORDER BY " + orderByClause) @@ -241,6 +246,25 @@ static Future streamResult(RoutingContext ctx, TenantPgPool pool, .onFailure(x -> sqlConnection.close())); } + /** + * The Open API 3.0 parser in Vert.x 5.0 appears to only forward query parameters that are + * actually provided by client, ignoring if the spec declares defaults. Thus looking up + * the defaults programmatically. + */ + static void getParameterDefaults(RoutingContext ctx) { + Operation operation = (Operation) ctx.currentRoute().metadata().get("openApiOperation"); + if (operation != null) { + for (Parameter specParameter : operation.getParameters()) { + String specName = specParameter.getName(); + Object specDefault = specParameter.getSchema().get("default"); + if (specDefault != null && !ctx.request().params().contains(specName)) { + ctx.request().params().add(specName, specDefault.toString()); + } + } + } + + } + Future getReportTitles(Vertx vertx, RoutingContext ctx) { PgCqlDefinition definition = PgCqlDefinition.create(); definition.addField("cql.allRecords", new PgCqlFieldAlwaysMatches()); @@ -259,16 +283,32 @@ Future getReportTitles(Vertx vertx, RoutingContext ctx) { definition.addField("kbManualMatch", new PgCqlFieldBoolean() .withColumn("title_entries.kbmanualmatch")); - RequestParameters params = ctx.get(ValidationHandler.REQUEST_CONTEXT_KEY); - final String counterReportId = stringOrNull(params.queryParameter("counterReportId")); - final String providerId = stringOrNull(params.queryParameter("providerId")); + // The Open API 3.0 parser in Vert.x 5.0 appears to not support validation of all + // the possible CQL query strings that are needed for operating the report titles API. + // Thus validating some parameters programmatically. + try { + String offsetParam = ctx.request().params().get("offset"); + String limitParam = ctx.request().params().get("limit"); + if (limitParam != null && Integer.parseInt(limitParam) < 0) { + throw new IllegalArgumentException("limit in location QUERY: value should be >= 0"); + } + if (offsetParam != null && Integer.parseInt(offsetParam) < 0) { + throw new IllegalArgumentException("offset in location QUERY: value should be >= 0"); + } + } catch (NumberFormatException nfe) { + throw new IllegalArgumentException("Parameters limit and offset must be integers: " + + nfe.getMessage()); + } + + final String counterReportId = ctx.request().getParam("counterReportId"); + final String providerId = ctx.request().getParam("providerId"); final TenantPgPool pool = TenantPgPool.pool(vertx, TenantUtil.tenant(ctx)); final String distinctCount = titleEntriesTable(pool) + ".id"; - final String query = stringOrNull(params.queryParameter("query")); - RequestParameter facetsParameter = params.queryParameter("facets"); - String [] facetsList = facetsParameter == null + final String query = ctx.request().getParam("query"); + final String facets = ctx.request().getParam("facets"); + String [] facetsList = facets == null ? new String[0] - : facetsParameter.getString().split(","); + : facets.split(","); boolean includeStatusFacet = false; for (String name : facetsList) { @@ -351,10 +391,11 @@ private String getFromTitleDataForeignKey(PgCqlQuery pgCqlQuery, String counterR Future postReportTitles(Vertx vertx, RoutingContext ctx) { TenantPgPool pool = TenantPgPool.pool(vertx, TenantUtil.tenant(ctx)); + ValidatedRequest request = ctx.get(RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST); return pool.getConnection() .compose(sqlConnection -> { - Future future = Future.succeededFuture(); - final JsonArray titles = ctx.getBodyAsJson().getJsonArray("titles"); + Future future = Future.succeededFuture(); + final JsonArray titles = request.getBody().getJsonObject().getJsonArray("titles"); for (int i = 0; i < titles.size(); i++) { final JsonObject titleEntry = titles.getJsonObject(i); UUID id = UUID.fromString(titleEntry.getString("id")); @@ -378,7 +419,7 @@ Future postReportTitles(Vertx vertx, RoutingContext ctx) { })); } return future - .eventually(x -> sqlConnection.close()) + .eventually(sqlConnection::close) .onFailure(x -> log.error(x.getMessage(), x)); }) .compose(x -> { @@ -394,10 +435,12 @@ Future getReportPackages(Vertx vertx, RoutingContext ctx) { definition.addField("kbPackageName", new PgCqlFieldText().withFullText()); definition.addField("kbTitleId", new PgCqlFieldUuid()); - RequestParameters params = ctx.get(ValidationHandler.REQUEST_CONTEXT_KEY); + final ValidatedRequest validatedRequest = + ctx.get(RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST); + Map parameters = validatedRequest.getQuery(); final TenantPgPool pool = TenantPgPool.pool(vertx, TenantUtil.tenant(ctx)); - PgCqlQuery pgCqlQuery = definition.parse(stringOrNull(params.queryParameter("query"))); + PgCqlQuery pgCqlQuery = definition.parse(stringOrNull(parameters.get("query"))); String cqlWhere = pgCqlQuery.getWhereClause(); String from = packageEntriesTable(pool); @@ -413,7 +456,9 @@ Future getReportPackages(Vertx vertx, RoutingContext ctx) { } Future getTitleData(Vertx vertx, RoutingContext ctx) { - RequestParameters params = ctx.get(ValidationHandler.REQUEST_CONTEXT_KEY); + final ValidatedRequest validatedRequest = + ctx.get(RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST); + Map parameters = validatedRequest.getQuery(); PgCqlDefinition definition = PgCqlDefinition.create(); definition.addField("cql.allRecords", new PgCqlFieldAlwaysMatches()); @@ -422,12 +467,11 @@ Future getTitleData(Vertx vertx, RoutingContext ctx) { TenantPgPool pool = TenantPgPool.pool(vertx, TenantUtil.tenant(ctx)); String from = titleDataTable(pool); - PgCqlQuery pgCqlQuery = definition.parse(stringOrNull(params.queryParameter("query"))); + PgCqlQuery pgCqlQuery = definition.parse(stringOrNull(parameters.get("query"))); String cqlWhere = pgCqlQuery.getWhereClause(); if (cqlWhere != null) { from = from + " WHERE " + cqlWhere; } - return streamResult(ctx, pool, null, from, pgCqlQuery.getOrderByClause(), "data", row -> { JsonObject obj = new JsonObject() @@ -538,7 +582,7 @@ Future ermFetch(RoutingContext ctx, String uri, int page, JsonArray r final String pageUri = uri + sep + "perPage=100&page=" + page; return getRequestSend(ctx, pageUri) .compose(res -> { - JsonArray ar = res.bodyAsJsonArray(); + JsonArray ar = res.body().toJsonArray(); if (ar.isEmpty()) { return Future.succeededFuture(result); } @@ -847,10 +891,13 @@ Future handleReport(TenantPgPool pool, SqlConnection con, RoutingContext c } HttpRequest getRequest(RoutingContext ctx, String uri) { - RequestParameters params = ctx.get(ValidationHandler.REQUEST_CONTEXT_KEY); - final String okapiUrl = stringOrNull(params.headerParameter(XOkapiHeaders.URL)); - final String tenant = stringOrNull(params.headerParameter(XOkapiHeaders.TENANT)); - final String token = stringOrNull(params.headerParameter(XOkapiHeaders.TOKEN)); + final ValidatedRequest validatedRequest = + ctx.get(RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST); + Map headers = validatedRequest.getHeaders(); + + final String okapiUrl = stringOrNull(headers.get(XOkapiHeaders.URL)); + final String tenant = stringOrNull(headers.get(XOkapiHeaders.TENANT)); + final String token = stringOrNull(headers.get(XOkapiHeaders.TOKEN)); log.info("GET {} request", uri); return webClient.request(HttpMethod.GET, new RequestOptions().setAbsoluteURI(okapiUrl + uri)) .putHeader(XOkapiHeaders.TOKEN, token) @@ -882,10 +929,12 @@ Future> getRequestSend(RoutingContext ctx, String uri) { * @return Result with True if found; False if counter report not found. */ Future populateCounterReportTitles(Vertx vertx, RoutingContext ctx) { - RequestParameters params = ctx.get(ValidationHandler.REQUEST_CONTEXT_KEY); - final String okapiUrl = stringOrNull(params.headerParameter(XOkapiHeaders.URL)); - final String id = ctx.getBodyAsJson().getString("counterReportId"); - final String providerId = ctx.getBodyAsJson().getString("providerId"); + final ValidatedRequest validatedRequest = + ctx.get(RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST); + Map headers = validatedRequest.getHeaders(); + final String okapiUrl = stringOrNull(headers.get(XOkapiHeaders.URL)); + final String id = validatedRequest.getBody().getJsonObject().getString("counterReportId"); + final String providerId = validatedRequest.getBody().getJsonObject().getString("providerId"); if (okapiUrl == null) { return Future.failedFuture("Missing " + XOkapiHeaders.URL); @@ -916,7 +965,7 @@ private Future populateCounterReportTitles(CounterReportContext context promise.tryFail("GET " + uri + " returned bad JSON: " + x.getMessage()); }); parser.endHandler(e -> - GenericCompositeFuture.all(futures) + Future.all(futures) .onComplete(x -> promise.handle(x.mapEmpty())) ); return getRequest(context.ctx, uri) @@ -932,7 +981,7 @@ private Future populateCounterReportTitles(CounterReportContext context } return promise.future().map(true); }) - .eventually(x -> con.close()) + .eventually(con::close) .compose(res -> { if (offset + limit >= totalRecords.get()) { return Future.succeededFuture(res); @@ -989,7 +1038,9 @@ private void populateCounterReportHandle( } Future getReportData(Vertx vertx, RoutingContext ctx) { - RequestParameters params = ctx.get(ValidationHandler.REQUEST_CONTEXT_KEY); + final ValidatedRequest validatedRequest = + ctx.get(RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST); + Map parameters = validatedRequest.getQuery(); PgCqlDefinition definition = PgCqlDefinition.create(); definition.addField("cql.allRecords", new PgCqlFieldAlwaysMatches()); @@ -1001,7 +1052,7 @@ Future getReportData(Vertx vertx, RoutingContext ctx) { TenantPgPool pool = TenantPgPool.pool(vertx, TenantUtil.tenant(ctx)); String from = agreementEntriesTable(pool); - PgCqlQuery pgCqlQuery = definition.parse(stringOrNull(params.queryParameter("query"))); + PgCqlQuery pgCqlQuery = definition.parse(stringOrNull(parameters.get("query"))); String cqlWhere = pgCqlQuery.getWhereClause(); if (cqlWhere != null) { from = from + " WHERE " + cqlWhere; @@ -1448,7 +1499,8 @@ private Future insertAgreementLine(TenantPgPool pool, SqlConnection con, U } Future populateAgreement(Vertx vertx, RoutingContext ctx) { - final String agreementIdStr = ctx.getBodyAsJson().getString("agreementId"); + ValidatedRequest request = ctx.get(RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST); + final String agreementIdStr = request.getBody().getJsonObject().getString("agreementId"); if (agreementIdStr == null) { return Future.failedFuture("Missing agreementId property"); } @@ -1477,10 +1529,10 @@ Future populateAgreement(Vertx vertx, RoutingContext ctx) { } return future.compose(x -> tx.commit()).map(items.size()); }) - .eventually(x -> populateStatus(pool, agreementId, false)); + .eventually(() -> populateStatus(pool, agreementId, false)); }) ) - .eventually(x -> con.close()) + .eventually(con::close) ); } @@ -1842,26 +1894,41 @@ Future getReportStatus(Vertx vertx, RoutingContext ctx) { }); } + private void addNoValidate(RouterBuilder routerBuilder, String operationId, + Function> function) { + routerBuilder.getRoute(operationId).setDoValidation(false) + .addHandler(ctx -> { + try { + getParameterDefaults(ctx); + function.apply(ctx) + .onFailure(cause -> failHandler(400, ctx, cause)); + } catch (Throwable t) { + failHandler(400, ctx, t); + } + }).addFailureHandler(EusageReportsApi::failHandler); + } + private void add(RouterBuilder routerBuilder, String operationId, Function> function) { - routerBuilder - .operation(operationId) - .handler(ctx -> { + routerBuilder.getRoute(operationId).setDoValidation(true) + .addHandler(ctx -> { + getParameterDefaults(ctx); try { function.apply(ctx) .onFailure(cause -> failHandler(400, ctx, cause)); } catch (Throwable t) { failHandler(400, ctx, t); } - }).failureHandler(EusageReportsApi::failHandler); + }).addFailureHandler(EusageReportsApi::failHandler); } @Override public Future createRouter(Vertx vertx) { - return RouterBuilder.create(vertx, "openapi/eusage-reports-1.0.yaml") - .map(routerBuilder -> { - add(routerBuilder, "getReportTitles", ctx -> getReportTitles(vertx, ctx)); + return OpenAPIContract.from(vertx, "openapi/eusage-reports-1.0.yaml") + .map(contract -> { + RouterBuilder routerBuilder = RouterBuilder.create(vertx, contract); + addNoValidate(routerBuilder, "getReportTitles", ctx -> getReportTitles(vertx, ctx)); add(routerBuilder, "postReportTitles", ctx -> postReportTitles(vertx, ctx)); add(routerBuilder, "getReportPackages", ctx -> getReportPackages(vertx, ctx)); add(routerBuilder, "postFromCounter", ctx -> postFromCounter(vertx, ctx)); @@ -2015,4 +2082,5 @@ public Future postInit(Vertx vertx, String tenant, JsonObject tenantAttrib + "$$ LANGUAGE SQL IMMUTABLE STRICT" )); } + } diff --git a/src/main/java/org/folio/eusage/reports/api/UseOverTime.java b/src/main/java/org/folio/eusage/reports/api/UseOverTime.java index 4d3f9583..80103856 100644 --- a/src/main/java/org/folio/eusage/reports/api/UseOverTime.java +++ b/src/main/java/org/folio/eusage/reports/api/UseOverTime.java @@ -46,7 +46,7 @@ private static JsonObject createItem(Row row, String accessType, String metricTy accessCountsByPeriods.add(0L); } JsonObject o = new JsonObject() - .put("kbId", row.getUUID("kbid")) + .put("kbId", row.getUUID("kbid").toString()) .put("title", row.getString("title")); String v = row.getString("printissn"); if (v != null) { diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties index faaac39c..d687a975 100644 --- a/src/main/resources/log4j2.properties +++ b/src/main/resources/log4j2.properties @@ -1,18 +1,14 @@ -status = error -name = PropertiesConfig - -filters = threshold - -filter.threshold.type = ThresholdFilter -filter.threshold.level = info - -appenders = console - -appender.console.type = Console -appender.console.name = STDOUT -appender.console.layout.type = PatternLayout -appender.console.layout.pattern = %d{HH:mm:ss} %-5p %-20.20C{1} %m%n - -rootLogger.level = info -rootLogger.appenderRefs = info -rootLogger.appenderRef.stdout.ref = STDOUT +status=error +name=PropertiesConfig +packages=org.folio.okapi.common.logging +filters=threshold +filter.threshold.type=ThresholdFilter +filter.threshold.level=info +appenders=console +appender.console.type=Console +appender.console.name=STDOUT +appender.console.layout.type=PatternLayout +appender.console.layout.pattern=%d{HH:mm:ss} [$${FolioLoggingContext:requestId}] [$${FolioLoggingContext:tenantId}] [$${FolioLoggingContext:userId}] [$${FolioLoggingContext:moduleId}] %-5p %-20.20C{1} %m%n +rootLogger.level=info +rootLogger.appenderRefs=info +rootLogger.appenderRef.stdout.ref=STDOUT diff --git a/src/main/resources/openapi/eusage-reports-1.0.yaml b/src/main/resources/openapi/eusage-reports-1.0.yaml index a3ebb5f6..e21a264c 100644 --- a/src/main/resources/openapi/eusage-reports-1.0.yaml +++ b/src/main/resources/openapi/eusage-reports-1.0.yaml @@ -1,17 +1,17 @@ -openapi: 3.0.0 +openapi: 3.1.0 info: title: EUsage Reports version: v1 paths: /eusage-reports/report-titles: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml - - $ref: parameters/facets.yaml - - $ref: parameters/limit.yaml - - $ref: parameters/query.yaml - - $ref: parameters/offset.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" + - $ref: "#/components/parameters/facets" + - $ref: "#/components/parameters/limit" + - $ref: "#/components/parameters/query" + - $ref: "#/components/parameters/offset" - in: query name: counterReportId required: false @@ -37,7 +37,7 @@ paths: content: application/json: schema: - $ref: schemas/reportTitles.json + $ref: "#/components/schemas/reportTitles" "400": $ref: "#/components/responses/trait_400" "500": @@ -49,7 +49,7 @@ paths: content: application/json: schema: - $ref: schemas/reportTitles.json + $ref: "#/components/schemas/reportTitles" responses: "204": description: OK @@ -59,12 +59,12 @@ paths: $ref: "#/components/responses/trait_500" /eusage-reports/report-packages: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml - - $ref: parameters/offset.yaml - - $ref: parameters/limit.yaml - - $ref: parameters/query.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" + - $ref: "#/components/parameters/offset" + - $ref: "#/components/parameters/limit" + - $ref: "#/components/parameters/query" get: description: Get KB title - package relationship. operationId: getReportPackages @@ -74,16 +74,17 @@ paths: content: application/json: schema: - $ref: schemas/reportPackages.json + $ref: "#/components/schemas/reportPackages" "400": $ref: "#/components/responses/trait_400" "500": $ref: "#/components/responses/trait_500" + /eusage-reports/report-titles/from-counter: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" post: description: Parse counter reports operationId: postFromCounter @@ -91,14 +92,14 @@ paths: content: application/json: schema: - $ref: schemas/fromCounterRequest.json + $ref: "#/components/schemas/fromCounterRequest" responses: "200": description: OK content: application/json: schema: - $ref: schemas/fromCounterResponse.json + $ref: "#/components/schemas/fromCounterResponse" "400": $ref: "#/components/responses/trait_400" "404": @@ -107,12 +108,12 @@ paths: $ref: "#/components/responses/trait_500" /eusage-reports/title-data: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml - - $ref: parameters/offset.yaml - - $ref: parameters/limit.yaml - - $ref: parameters/query.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" + - $ref: "#/components/parameters/offset" + - $ref: "#/components/parameters/limit" + - $ref: "#/components/parameters/query" get: description: Get counter report title data. operationId: getTitleData @@ -122,19 +123,19 @@ paths: content: application/json: schema: - $ref: schemas/titleDataEntries.json + $ref: "#/components/schemas/titleDataEntries" "400": $ref: "#/components/responses/trait_400" "500": $ref: "#/components/responses/trait_500" /eusage-reports/report-data: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml - - $ref: parameters/offset.yaml - - $ref: parameters/limit.yaml - - $ref: parameters/query.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" + - $ref: "#/components/parameters/offset" + - $ref: "#/components/parameters/limit" + - $ref: "#/components/parameters/query" get: description: This returns data for parsed agreements. operationId: getReportData @@ -144,16 +145,16 @@ paths: content: application/json: schema: - $ref: schemas/reportDataEntries.json + $ref: "#/components/schemas/reportDataEntries" "400": $ref: "#/components/responses/trait_400" "500": $ref: "#/components/responses/trait_500" /eusage-reports/report-data/from-agreement: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" post: description: Parse agreements and populate report data operationId: postFromAgreement @@ -161,14 +162,14 @@ paths: content: application/json: schema: - $ref: schemas/fromAgreementRequest.json + $ref: "#/components/schemas/fromAgreementRequest" responses: "200": description: OK content: application/json: schema: - $ref: schemas/fromAgreementResponse.json + $ref: "#/components/schemas/fromAgreementResponse" "400": $ref: "#/components/responses/trait_400" "404": @@ -177,17 +178,17 @@ paths: $ref: "#/components/responses/trait_500" /eusage-reports/stored-reports/use-over-time: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml - - $ref: parameters/access-count-period.yaml - - $ref: parameters/agreement-id.yaml - - $ref: parameters/csv.yaml - - $ref: parameters/start-date.yaml - - $ref: parameters/end-date.yaml - - $ref: parameters/format.yaml - - $ref: parameters/include-oa.yaml - - $ref: parameters/full.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" + - $ref: "#/components/parameters/accessCountPeriod" + - $ref: "#/components/parameters/agreementId" + - $ref: "#/components/parameters/csv" + - $ref: "#/components/parameters/startDate" + - $ref: "#/components/parameters/endDate" + - $ref: "#/components/parameters/format" + - $ref: "#/components/parameters/includeOA" + - $ref: "#/components/parameters/full" get: description: Return usage data over time, where usageDateRange falls within startDate, endDate operationId: getUseOverTime @@ -197,9 +198,7 @@ paths: content: application/json: schema: - $ref: schemas/report.json - example: - $ref: examples/report.json + $ref: "#/components/schemas/report" "400": $ref: "#/components/responses/trait_400" "404": @@ -208,18 +207,18 @@ paths: $ref: "#/components/responses/trait_500" /eusage-reports/stored-reports/reqs-by-date-of-use: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml - - $ref: parameters/access-count-period.yaml - - $ref: parameters/agreement-id.yaml - - $ref: parameters/csv.yaml - - $ref: parameters/start-date.yaml - - $ref: parameters/end-date.yaml - - $ref: parameters/format.yaml - - $ref: parameters/include-oa.yaml - - $ref: parameters/yop-interval.yaml - - $ref: parameters/full.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" + - $ref: "#/components/parameters/accessCountPeriod" + - $ref: "#/components/parameters/agreementId" + - $ref: "#/components/parameters/csv" + - $ref: "#/components/parameters/startDate" + - $ref: "#/components/parameters/endDate" + - $ref: "#/components/parameters/format" + - $ref: "#/components/parameters/includeOA" + - $ref: "#/components/parameters/full" + - $ref: "#/components/parameters/yopInterval" get: description: Return requests by date of use; this is like use over time but additionally groups by publication year. operationId: getReqsByDateOfUse @@ -229,7 +228,7 @@ paths: content: application/json: schema: - $ref: schemas/report.json + $ref: "#/components/schemas/report" "400": $ref: "#/components/responses/trait_400" "404": @@ -238,18 +237,18 @@ paths: $ref: "#/components/responses/trait_500" /eusage-reports/stored-reports/reqs-by-pub-year: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml - - $ref: parameters/access-count-period.yaml - - $ref: parameters/agreement-id.yaml - - $ref: parameters/csv.yaml - - $ref: parameters/start-date.yaml - - $ref: parameters/end-date.yaml - - $ref: parameters/format.yaml - - $ref: parameters/include-oa.yaml - - $ref: parameters/period-of-use.yaml - - $ref: parameters/full.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" + - $ref: "#/components/parameters/accessCountPeriod" + - $ref: "#/components/parameters/agreementId" + - $ref: "#/components/parameters/csv" + - $ref: "#/components/parameters/startDate" + - $ref: "#/components/parameters/endDate" + - $ref: "#/components/parameters/format" + - $ref: "#/components/parameters/includeOA" + - $ref: "#/components/parameters/periodOfUse" + - $ref: "#/components/parameters/full" get: description: Return requests by publication year where usageDateRange falls within startDate, endDate. Grouping controlled by periodOfUse. @@ -262,7 +261,7 @@ paths: content: application/json: schema: - $ref: schemas/report.json + $ref: "#/components/schemas/report" "400": $ref: "#/components/responses/trait_400" "404": @@ -271,17 +270,17 @@ paths: $ref: "#/components/responses/trait_500" /eusage-reports/stored-reports/cost-per-use: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml - - $ref: parameters/access-count-period.yaml - - $ref: parameters/agreement-id.yaml - - $ref: parameters/csv.yaml - - $ref: parameters/start-date.yaml - - $ref: parameters/end-date.yaml - - $ref: parameters/format.yaml - - $ref: parameters/include-oa.yaml - - $ref: parameters/full.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" + - $ref: "#/components/parameters/accessCountPeriod" + - $ref: "#/components/parameters/agreementId" + - $ref: "#/components/parameters/csv" + - $ref: "#/components/parameters/startDate" + - $ref: "#/components/parameters/endDate" + - $ref: "#/components/parameters/format" + - $ref: "#/components/parameters/includeOA" + - $ref: "#/components/parameters/full" get: description: Return cost per where usageDateRange falls within startDate, endDate. The report is structured in periods, typically months, and the cost-per-use in a period is @@ -301,7 +300,7 @@ paths: content: application/json: schema: - $ref: schemas/reportCost.json + $ref: "#/components/schemas/reportCost" "400": $ref: "#/components/responses/trait_400" "404": @@ -310,9 +309,9 @@ paths: $ref: "#/components/responses/trait_500" /eusage-reports/report-data/status/{id}: parameters: - - $ref: headers/okapi-tenant.yaml - - $ref: headers/okapi-token.yaml - - $ref: headers/okapi-url.yaml + - $ref: "#/components/parameters/okapi_tenant" + - $ref: "#/components/parameters/okapi_token" + - $ref: "#/components/parameters/okapi_url" - in: path name: id required: true @@ -329,7 +328,7 @@ paths: content: application/json: schema: - $ref: schemas/reportStatus.json + $ref: "#/components/schemas/reportStatus" "400": $ref: "#/components/responses/trait_400" "404": @@ -337,6 +336,147 @@ paths: "500": $ref: "#/components/responses/trait_500" components: + parameters: + okapi_tenant: + in: header + name: X-Okapi-Tenant + description: Okapi Tenant + required: false + schema: + type: string + okapi_token: + in: header + name: X-Okapi-Token + description: Okapi Token + required: false + schema: + type: string + okapi_url: + in: header + name: X-Okapi-Url + description: Okapi URL + required: false + schema: + type: string + offset: + in: query + name: offset + description: Skip over number of elements (default is first element) + required: false + schema: + type: integer + default: 0 + minimum: 0 + limit: + in: query + name: limit + description: Limit the number of elements returned in the response + required: false + schema: + type: integer + default: 10 + minimum: 0 + query: + in: query + name: query + description: CQL query + required: false + schema: + type: string + facets: + in: query + name: facets + description: facet names. Each facet is separated by comma. + required: false + schema: + type: string + accessCountPeriod: + in: query + name: accessCountPeriod + description: Group access according to this parameter. May be given in a number of months (nM) or + in years (nY). The value "auto" makes it group as 1Y if startDate is given as YYYY; otherwise 1M. + required: false + schema: + type: string + default: auto + pattern: ^(\d+[YM])|(auto)$ + agreementId: + in: query + name: agreementId + description: Agreement identifier + required: true + schema: + type: string + format: uuid + csv: + in: query + name: csv + description: whether to return CSV response with details. + required: false + schema: + type: boolean + default: false + startDate: + in: query + name: startDate + description: first year for year reporting, or first month for month reporting + required: true + schema: + type: string + pattern: ^[12]\d\d\d(-0[1-9]|-1[012])?$ + description: A year in range 1000-2999, or a year in range 1000-2999 and a minus and a month in range 01-12 (similar to RFC3339, section 5.6). + example: 2019-04 + endDate: + in: query + name: endDate + description: last year for year reporting, or last month for month reporting + required: true + schema: + type: string + pattern: ^[12]\d\d\d(-0[1-9]|-1[012])?$ + description: A year in range 1000-2999, or a year in range 1000-2999 and a minus and a month in range 01-12 (similar to RFC3339, section 5.6). + example: 2019-06 + format: + in: query + name: format + description: item format type + schema: + type: string + pattern: ^(BOOK|JOURNAL|ALL)$ + full: + in: query + name: full + description: whether to return full response or brief (summary) response + required: false + schema: + type: boolean + default: true + includeOA: + in: query + name: includeOA + description: whether to include Open Access material + required: false + schema: + type: boolean + default: false + periodOfUse: + in: query + name: periodOfUse + description: a number of months or years for grouping + required: true + schema: + type: string + pattern: ^\d+[YM]$ + yopInterval: + in: query + name: yopInterval + description: a number of months or years for grouping publication dates + required: false + schema: + type: string + default: auto + pattern: ^(\d+[YM])|(auto)$ + responses: trait_400: description: Bad request @@ -344,31 +484,603 @@ components: text/plain: schema: type: string - example: Invalid JSON in request + example: + $ref: "#/components/examples/invalidJsonText" application/json: schema: type: object - example: {"error":"Invalid JSON in request"} + example: + $ref: "#/components/examples/invalidJsonJson" trait_404: description: Not Found content: text/plain: schema: type: string - example: Identifier 596d9f60-cda3-44d2-a4a1-2f48b7d4d23c not found + example: + $ref: "#/components/examples/notFoundText" + application/json: schema: type: object - example: {"error":"Identifier 596d9f60-cda3-44d2-a4a1-2f48b7d4d23c not found"} + example: + $ref: "#/components/examples/notFoundJson" trait_500: description: Internal error content: text/plain: schema: type: string - example: Internal server error, contact administrator + example: + $ref: "#/components/examples/internalServerError" + examples: + notFoundText: + value: Identifier 596d9f60-cda3-44d2-a4a1-2f48b7d4d23c not found + notFoundJson: + value: + - error: Identifier 596d9f60-cda3-44d2-a4a1-2f48b7d4d23c not found + internalServerError: + value: Internal server error, contact administrator + invalidJsonText: + value: Invalid JSON in request + invalidJsonJson: + value: + - error: Invalid JSON in request schemas: - errors: - $ref: schemas/errors.json + reportTitles: + description: "report titles (for both request and response)" + type: object + properties: + titles: + description: "List of titles" + type: array + items: + $ref: "#/components/schemas/reportTitle" + resultInfo: + $ref: "#/components/schemas/resultInfo" + additionalProperties: false + required: + - titles + reportTitle: + description: report title entry + type: object + properties: + id: + type: string + description: "title identifier (UUID)" + counterReportTitle: + type: string + description: "Title as it appears in counter report" + kbTitleName: + type: string + description: "KB title name" + kbTitleId: + type: string + description: "KB title identifier. If not given, title is ignored (kbManualMatch=true) or unmatched (kbManualMatch=false)" + format: uuid + kbManualMatch: + type: boolean + description: "whether the counter title to kb title is manually set or ignored" + printISSN: + type: string + description: ISSN for print instance + onlineISSN: + type: string + description: "ISSN for online instance" + ISBN: + type: string + description: "ISBN-13 with hyphens" + DOI: + type: string + description: "Digital Object identifier" + publicationType: + type: string + description: "publication type from ERM ('serial', 'monograph')" + required: + - id + resultInfo: + description: "Common result set information for streaming response" + type: object + properties: + totalRecords: + description: "Total number of entries in response" + type: integer + diagnostics: + description: "Diagnostics for response" + type: array + items: + type: object + properties: + message: + description: "single diagnostic message" + type: string + facets: + type: array + description: "Array of facets" + items: + type: object + description: "A facet" + properties: + facetValues: + type: array + description: "Array of facet values" + items: + type: object + description: "A facet value" + properties: + count: + type: integer + description: "Count of facet values" + value: + description: "Value Object" + type: + type: string + description: "Type of facet" + additionalProperties: false + reportPackages: + description: "get KB packages" + type: object + properties: + packages: + description: "List of packages" + type: array + items: + $ref: "#/components/schemas/reportPackage" + resultInfo: + $ref: "#/components/schemas/resultInfo" + additionalProperties: false + required: + - packages + reportPackage: + description: "KB package entry" + type: object + properties: + kbPackageId: + type: string + description: "KB package identifier" + format: uuid + kbPackageName: + type: string + description: "KB package name" + kbTitleId: + type: string + description: "KB title identifier" + format: uuid + additionalProperties: false + required: + - kbPackageId + fromCounterRequest: + description: "Specify what counter to report from" + type: object + properties: + counterReportId: + description: "Counter report identifier" + type: string + format: uuid + providerId: + description: "Counter reports with given usage data provider ID" + type: string + additionalProperties: false + fromCounterResponse: + description: "Parse counter report response" + type: object + additionalProperties: false + titleDataEntries: + description: "return title data entries" + type: object + properties: + data: + description: "List of title data entries" + type: array + items: + $ref: "#/components/schemas/titleDataEntry" + resultInfo: + $ref : "#/components/schemas/resultInfo" + additionalProperties: false + required: + - data + - resultInfo + titleDataEntry: + description: "title data entry from counter reports" + type: object + properties: + id: + type: string + description: "title data identifier" + format: uuid + titleEntryId: + type: string + description: "key to title entries" + format: uuid + counterReportId: + type: string + description: "counter report identifier" + format: uuid + counterReportTitle: + type: string + description: "counter report title" + providerId: + type: string + description: "usage data provider identifier" + format: uuid + publicationDate: + type: string + description: "Publication date in ISO format YYYY-MM-DD. example 1988-05-17" + usageYearMonth: + type: string + description: "Usage data range (Postgresql daterange). example: [2021-01-01,2021-02-01)" + uniqueAccessCount: + type: integer + description: "Unique access count" + totalAccessCount: + type: integer + description: "Total access count" + openAccess: + type: boolean + description: "Whether open access" + additionalProperties: false + required: + - id + - titleEntryId + - counterReportId + - counterReportTitle + - openAccess + reportDataEntries: + description: "report data entries" + type: object + properties: + data: + description: "List of data entries" + type: array + items: + $ref: "#/components/schemas/reportDataEntry" + resultInfo: + $ref: "#/components/schemas/resultInfo" + additionalProperties: false + required: + - data + - resultInfo + reportDataEntry: + description: "report data entry (agreement line information)" + type: object + properties: + id: + type: string + description: "report data identifier" + format: uuid + kbTitleId: + type: string + description: "kb title identifier (if the agreement line is a title)" + format: uuid + kbPackageId: + type: string + description: "kb package identifier (if the agreement line is a package)" + format: uuid + type: + type: string + description: "one of journal, package, ebook" + agreementId: + type: string + description: "agreement identifier" + format: uuid + agreementLineId: + type: string + description: "agreement line identifier" + format: uuid + poLineId: + type: string + description: "po line identifier (UUID)" + format: uuid + encumberedCost: + type: "number" + description: "cost from the PO line" + invoicedCost: + type: "number" + description: "Total access count" + fiscalYearRange: + type: string + description: "kept on the fiscal year record, there should be a link from the invoice to that record" + subscriptionDateRange: + type: string + description: "subscription period - retrieved from the invoice" + coverageDateRanges: + type: string + description: "coverage dates as retrieved from the agreement" + orderType: + type: string + description: "purchase order type" + enum: + - One-Time + - Ongoing + invoiceNumber: + type: string + description: "invoice line number" + poLineNumber: + type: string + description: "human readable PO line number" + additionalProperties: false + required: + - id + - agreementLineId + fromAgreementRequest: + description: "Import from agreement request" + type: object + properties: + agreementId: + description: "Agreement Identifier" + type: string + format: uuid + additionalProperties: false + fromAgreementResponse: + description: "Import from agreement response" + type: object + properties: + reportLinesCreated: + description: "Number of report lines created" + type: integer + additionalProperties: false + report: + description: "Usage report schema" + type: object + properties: + agreementId: + type: string + description: "Agreement identifier" + format: uuid + accessCountPeriods: + description: "List of reporting periods, either a list of months or a list of years, for example [\"2020-03\", \"2020-04\", \"2020-05\"]" + type: array + items: + type: string + totalItemRequestsTotal: + type: integer + nullable: true + description: "Access count total for all periods and all items" + totalItemRequestsByPeriod: + type: array + description: "Access count per period, total for all items" + items: + type: integer + nullable: true + totalRequestsPublicationYearsByPeriod: + type: array + description: "Access count per period for each publication year, total for all items" + items: + type: object + description: "object with publication year as key and count as value" + totalRequestsPeriodsOfUseByPeriod: + type: array + description: "Access count per period for each publication period, total for all items" + items: + type: object + description: "object with publication year as key and count as value" + uniqueItemRequestsTotal: + type: integer + nullable: true + description: "Unique access count total for all periods and all items" + uniqueItemRequestsByPeriod: + type: array + description: "Unique access count per period, total for all items" + items: + type: integer + nullable: true + uniqueRequestsPublicationYearsByPeriod: + type: array + description: "Unique count per period for each publication year, total for all items" + items: + type: object + description: "object with publication year as key and count as value" + uniqueRequestsPeriodsOfUseByPeriod: + type: array + description: "Unique access count per period for each publication period, total for all items" + items: + type: object + description: "object with publication year as key and count as value" + items: + description: "List of items, with access data per item" + type: array + items: + $ref: "#/components/schemas/reportRow" + execution: + description: "Information about execution, such as various timings" + type: object + additionalProperties: false + reportRow: + description: "Single row of usage report data" + type: object + properties: + kbId: + type: string + description: "KB identifier" + title: + type: string + description: "Title of the item" + printISSN: + type: string + description: "ISSN for print instance" + onlineISSN: + type: string + description: "ISSN for online instance" + ISBN: + type: string + description: "ISBN for instance" + publicationYear: + type: string + description: "Publication year .. or range (eg 2000 for 1Y, or 2000-2001 for 2Y)" + periodOfUse: + type: string + description: "The usage period of this publication year report row, either one month like 2018-03 or one year like 2018 or a month range like 2018-03 - 2018-05 or a year range like 2018-2019" + accessType: + type: string + description: "Counter report access type like controlled or OA_Gold" + metricType: + type: string + enum: + - Total_Item_Requests + - Unique_Item_Requests + description: "Handling of multiple requests of the same client" + accessCountTotal: + type: integer + nullable: true + description: "Sum of all access counts" + accessCountsByPeriod: + type: array + description: "Access count per reporting period" + items: + type: integer + nullable: true + additionalProperties: false + + reportCost: + description: "Cost report schema" + type: object + properties: + accessCountPeriods: + description: "List of reporting periods, either a list of months or a list of years, for example [\"2020-03\", \"2020-04\", \"2020-05\"]" + type: array + items: + type: string + amountEncumberedTotal: + description: "This number is sum of all encumbered amounts in the total access period" + type: number + amountPaidTotal: + description: "This number is sum of all paid amounts in the total access period" + type: number + costByPeriod: + type: array + description: "Total cost for each period" + items: + type: number + nullable: true + items: + description: "List of items, with access data per item" + type: array + items: + $ref: "#/components/schemas/reportCostRow" + titleCountByPeriod: + type: array + description: "Title count per period, total for all items" + items: + type: integer + nullable: true + totalItemRequestsByPeriod: + type: array + description: "Total access count per period" + items: + type: integer + nullable: true + totalItemCostsPerRequestsByPeriod: + type: array + description: "Cost per period, total for all items" + items: + type: number + nullable: true + uniqueItemRequestsByPeriod: + type: array + description: "Unique access count per period" + items: + type: integer + nullable: true + uniqueItemCostsPerRequestsByPeriod: + type: array + description: "Unique access count per period, total for all items" + items: + type: number + nullable: true + execution: + description: "Information about execution, such as various timings" + type: object + additionalProperties: false + reportCostRow: + description: "Single row of cost report data" + type: object + properties: + kbId: + type: string + description: "KB identifier" + title: + type: string + description: "Title if the item" + derivedTitle: + type: boolean + description: "Indicate whether the resource is derived from an agreement line" + printISSN: + type: string + description: "ISSN for print instance" + onlineISSN: + type: string + description: "ISSN for online instance" + ISBN: + type: string + description: "ISBN for instance" + orderType: + type: string + enum: + - One-Time + - Ongoing + description: "Order type from agreement - defaults to Ongoing" + poLineIDs: + type: array + description: "PO line IDs" + items: + type: string + description: "PO line ID" + invoiceNumbers: + type: array + description: "Invoice numbers" + items: + type: string + description: "Invoice number" + fiscalDateStart: + type: string + description: "Fiscal date start, YYYY-MM-DD" + fiscalDateEnd: + type: string + description: "Fiscal date end, YYYY-MM-DD" + subscriptionDateStart: + type: string + description: "Subscription date start, YYYY-MM-DD" + subscriptionDateEnd: + type: string + description: "Subscription date end, YYYY-MM-DD" + publicationYear: + type: string + description: "Publication year .. or range (eg 2000 for 1Y, or 2000-2001 for 2Y)" + amountEncumbered: + type: number + description: "Encumbered amount for PO lines" + amountPaid: + description: "Paid amount for invoices" + type: number + totalItemRequests: + description : "total item requests" + type: integer + uniqueItemRequests: + description: "unique item requests" + type: integer + costPerTotalRequest: + type: number + description: "Cost per total request for invoices" + costPerUniqueRequest: + type: number + description: "Cost per unique request for invoices" + additionalProperties: false + reportStatus: + description: "report status" + type: object + properties: + id: + type: string + description: "report data identifier" + format: uuid + lastUpdated: + type: string + description: "date and time of last update - UTC zone" + active: + type: boolean + description: "whether being updated at the moment" + additionalProperties: false + required: + - id diff --git a/src/main/resources/openapi/headers/okapi-tenant.yaml b/src/main/resources/openapi/headers/okapi-tenant.yaml deleted file mode 100644 index 5eb8f951..00000000 --- a/src/main/resources/openapi/headers/okapi-tenant.yaml +++ /dev/null @@ -1,6 +0,0 @@ -in: header -name: X-Okapi-Tenant -description: Okapi Tenant -required: false -schema: - type: string diff --git a/src/main/resources/openapi/headers/okapi-token.yaml b/src/main/resources/openapi/headers/okapi-token.yaml deleted file mode 100644 index 6de6cb2c..00000000 --- a/src/main/resources/openapi/headers/okapi-token.yaml +++ /dev/null @@ -1,6 +0,0 @@ -in: header -name: X-Okapi-Token -description: Okapi Token -required: false -schema: - type: string diff --git a/src/main/resources/openapi/headers/okapi-url.yaml b/src/main/resources/openapi/headers/okapi-url.yaml deleted file mode 100644 index 4febf2b4..00000000 --- a/src/main/resources/openapi/headers/okapi-url.yaml +++ /dev/null @@ -1,6 +0,0 @@ -in: header -name: X-Okapi-Url -description: Okapi URL -required: false -schema: - type: string diff --git a/src/main/resources/openapi/parameters/access-count-period.yaml b/src/main/resources/openapi/parameters/access-count-period.yaml deleted file mode 100644 index 8ef4782a..00000000 --- a/src/main/resources/openapi/parameters/access-count-period.yaml +++ /dev/null @@ -1,9 +0,0 @@ -in: query -name: accessCountPeriod -description: Group access according to this parameter. May be given in a number of months (nM) or - in years (nY). The value "auto" makes it group as 1Y if startDate is given as YYYY; otherwise 1M. -required: false -schema: - type: string - default: auto - pattern: ^(\d+[YM])|(auto)$ diff --git a/src/main/resources/openapi/parameters/agreement-id.yaml b/src/main/resources/openapi/parameters/agreement-id.yaml deleted file mode 100644 index b88a787b..00000000 --- a/src/main/resources/openapi/parameters/agreement-id.yaml +++ /dev/null @@ -1,7 +0,0 @@ -in: query -name: agreementId -description: Agreement identifier -required: true -schema: - type: string - format: uuid diff --git a/src/main/resources/openapi/parameters/csv.yaml b/src/main/resources/openapi/parameters/csv.yaml deleted file mode 100644 index 318847b1..00000000 --- a/src/main/resources/openapi/parameters/csv.yaml +++ /dev/null @@ -1,7 +0,0 @@ -in: query -name: csv -description: whether to return CSV response with details. -required: false -schema: - type: boolean - default: false diff --git a/src/main/resources/openapi/parameters/end-date.yaml b/src/main/resources/openapi/parameters/end-date.yaml deleted file mode 100644 index fd79168c..00000000 --- a/src/main/resources/openapi/parameters/end-date.yaml +++ /dev/null @@ -1,9 +0,0 @@ -in: query -name: endDate -description: last year for year reporting, or last month for month reporting -required: true -schema: - type: string - pattern: ^[12]\d\d\d(-0[1-9]|-1[012])?$ - description: A year in range 1000-2999, or a year in range 1000-2999 and a minus and a month in range 01-12 (similar to RFC3339, section 5.6). - example: 2019-06 diff --git a/src/main/resources/openapi/parameters/facets.yaml b/src/main/resources/openapi/parameters/facets.yaml deleted file mode 100644 index c694b6d1..00000000 --- a/src/main/resources/openapi/parameters/facets.yaml +++ /dev/null @@ -1,6 +0,0 @@ -in: query -name: facets -description: facet names. Each facet is separted by comma. -required: false -schema: - type: string diff --git a/src/main/resources/openapi/parameters/format.yaml b/src/main/resources/openapi/parameters/format.yaml deleted file mode 100644 index 4f0c3156..00000000 --- a/src/main/resources/openapi/parameters/format.yaml +++ /dev/null @@ -1,6 +0,0 @@ -in: query -name: format -description: item format type -schema: - type: string - pattern: ^(BOOK|JOURNAL|ALL)$ diff --git a/src/main/resources/openapi/parameters/full.yaml b/src/main/resources/openapi/parameters/full.yaml deleted file mode 100644 index 04e98a47..00000000 --- a/src/main/resources/openapi/parameters/full.yaml +++ /dev/null @@ -1,7 +0,0 @@ -in: query -name: full -description: whether to return full response or brief (summary) response -required: false -schema: - type: boolean - default: true diff --git a/src/main/resources/openapi/parameters/include-oa.yaml b/src/main/resources/openapi/parameters/include-oa.yaml deleted file mode 100644 index aead5ba1..00000000 --- a/src/main/resources/openapi/parameters/include-oa.yaml +++ /dev/null @@ -1,7 +0,0 @@ -in: query -name: includeOA -description: whether to include Open Access material -required: false -schema: - type: boolean - default: false diff --git a/src/main/resources/openapi/parameters/limit.yaml b/src/main/resources/openapi/parameters/limit.yaml deleted file mode 100644 index 362dd047..00000000 --- a/src/main/resources/openapi/parameters/limit.yaml +++ /dev/null @@ -1,8 +0,0 @@ -in: query -name: limit -description: Limit the number of elements returned in the response -required: false -schema: - type: integer - default: 10 - minimum: 0 diff --git a/src/main/resources/openapi/parameters/offset.yaml b/src/main/resources/openapi/parameters/offset.yaml deleted file mode 100644 index ff9864f0..00000000 --- a/src/main/resources/openapi/parameters/offset.yaml +++ /dev/null @@ -1,8 +0,0 @@ -in: query -name: offset -description: Skip over number of elements (default is first element) -required: false -schema: - type: integer - default: 0 - minimum: 0 diff --git a/src/main/resources/openapi/parameters/period-of-use.yaml b/src/main/resources/openapi/parameters/period-of-use.yaml deleted file mode 100644 index b3259db7..00000000 --- a/src/main/resources/openapi/parameters/period-of-use.yaml +++ /dev/null @@ -1,7 +0,0 @@ -in: query -name: periodOfUse -description: a number of months or years for grouping -required: true -schema: - type: string - pattern: ^\d+[YM]$ diff --git a/src/main/resources/openapi/parameters/query.yaml b/src/main/resources/openapi/parameters/query.yaml deleted file mode 100644 index 46f14473..00000000 --- a/src/main/resources/openapi/parameters/query.yaml +++ /dev/null @@ -1,6 +0,0 @@ -in: query -name: query -description: CQL query -required: false -schema: - type: string diff --git a/src/main/resources/openapi/parameters/start-date.yaml b/src/main/resources/openapi/parameters/start-date.yaml deleted file mode 100644 index 138f8ffa..00000000 --- a/src/main/resources/openapi/parameters/start-date.yaml +++ /dev/null @@ -1,9 +0,0 @@ -in: query -name: startDate -description: first year for year reporting, or first month for month reporting -required: true -schema: - type: string - pattern: ^[12]\d\d\d(-0[1-9]|-1[012])?$ - description: A year in range 1000-2999, or a year in range 1000-2999 and a minus and a month in range 01-12 (similar to RFC3339, section 5.6). - example: 2019-04 diff --git a/src/main/resources/openapi/parameters/yop-interval.yaml b/src/main/resources/openapi/parameters/yop-interval.yaml deleted file mode 100644 index aed1197c..00000000 --- a/src/main/resources/openapi/parameters/yop-interval.yaml +++ /dev/null @@ -1,9 +0,0 @@ -in: query -name: yopInterval -description: a number of months or years for grouping publication dates -required: false - -schema: - type: string - default: auto - pattern: ^(\d+[YM])|(auto)$ diff --git a/src/main/resources/openapi/schemas/error.json b/src/main/resources/openapi/schemas/error.json deleted file mode 100644 index 97a99a9f..00000000 --- a/src/main/resources/openapi/schemas/error.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "description": "An error", - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Error message text" - }, - "type": { - "type": "string", - "description": "Error message type" - }, - "code": { - "type": "string", - "description": "Error message code" - }, - "parameters": { - "type": "object", - "description": "Error message parameters", - "$ref": "parameters.json" - } - }, - "additionalProperties": false, - "required": [ - "message" - ] -} diff --git a/src/main/resources/openapi/schemas/errors.json b/src/main/resources/openapi/schemas/errors.json deleted file mode 100644 index b358d4f0..00000000 --- a/src/main/resources/openapi/schemas/errors.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "description": "A set of errors", - "type": "object", - "properties": { - "errors": { - "description": "List of errors", - "type": "array", - "items": { - "type": "object", - "$ref": "error.json" - } - }, - "total_records": { - "description": "Total number of errors", - "type": "integer" - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/fromAgreementRequest.json b/src/main/resources/openapi/schemas/fromAgreementRequest.json deleted file mode 100644 index 64de3476..00000000 --- a/src/main/resources/openapi/schemas/fromAgreementRequest.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "description": "Import from agreement request", - "type": "object", - "properties": { - "agreementId": { - "description": "Agreement Identifier", - "type": "string", - "format": "uuid" - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/fromAgreementResponse.json b/src/main/resources/openapi/schemas/fromAgreementResponse.json deleted file mode 100644 index b67b8294..00000000 --- a/src/main/resources/openapi/schemas/fromAgreementResponse.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "description": "Import from agreement response", - "type": "object", - "properties": { - "reportLinesCreated": { - "description": "Number of report lines created", - "type": "integer" - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/fromCounterRequest.json b/src/main/resources/openapi/schemas/fromCounterRequest.json deleted file mode 100644 index 2d6b1883..00000000 --- a/src/main/resources/openapi/schemas/fromCounterRequest.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "description": "Specify what counter to report from", - "type": "object", - "properties": { - "counterReportId": { - "description": "Counter report identifier", - "type": "string", - "format": "uuid" - }, - "providerId": { - "description": "Counter reports with given usage data provider ID", - "type": "string" - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/fromCounterResponse.json b/src/main/resources/openapi/schemas/fromCounterResponse.json deleted file mode 100644 index f9d9c0d3..00000000 --- a/src/main/resources/openapi/schemas/fromCounterResponse.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "description": "Parse counter report response", - "type": "object", - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/metadata.json b/src/main/resources/openapi/schemas/metadata.json deleted file mode 100644 index e8bbaffb..00000000 --- a/src/main/resources/openapi/schemas/metadata.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "title": "Metadata Schema", - "description": "Metadata about creation and changes to records, provided by the server (client should not provide)", - "type": "object", - "properties": { - "createdDate": { - "description": "Date and time when the record was created", - "type": "string", - "format": "date-time" - }, - "createdByUserId": { - "description": "ID of the user who created the record (when available)", - "type": "string", - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "createdByUsername": { - "description": "Username of the user who created the record (when available)", - "type": "string" - }, - "updatedDate": { - "description": "Date and time when the record was last updated", - "type": "string", - "format": "date-time" - }, - "updatedByUserId": { - "description": "ID of the user who last updated the record (when available)", - "type": "string", - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - }, - "updatedByUsername": { - "description": "Username of the user who last updated the record (when available)", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "createdDate" - ] -} diff --git a/src/main/resources/openapi/schemas/parameter.json b/src/main/resources/openapi/schemas/parameter.json deleted file mode 100644 index a1a8f55c..00000000 --- a/src/main/resources/openapi/schemas/parameter.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "description": "List of key/value parameters of an error", - "type": "object", - "properties": { - "key": { - "description": "The key for this parameter", - "type": "string" - }, - "value": { - "description": "The value of this parameter", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "key" - ] -} diff --git a/src/main/resources/openapi/schemas/parameters.json b/src/main/resources/openapi/schemas/parameters.json deleted file mode 100644 index 23d8eace..00000000 --- a/src/main/resources/openapi/schemas/parameters.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "List of key/value parameters of an error", - "type": "array", - "items": { - "type": "object", - "$ref": "parameter.json" - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/report.json b/src/main/resources/openapi/schemas/report.json deleted file mode 100644 index b83b98eb..00000000 --- a/src/main/resources/openapi/schemas/report.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "description": "Usage report schema", - "type": "object", - "properties": { - "agreementId": { - "type": "string", - "description": "Agreement identifier (UUID)" - }, - "accessCountPeriods": { - "description": "List of reporting periods, either a list of months or a list of years, for example [\"2020-03\", \"2020-04\", \"2020-05\"]", - "type": "array", - "items": { - "type": "string" - } - }, - "totalItemRequestsTotal": { - "type": "integer", - "nullable": true, - "description": "Access count total for all periods and all items" - }, - "totalItemRequestsByPeriod": { - "type": "array", - "description": "Access count per period, total for all items", - "items": { - "type": "integer", - "nullable": true - } - }, - "totalRequestsPublicationYearsByPeriod": { - "type": "array", - "description": "Access count per period for each publication year, total for all items", - "items": { - "type": "object", - "description": "object with publication year as key and count as value" - } - }, - "totalRequestsPeriodsOfUseByPeriod": { - "type": "array", - "description": "Access count per period for each publication period, total for all items", - "items": { - "type": "object", - "description": "object with publication year as key and count as value" - } - }, - "uniqueItemRequestsTotal": { - "type": "integer", - "nullable": true, - "description": "Unique access count total for all periods and all items" - }, - "uniqueItemRequestsByPeriod": { - "type": "array", - "description": "Unique access count per period, total for all items", - "items": { - "type": "integer", - "nullable": true - } - }, - "uniqueRequestsPublicationYearsByPeriod": { - "type": "array", - "description": "Unique count per period for each publication year, total for all items", - "items": { - "type": "object", - "description": "object with publication year as key and count as value" - } - }, - "uniqueRequestsPeriodsOfUseByPeriod": { - "type": "array", - "description": "Unique access count per period for each publication period, total for all items", - "items": { - "type": "object", - "description": "object with publication year as key and count as value" - } - }, - "items": { - "description": "List of items, with access data per item", - "type": "array", - "items": { - "type": "object", - "$ref": "reportRow.json" - } - }, - "execution": { - "description": "Information about execution, such as various timings", - "type": "object" - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/reportCost.json b/src/main/resources/openapi/schemas/reportCost.json deleted file mode 100644 index fd3c347f..00000000 --- a/src/main/resources/openapi/schemas/reportCost.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "description": "Cost report schema", - "type": "object", - "properties": { - "accessCountPeriods": { - "description": "List of reporting periods, either a list of months or a list of years, for example [\"2020-03\", \"2020-04\", \"2020-05\"]", - "type": "array", - "items": { - "type": "string" - } - }, - "amountEncumeredTotal": { - "description": "This number is sum of all encumbered amounts in the total access period", - "type": "number" - }, - "amountPaidTotal": { - "description": "This number is sum of all paid amounts in the total access period", - "type": "number" - }, - "costByPeriod": { - "type": "array", - "description": "Total cost for each period", - "items": { - "type": "number", - "nullable": true - } - }, - "items": { - "description": "List of items, with access data per item", - "type": "array", - "items": { - "type": "object", - "$ref": "reportCostRow.json" - } - }, - "titleCountByPeriod": { - "type": "array", - "description": "Title count per period, total for all items", - "items": { - "type": "integer", - "nullable": true - } - }, - "totalItemRequestsByPeriod": { - "type": "array", - "description": "Total access count per period", - "items": { - "type": "integer", - "nullable": true - } - }, - "totalItemCostsPerRequestsByPeriod": { - "type": "array", - "description": "Cost per period, total for all items", - "items": { - "type": "number", - "nullable": true - } - }, - "uniqueItemRequestsByPeriod": { - "type": "array", - "description": "Unique access count per period", - "items": { - "type": "integer", - "nullable": true - } - }, - "uniqueItemCostsPerRequestsByPeriod": { - "type": "array", - "description": "Unique access count per period, total for all items", - "items": { - "type": "number", - "nullable": true - } - }, - "execution": { - "description": "Information about execution, such as various timings", - "type": "object" - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/reportCostRow.json b/src/main/resources/openapi/schemas/reportCostRow.json deleted file mode 100644 index 12c05521..00000000 --- a/src/main/resources/openapi/schemas/reportCostRow.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "description": "Single row of cost report data", - "type": "object", - "properties": { - "kbId": { - "type": "string", - "description": "KB identifier" - }, - "title": { - "type": "string", - "description": "Title if the item" - }, - "derivedTitle": { - "type": "boolean", - "description": "Indicate whether the resource is derived from an agreement line" - }, - "printISSN": { - "type": "string", - "description": "ISSN for print instance" - }, - "onlineISSN": { - "type": "string", - "description": "ISSN for online instance" - }, - "ISBN": { - "type": "string", - "description": "ISBN for instance" - }, - "orderType": { - "type": "string", - "enum": ["One-Time", "Ongoing"], - "description": "Order type from agreement - defaults to Ongoing" - }, - "poLineIDs" : { - "type": "array", - "description" : "PO line IDs", - "items" : { - "type": "string", - "description" : "PO line ID" - } - }, - "invoiceNumbers" : { - "type": "array", - "description": "Invoice numbers", - "items" : { - "type": "string", - "description" : "Invoice number" - } - }, - "fiscalDateStart" : { - "type": "string", - "description" : "Fiscal date start, YYYY-MM-DD" - }, - "fiscalDateEnd" : { - "type": "string", - "description" : "Fiscal date end, YYYY-MM-DD" - }, - "subscriptionDateStart" : { - "type": "string", - "description" : "Subscription date start, YYYY-MM-DD" - }, - "subscriptionDateEnd" : { - "type": "string", - "description" : "Subscription date end, YYYY-MM-DD" - }, - "publicationYear": { - "type": "string", - "description": "Publication year .. or range (eg 2000 for 1Y, or 2000-2001 for 2Y)" - }, - "amountEncumbered" : { - "type": "number", - "description" : "Encumbered amount for PO lines" - }, - "amountPaid" : { - "description" : "Paid amount for invoices", - "type": "number" - }, - "totalItemRequests" : { - "description" : "total item requests", - "type": "integer" - }, - "uniqueItemRequests" : { - "description" : "unique item requests", - "type": "integer" - }, - "costPerTotalRequest" : { - "type": "number", - "description" : "Cost per total request for invoices" - }, - "costPerUniqueRequest" : { - "type": "number", - "description" : "Cost per unique request for invoices" - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/reportDataEntries.json b/src/main/resources/openapi/schemas/reportDataEntries.json deleted file mode 100644 index 6bb1eaec..00000000 --- a/src/main/resources/openapi/schemas/reportDataEntries.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "description": "report data entries", - "type": "object", - "properties": { - "data": { - "description": "List of data entries", - "type": "array", - "items": { - "type": "object", - "$ref": "reportDataEntry.json" - } - }, - "resultInfo": { - "description": "Common result set information", - "type": "object", - "$ref" : "resultInfo.json" - } - }, - "additionalProperties": false, - "required": [ - "data", "resultInfo" - ] -} diff --git a/src/main/resources/openapi/schemas/reportDataEntry.json b/src/main/resources/openapi/schemas/reportDataEntry.json deleted file mode 100644 index a2280a85..00000000 --- a/src/main/resources/openapi/schemas/reportDataEntry.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "description": "report data entry (agreement line information)", - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "report data identifier", - "format": "uuid" - }, - "kbTitleId": { - "type": "string", - "description": "kb title identifier (if the agreement line is a title)", - "format": "uuid" - }, - "kbPackageId": { - "type": "string", - "description": "kb package identifier (if the agreement line is a package)", - "format": "uuid" - }, - "type": { - "type": "string", - "description": "one of journal, package, ebook" - }, - "agreementId": { - "type": "string", - "description": "agreement identifier", - "format": "uuid" - }, - "agreementLineId": { - "type": "string", - "description": "agreement line identifier", - "format": "uuid" - }, - "poLineId": { - "type": "string", - "description": "po line identifier (UUID)", - "format": "uuid" - }, - "encumberedCost": { - "type": "number", - "description": "cost from the PO line" - }, - "invoicedCost": { - "type": "number", - "description": "Total access count" - }, - "fiscalYearRange": { - "type": "string", - "description": "kept on the fiscal year record, there should be a link from the invoice to that record" - }, - "subscriptionDateRange": { - "type": "string", - "description": "subscription period - retrieved from the invoice" - }, - "coverageDateRanges": { - "type": "string", - "description": "coverage dates as retrieved from the agreement" - }, - "orderType": { - "type": "string", - "description": "purchase order type", - "enum": [ "One-Time", "Ongoing"] - }, - "invoiceNumber": { - "type": "string", - "description": "invoice line number" - }, - "poLineNumber": { - "type": "string", - "description": "human readable PO line number" - } - }, - "additionalProperties": false, - "required": [ - "id", "agreementLineId" - ] -} diff --git a/src/main/resources/openapi/schemas/reportPackage.json b/src/main/resources/openapi/schemas/reportPackage.json deleted file mode 100644 index e0dd7e48..00000000 --- a/src/main/resources/openapi/schemas/reportPackage.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "description": "KB package entry", - "type": "object", - "properties": { - "kbPackageId": { - "type": "string", - "description" : "KB package identifier", - "format": "uuid" - }, - "kbPackageName": { - "type": "string", - "description": "KB package name" - }, - "kbTitleId": { - "type": "string", - "description": "KB title identifier", - "format": "uuid" - } - }, - "additionalProperties": false, - "required": [ - "kbPackageId" - ] -} diff --git a/src/main/resources/openapi/schemas/reportPackages.json b/src/main/resources/openapi/schemas/reportPackages.json deleted file mode 100644 index 9c3de407..00000000 --- a/src/main/resources/openapi/schemas/reportPackages.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "description": "get KB packages", - "type": "object", - "properties": { - "packages": { - "description": "List of packages", - "type": "array", - "items": { - "type": "object", - "$ref": "reportPackage.json" - } - }, - "resultInfo": { - "description": "Common result set information", - "type": "object", - "$ref" : "resultInfo.json" - } - }, - "additionalProperties": false, - "required": [ - "packages" - ] -} diff --git a/src/main/resources/openapi/schemas/reportRow.json b/src/main/resources/openapi/schemas/reportRow.json deleted file mode 100644 index ce1b314e..00000000 --- a/src/main/resources/openapi/schemas/reportRow.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "description": "Single row of usage report data", - "type": "object", - "properties": { - "kbId": { - "type": "string", - "description": "KB identifier" - }, - "title": { - "type": "string", - "description": "Title of the item" - }, - "printISSN": { - "type": "string", - "description": "ISSN for print instance" - }, - "onlineISSN": { - "type": "string", - "description": "ISSN for online instance" - }, - "ISBN": { - "type": "string", - "description": "ISBN for instance" - }, - "publicationYear": { - "type": "string", - "description": "Publication year .. or range (eg 2000 for 1Y, or 2000-2001 for 2Y)" - }, - "periodOfUse": { - "type": "string", - "description": "The usage period of this publication year report row, either one month like 2018-03 or one year like 2018 or a month range like 2018-03 - 2018-05 or a year range like 2018-2019" - }, - "accessType": { - "type": "string", - "description": "Counter report access type like controlled or OA_Gold" - }, - "metricType": { - "type": "string", - "enum": ["Total_Item_Requests", "Unique_Item_Requests"], - "description": "Handling of multiple requests of the same client" - }, - "accessCountTotal": { - "type": "integer", - "nullable": true, - "description": "Sum of all access counts" - }, - "accessCountsByPeriod": { - "type": "array", - "description": "Access count per reporting period", - "items": { - "type": "integer", - "nullable": true - } - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/reportStatus.json b/src/main/resources/openapi/schemas/reportStatus.json deleted file mode 100644 index 83e7d964..00000000 --- a/src/main/resources/openapi/schemas/reportStatus.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "description": "report status", - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "report data identifier", - "format": "uuid" - }, - "lastUpdated": { - "type": "string", - "description": "date and time of last update - UTC zone" - }, - "active": { - "type": "boolean", - "description": "whether being updated at the moment" - } - }, - "additionalProperties": false, - "required": [ - "id" - ] -} diff --git a/src/main/resources/openapi/schemas/reportTitle.json b/src/main/resources/openapi/schemas/reportTitle.json deleted file mode 100644 index 4ad8dcd4..00000000 --- a/src/main/resources/openapi/schemas/reportTitle.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "description": "report title entry", - "type": "object", - "properties": { - "id": { - "type": "string", - "description" : "title identifier", - "format": "uuid" - }, - "counterReportTitle": { - "type": "string", - "description": "Title as it appears in counter report" - }, - "kbTitleName": { - "type": "string", - "description": "KB title name" - }, - "kbTitleId": { - "type": "string", - "description": "KB title identifier. If not given, title is ignored (kbManualMatch=true) or unmatched (kbManualMatch=false)", - "format": "uuid" - }, - "kbManualMatch": { - "type": "boolean", - "description": "whether the counter title to kb title is manually set or ignored" - }, - "printISSN": { - "type": "string", - "description": "ISSN for print instance" - }, - "onlineISSN": { - "type": "string", - "description": "ISSN for online instance" - }, - "ISBN": { - "type": "string", - "description": "ISBN-13 with hyphens" - }, - "DOI": { - "type": "string", - "description": "Digital Object identifier" - }, - "publicationType": { - "type": "string", - "description": "publication type from ERM ('serial', 'monograph')" - } - }, - "additionalProperties": false, - "required": [ - "id" - ] -} diff --git a/src/main/resources/openapi/schemas/reportTitles.json b/src/main/resources/openapi/schemas/reportTitles.json deleted file mode 100644 index 5ab1f39f..00000000 --- a/src/main/resources/openapi/schemas/reportTitles.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "description": "report titles (for both request and response)", - "type": "object", - "properties": { - "titles": { - "description": "List of titles", - "type": "array", - "items": { - "type": "object", - "$ref": "reportTitle.json" - } - }, - "resultInfo": { - "description": "Common result set information", - "type": "object", - "$ref" : "resultInfo.json" - } - }, - "additionalProperties": false, - "required": [ - "titles" - ] -} diff --git a/src/main/resources/openapi/schemas/resultInfo.json b/src/main/resources/openapi/schemas/resultInfo.json deleted file mode 100644 index 93081b4f..00000000 --- a/src/main/resources/openapi/schemas/resultInfo.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "description": "Common result set information for streaming response", - "type": "object", - "properties": { - "totalRecords": { - "description": "Total number of entries in response", - "type": "integer" - }, - "diagnostics": { - "description": "Diagnostics for response", - "type": "array", - "items": { - "type": "object", - "properties": { - "message": { - "description": "single diagnostic message", - "type": "string" - } - } - } - }, - "facets": { - "type": "array", - "description": "Array of facets", - "items": { - "type": "object", - "description": "A facet", - "properties": { - "facetValues": { - "type": "array", - "description": "Array of facet values", - "items": { - "type": "object", - "description": "A facet value", - "properties": { - "count": { - "type": "integer", - "description": "Count of facet values" - }, - "value": { - "description": "Value Object" - } - } - } - }, - "type": { - "type": "string", - "description": "Type of facet" - } - } - } - } - }, - "additionalProperties": false -} diff --git a/src/main/resources/openapi/schemas/titleDataEntries.json b/src/main/resources/openapi/schemas/titleDataEntries.json deleted file mode 100644 index 8adf76f7..00000000 --- a/src/main/resources/openapi/schemas/titleDataEntries.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "description": "return title data entries", - "type": "object", - "properties": { - "data": { - "description": "List of title data entries", - "type": "array", - "items": { - "type": "object", - "$ref": "titleDataEntry.json" - } - }, - "resultInfo": { - "description": "Common result set information", - "type": "object", - "$ref" : "resultInfo.json" - } - }, - "additionalProperties": false, - "required": [ - "data", "resultInfo" - ] -} diff --git a/src/main/resources/openapi/schemas/titleDataEntry.json b/src/main/resources/openapi/schemas/titleDataEntry.json deleted file mode 100644 index 33fc1894..00000000 --- a/src/main/resources/openapi/schemas/titleDataEntry.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "description": "title data entry from counter reports", - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "title data identifier", - "format": "uuid" - }, - "titleEntryId": { - "type": "string", - "description": "key to title entries", - "format": "uuid" - }, - "counterReportId": { - "type": "string", - "description": "counter report identifier", - "format": "uuid" - }, - "counterReportTitle": { - "type": "string", - "description": "counter report title" - }, - "providerId": { - "type": "string", - "description": "usage data provider identifier", - "format": "uuid" - }, - "publicationDate": { - "type": "string", - "description": "Publication date in ISO format YYYY-MM-DD. example 1988-05-17" - }, - "usageYearMonth": { - "type": "string", - "description": "Usage data range (Postgresql daterange). example: [2021-01-01,2021-02-01)" - }, - "uniqueAccessCount": { - "type": "integer", - "description": "Unique access count" - }, - "totalAccessCount": { - "type": "integer", - "description": "Total access count" - }, - "openAccess": { - "type": "boolean", - "description": "Whether open access" - } - }, - "additionalProperties": false, - "required": [ - "id", "titleEntryId", "counterReportId", "counterReportTitle", "openAccess" - ] -} diff --git a/src/test/java/org/folio/eusage/reports/BasicDbTest.java b/src/test/java/org/folio/eusage/reports/BasicDbTest.java index 1fbe8647..f79841ae 100644 --- a/src/test/java/org/folio/eusage/reports/BasicDbTest.java +++ b/src/test/java/org/folio/eusage/reports/BasicDbTest.java @@ -1,13 +1,13 @@ package org.folio.eusage.reports; import io.vertx.core.Future; -import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import io.vertx.ext.unit.TestContext; import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.pgclient.PgBuilder; import io.vertx.pgclient.PgConnectOptions; -import io.vertx.pgclient.PgPool; import io.vertx.sqlclient.PoolOptions; +import io.vertx.sqlclient.SqlClient; import io.vertx.sqlclient.Tuple; import java.util.UUID; @@ -22,12 +22,10 @@ public class BasicDbTest { private static PostgreSQLContainer postgresSQLContainer; - private static PgPool pgPool; - private static Vertx vertx; + private static SqlClient pgClient; @BeforeClass public static void setUpBeforeClass(TestContext context) { - vertx = Vertx.vertx(); postgresSQLContainer = TenantPgPoolContainer.create(); PgConnectOptions pgConnectOptions = new PgConnectOptions(); pgConnectOptions.setHost(postgresSQLContainer.getHost()); @@ -36,7 +34,11 @@ public static void setUpBeforeClass(TestContext context) { pgConnectOptions.setPassword(postgresSQLContainer.getPassword()); pgConnectOptions.setDatabase(postgresSQLContainer.getDatabaseName()); PoolOptions poolOptions = new PoolOptions().setMaxSize(5); - pgPool = PgPool.pool(vertx, pgConnectOptions, poolOptions); + pgClient = PgBuilder + .client() + .with(poolOptions) + .connectingTo(pgConnectOptions) + .build(); } @AfterClass @@ -50,27 +52,27 @@ public void createTable(TestContext context) { Future future = Future.succeededFuture(); future = future.compose(res -> - pgPool.query("CREATE TABLE IF NOT EXISTS foo ( id UUID PRIMARY KEY, jsonb JSONB NOT NULL)") + pgClient.query("CREATE TABLE IF NOT EXISTS foo ( id UUID PRIMARY KEY, jsonb JSONB NOT NULL)") .execute().mapEmpty()); future = future.compose(res -> - pgPool.preparedQuery("SELECT * FROM foo WHERE id = $1") + pgClient.preparedQuery("SELECT * FROM foo WHERE id = $1") .execute(Tuple.of(id)) .compose(res1 -> { context.assertEquals(0, res1.rowCount()); return Future.succeededFuture(); })); future = future.compose(res -> - pgPool.preparedQuery("INSERT INTO foo (id, jsonb) VALUES ($1, $2)") + pgClient.preparedQuery("INSERT INTO foo (id, jsonb) VALUES ($1, $2)") .execute(Tuple.of(id, new JsonObject().put("a", "b"))).mapEmpty()); future = future.compose(res -> - pgPool.preparedQuery("SELECT * FROM foo WHERE id = $1") + pgClient.preparedQuery("SELECT * FROM foo WHERE id = $1") .execute(Tuple.of(id)) .compose(res1 -> { context.assertEquals(1, res1.rowCount()); return Future.succeededFuture(); })); future = future.compose(res -> - pgPool.query("DROP TABLE foo") + pgClient.query("DROP TABLE foo") .execute().mapEmpty()); future.onComplete(context.asyncAssertSuccess()); } diff --git a/src/test/java/org/folio/eusage/reports/MainVerticleTest.java b/src/test/java/org/folio/eusage/reports/MainVerticleTest.java index 4ce381dd..e4763f86 100644 --- a/src/test/java/org/folio/eusage/reports/MainVerticleTest.java +++ b/src/test/java/org/folio/eusage/reports/MainVerticleTest.java @@ -30,6 +30,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.startsWith; @RunWith(VertxUnitRunner.class) public class MainVerticleTest { @@ -86,8 +87,8 @@ public class MainVerticleTest { static JsonObject getCounterReportMock(UUID id, int cnt) { JsonObject counterReport = new JsonObject(); - counterReport.put("id", id); - counterReport.put("providerId", usageProviderId); + counterReport.put("id", id.toString()); + counterReport.put("providerId", usageProviderId.toString()); counterReport.put("yearMonth", "2021-01"); JsonObject report = new JsonObject(); counterReport.put("report", report); @@ -290,7 +291,7 @@ static JsonObject getKbTitle(UUID kbTitleId) { JsonObject res = new JsonObject(); if (goodKbTitleId.equals(kbTitleId)) { res.put("name", "good kb title instance name"); - res.put("id", kbTitleId); + res.put("id", kbTitleId.toString()); res.put("publicationType", new JsonObject().put("value", "monograph")); res.put("identifiers", new JsonArray() .add(new JsonObject() @@ -300,7 +301,7 @@ static JsonObject getKbTitle(UUID kbTitleId) { )); } else if (otherKbTitleId.equals(kbTitleId)) { res.put("name", "other kb title instance name"); - res.put("id", kbTitleId); + res.put("id", kbTitleId.toString()); res.put("identifiers", new JsonArray() .add(new JsonObject() .put("identifier", new JsonObject() @@ -310,7 +311,7 @@ static JsonObject getKbTitle(UUID kbTitleId) { } else { res.put("name", "fake kb title instance name"); res.put("publicationType", new JsonObject().put("value", "serial")); - res.put("id", kbTitleId); + res.put("id", kbTitleId.toString()); res.put("identifiers", new JsonArray() .add(new JsonObject() .put("identifier", new JsonObject() @@ -414,20 +415,20 @@ static void getEntitlements(RoutingContext ctx) { JsonArray poLinesAr = new JsonArray(); for (int j = 0; j < i && j < poLineIds.length; j++) { poLinesAr.add(new JsonObject() - .put("poLineId", poLineIds[j]) + .put("poLineId", poLineIds[j].toString()) ); } if (i == 1) { // fake package ar.add(new JsonObject() - .put("id", agreementLineIds[i]) + .put("id", agreementLineIds[i].toString()) .put("owner", new JsonObject() - .put("id", goodAgreementId) + .put("id", goodAgreementId.toString()) .put("name", "Good agreement")) .put("resource", new JsonObject() .put("class", "org.olf.kb.Pkg") .put("name", "good package name") - .put("id", goodPackageId) + .put("id", goodPackageId.toString()) .put("_object", new JsonObject() )) .put("poLines", poLinesAr) @@ -454,18 +455,18 @@ static void getEntitlements(RoutingContext ctx) { kbtitleId = UUID.randomUUID(); } ar.add(new JsonObject() - .put("id", agreementLineIds[i]) + .put("id", agreementLineIds[i].toString()) .put("owner", new JsonObject() - .put("id", goodAgreementId) + .put("id", goodAgreementId.toString()) .put("name", "Good agreement")) .put("resource", new JsonObject() .put("class", "org.olf.kb.PackageContentItem") - .put("id", UUID.randomUUID()) + .put("id", UUID.randomUUID().toString()) .put("coverage", coverage) .put("_object", new JsonObject() .put("pti", new JsonObject() .put("titleInstance", new JsonObject() - .put("id", kbtitleId) + .put("id", kbtitleId.toString()) .put("publicationType", new JsonObject() .put("value", "serial") ) @@ -494,7 +495,7 @@ static void getOrderLines(RoutingContext ctx) { ctx.response().setChunked(true); ctx.response().putHeader("Content-Type", "application/json"); JsonObject orderLine = new JsonObject(); - orderLine.put("id", id); + orderLine.put("id", id.toString()); orderLine.put("poLineNumber", POLINE_NUMBER_SAMPLE); String currency = i < orderLinesCurrencies.size() ? orderLinesCurrencies.get(i) : "USD"; orderLine.put("cost", new JsonObject() @@ -542,8 +543,8 @@ static void getInvoiceLines(RoutingContext ctx) { if (poLineId.equals(poLineIds[i])) { { JsonObject invoiceLine = new JsonObject() - .put("poLineId", poLineId) - .put("invoiceId", goodInvoiceIds[i]) + .put("poLineId", poLineId.toString()) + .put("invoiceId", goodInvoiceIds[i].toString()) .put("quantity", 1 + i) .put("subTotal", 10.0 + i * 5) .put("total", 12.0 + i * 6) @@ -575,10 +576,10 @@ static void getPackageContent(RoutingContext ctx) { if ("1".equals(page)) { for (UUID packageTitle : packageTitles) { JsonObject item = new JsonObject() - .put("id", UUID.randomUUID()) + .put("id", UUID.randomUUID().toString()) .put("pti", new JsonObject() .put("titleInstance", new JsonObject() - .put("id", packageTitle) + .put("id", packageTitle.toString()) ) ); ar.add(item); @@ -665,7 +666,7 @@ static void getTransaction(RoutingContext ctx) { ctx.response().setChunked(true); ctx.response().putHeader("Content-Type", "application/json"); JsonObject transaction = new JsonObject(); - transaction.put("id", id); + transaction.put("id", id.toString()); transaction.put("amount", 100.0); ctx.response().end(transaction.encode()); return; @@ -724,7 +725,7 @@ public static void beforeClass(TestContext context) { @AfterClass public static void afterClass(TestContext context) { - vertx.close(context.asyncAssertSuccess()); + vertx.close().onComplete(context.asyncAssertSuccess()); } @Test @@ -783,6 +784,26 @@ public void testGetTitlesBadLimit() { .body(containsString("limit in location QUERY: value should be >= 0")); } + @Test + public void testGetTitlesBadOffset() { + RestAssured.given() + .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) + .get("/eusage-reports/report-titles?offset=-2") + .then().statusCode(400) + .header("Content-Type", is("text/plain")) + .body(containsString("offset in location QUERY: value should be >= 0")); + } + + @Test + public void testGetTitlesBadLimitOffset() { + RestAssured.given() + .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) + .get("/eusage-reports/report-titles?limit=a&offset=b") + .then().statusCode(400) + .header("Content-Type", is("text/plain")) + .body(containsString("Parameters limit and offset must be integers")); + } + @Test public void testPostTitlesFromCounterNoOkapiUrl() { String tenant = "testlib"; @@ -835,7 +856,7 @@ public void testPostTitlesBadJson() { .post("/eusage-reports/report-titles") .then().statusCode(400) .header("Content-Type", is("text/plain")) - .body(containsString("Failed to decode")); + .body(containsString("The request body can't be decoded")); } @Test @@ -854,7 +875,7 @@ public void testPostTitlesBadId() { .post("/eusage-reports/report-titles") .then().statusCode(400) .header("Content-Type", is("text/plain")) - .body(containsString("Validation error for body application/json")); + .body(containsString("Invalid UUID string: 1234")); } @Test @@ -865,7 +886,7 @@ public void testPostTitlesBadKbTitleId() { .header("Content-Type", "application/json") .body(new JsonObject().put("titles", new JsonArray() .add(new JsonObject() - .put("id", UUID.randomUUID()) + .put("id", UUID.randomUUID().toString()) .put("kbTitleName", "kb title name") .put("kbTitleId", "1234") ) @@ -873,7 +894,7 @@ public void testPostTitlesBadKbTitleId() { .post("/eusage-reports/report-titles") .then().statusCode(400) .header("Content-Type", is("text/plain")) - .body(containsString("Validation error for body application/json")); + .body(containsString("The value of the request body is invalid. Reason: Property \"titles\" does not match additional properties schema at #/titles")); } @Test @@ -1023,7 +1044,7 @@ public void testFromCounterMissingOkapiUrl() { .header(XOkapiHeaders.TENANT, tenant) .header("Content-Type", "application/json") .body(new JsonObject() - .put("counterReportId", goodCounterReportId) + .put("counterReportId", goodCounterReportId.toString()) .encode()) .post("/eusage-reports/report-titles/from-counter") .then().statusCode(400) @@ -1045,7 +1066,7 @@ public void testFromCounterBadId() { .post("/eusage-reports/report-titles/from-counter") .then().statusCode(400) .header("Content-Type", is("text/plain")) - .body(containsString("Validation error for body application/json")); + .body(containsString("The value of the request body is invalid. Reason: Property \"counterReportId\" does not match additional properties schema at #/counterReportId")); } @Test @@ -1073,7 +1094,7 @@ public void testFromAgreementBadId() { .post("/eusage-reports/report-data/from-agreement") .then().statusCode(400) .header("Content-Type", is("text/plain")) - .body(containsString("Bad Request")); + .body(containsString("The value of the request body is invalid. Reason: Property \"agreementId\" does not match additional properties schema at #/agreementId")); } @Test @@ -1275,7 +1296,7 @@ public void testPostTenantOK(TestContext context) { analyzeTitles(context, resObject, 7, 7, 1, 0, 0); JsonObject n = new JsonObject(); - n.put("id", UUID.randomUUID()); + n.put("id", UUID.randomUUID().toString()); n.put("kbTitleName", "correct kb title name"); n.put("kbTitleId", UUID.randomUUID().toString()); postTitleObject = new JsonObject(); @@ -1304,7 +1325,8 @@ public void testPostTenantOK(TestContext context) { .post("/eusage-reports/report-titles") .then().statusCode(400) .header("Content-Type", is("text/plain")) - .body(containsString("Validation error for body application/json")); + .body(containsString("The value of the request body is invalid. Reason: Property \"titles\" " + + "does not match additional properties schema at #/titles")); response = RestAssured.given() .header(XOkapiHeaders.TENANT, tenant) @@ -1339,7 +1361,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("counterReportId", goodCounterReportId) + .put("counterReportId", goodCounterReportId.toString()) .encode()) .post("/eusage-reports/report-titles/from-counter") .then().statusCode(200) @@ -1351,7 +1373,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("providerId", usageProviderId) + .put("providerId", usageProviderId.toString()) .encode()) .post("/eusage-reports/report-titles/from-counter") .then().statusCode(200) @@ -1496,7 +1518,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("counterReportId", badJsonCounterReportId) + .put("counterReportId", badJsonCounterReportId.toString()) .encode()) .post("/eusage-reports/report-titles/from-counter") .then().statusCode(400) @@ -1508,7 +1530,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("counterReportId", badStatusCounterReportId) + .put("counterReportId", badStatusCounterReportId.toString()) .encode()) .post("/eusage-reports/report-titles/from-counter") .then().statusCode(400) @@ -1520,7 +1542,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("counterReportId", UUID.randomUUID()) // unknown ID + .put("counterReportId", UUID.randomUUID().toString()) // unknown ID .encode()) .post("/eusage-reports/report-titles/from-counter") .then().statusCode(404); @@ -1546,7 +1568,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("agreementId", UUID.randomUUID()) // unknown ID + .put("agreementId", UUID.randomUUID().toString()) // unknown ID .encode()) .post("/eusage-reports/report-data/from-agreement") .then().statusCode(404); @@ -1556,18 +1578,18 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("agreementId", badJsonAgreementId) + .put("agreementId", badJsonAgreementId.toString()) .encode()) .post("/eusage-reports/report-data/from-agreement") .then().statusCode(400) - .body(containsString("Failed to decode")); + .body(startsWith("Unexpected close marker ']': expected '}'")); RestAssured.given() .header(XOkapiHeaders.TENANT, tenant) .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("agreementId", badStatusAgreementId) + .put("agreementId", badStatusAgreementId.toString()) .encode()) .post("/eusage-reports/report-data/from-agreement") .then().statusCode(400) @@ -1579,7 +1601,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("agreementId", badStatusAgreementId2) + .put("agreementId", badStatusAgreementId2.toString()) .encode()) .post("/eusage-reports/report-data/from-agreement") .then().statusCode(400) @@ -1591,7 +1613,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("agreementId", goodAgreementId) + .put("agreementId", goodAgreementId.toString()) .encode()) .post("/eusage-reports/report-data/from-agreement") .then().statusCode(200) @@ -1615,7 +1637,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("agreementId", goodAgreementId) + .put("agreementId", goodAgreementId.toString()) .encode()) .post("/eusage-reports/report-data/from-agreement") .then().statusCode(200) @@ -1629,7 +1651,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("counterReportId", otherCounterReportId) + .put("counterReportId", otherCounterReportId.toString()) .encode()) .post("/eusage-reports/report-titles/from-counter") .then().statusCode(200) @@ -1736,7 +1758,7 @@ public void testPostTenantOK(TestContext context) { .header(XOkapiHeaders.URL, "http://localhost:" + MOCK_PORT) .header("Content-Type", "application/json") .body(new JsonObject() - .put("agreementId", goodAgreementId) + .put("agreementId", goodAgreementId.toString()) .encode()) .post("/eusage-reports/report-data/from-agreement") .then().statusCode(400) diff --git a/src/test/java/org/folio/eusage/reports/api/EusageReportsApiTest.java b/src/test/java/org/folio/eusage/reports/api/EusageReportsApiTest.java index f36e73d3..0050988f 100644 --- a/src/test/java/org/folio/eusage/reports/api/EusageReportsApiTest.java +++ b/src/test/java/org/folio/eusage/reports/api/EusageReportsApiTest.java @@ -17,6 +17,7 @@ import static org.mockito.Mockito.when; import io.vertx.core.Future; +import io.vertx.core.MultiMap; import io.vertx.core.Vertx; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; @@ -112,7 +113,10 @@ private Future getUseOverTime(String format, String startDate, String en if (!full) { when(ctx.request().params().get("full")).thenReturn("false"); } - when(ctx.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + + MultiMap multimap = MultiMap.caseInsensitiveMultiMap(); + multimap.add("X-Okapi-Tenant", "tenant"); + when(ctx.request().headers()).thenReturn(multimap); when(ctx.request().params().get("format")).thenReturn(format); when(ctx.request().params().get("agreementId")).thenReturn(UUID.randomUUID().toString()); when(ctx.request().params().get("startDate")).thenReturn(startDate); @@ -916,7 +920,8 @@ public void useOverTime63(TestContext context) { @Test public void costPerUse63(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("startDate")).thenReturn("2020-02"); when(routingContext.request().params().get("endDate")).thenReturn("2020-06"); @@ -975,7 +980,8 @@ public void reqsByDateOfUseYopInterval2Y(TestContext context) { @Test public void reqsByDateOfUseWithRoutingContext(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("startDate")).thenReturn("2020-05"); when(routingContext.request().params().get("endDate")).thenReturn("2020-06"); @@ -1006,7 +1012,8 @@ public void reqsByDateOfUseWithRoutingContext(TestContext context) { @Test public void reqsByDateOfUseWithRoutingContextNoItems(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("full")).thenReturn("false"); when(routingContext.request().params().get("startDate")).thenReturn("2020-05"); @@ -1028,7 +1035,8 @@ public void reqsByDateOfUseWithRoutingContextNoItems(TestContext context) { @Test public void reqsByDateOfUseWithRoutingContextCsv(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("csv")).thenReturn("true"); when(routingContext.request().params().get("startDate")).thenReturn("2020-05"); @@ -1081,7 +1089,8 @@ private Future getReqsByPubPeriod(boolean includeOA, String agreemen @Test public void reqsByPubYearAccessCountPeriodAuto(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("full")).thenReturn("false"); when(routingContext.request().params().get("accessCountPeriod")).thenReturn("auto"); @@ -1118,7 +1127,8 @@ public void reqsByPubYearAccessCountPeriodAuto(TestContext context) { @Test public void reqsByPubYearAccessCountPeriod2Y(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("accessCountPeriod")).thenReturn("2Y"); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); @@ -1143,7 +1153,8 @@ public void reqsByPubYearAccessCountPeriod2Y(TestContext context) { @Test public void reqsByPubYearAccessCountPeriod3M(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("accessCountPeriod")).thenReturn("3M"); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); @@ -1216,7 +1227,8 @@ public void reqsByPubYear(TestContext context) { @Test public void costPerUseWithRoutingContextNoItems(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("full")).thenReturn("false"); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); @@ -1244,7 +1256,8 @@ public void costPerUseWithRoutingContextNoItems(TestContext context) { @Test public void costPerUseWithRoutingContext1(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); when(routingContext.request().params().get("endDate")).thenReturn("2020-08"); @@ -1297,7 +1310,8 @@ public void costPerUseWithRoutingContext1(TestContext context) { @Test public void costPerUseWithRoutingContext2(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); when(routingContext.request().params().get("endDate")).thenReturn("2020-08"); @@ -1325,7 +1339,8 @@ public void costPerUseWithRoutingContext2(TestContext context) { @Test public void costPerUseWithRoutingContext2NoOA(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); when(routingContext.request().params().get("endDate")).thenReturn("2020-08"); @@ -1365,7 +1380,8 @@ public void costPerUseWithRoutingContext2NoOA(TestContext context) { @Test public void costPerUseWithRoutingContext3(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a3); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); when(routingContext.request().params().get("endDate")).thenReturn("2020-06"); @@ -1389,7 +1405,8 @@ public void costPerUseWithRoutingContext3(TestContext context) { @Test public void costPerUseWithRoutingContext4(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a4); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); when(routingContext.request().params().get("endDate")).thenReturn("2020-07"); @@ -1430,7 +1447,8 @@ public void costPerUseWithRoutingContext4(TestContext context) { @Test public void costPerUseAccessCountPeriod1Y(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("startDate")).thenReturn("2020-04"); when(routingContext.request().params().get("endDate")).thenReturn("2020-08"); @@ -1489,7 +1507,8 @@ public void costPerUseAccessCountPeriod1Y(TestContext context) { @Test public void costPerUseAccessCountPeriod5Y(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("startDate")).thenReturn("2015-09"); when(routingContext.request().params().get("endDate")).thenReturn("2020-08"); @@ -1533,7 +1552,8 @@ public void costPerUseAccessCountPeriod5Y(TestContext context) { @Test public void costPerUseNoOverlap(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a1); when(routingContext.request().params().get("startDate")).thenReturn("2022-01"); when(routingContext.request().params().get("endDate")).thenReturn("2022-02"); @@ -1556,7 +1576,8 @@ public void costPerUseNoOverlap(TestContext context) { @Test public void costPerUseNoItems(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("csv")).thenReturn("true"); when(routingContext.request().params().get("full")).thenReturn("false"); @@ -1591,7 +1612,8 @@ public void costPerUseNoItems(TestContext context) { @Test public void costPerFormatAllCsv(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("csv")).thenReturn("true"); when(routingContext.request().params().get("startDate")).thenReturn("2020-05"); @@ -1660,7 +1682,8 @@ public void costPerFormatAllCsv(TestContext context) { @Test public void costPerUseFormatBookCsv(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("format")).thenReturn("BOOK"); when(routingContext.request().params().get("csv")).thenReturn("true"); @@ -1696,7 +1719,8 @@ public void costPerUseFormatBookCsv(TestContext context) { @Test public void costPerUseFormatJournalCsv(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("format")).thenReturn("JOURNAL"); when(routingContext.request().params().get("csv")).thenReturn("true"); @@ -1738,7 +1762,8 @@ public void costPerUseFormatJournalCsv(TestContext context) { @Test public void costPerUseFormatJournalJson(TestContext context) { RoutingContext routingContext = mock(RoutingContext.class, RETURNS_DEEP_STUBS); - when(routingContext.request().getHeader("X-Okapi-Tenant")).thenReturn(tenant); + when(routingContext.request().headers()) + .thenReturn(MultiMap.caseInsensitiveMultiMap().add("X-Okapi-Tenant","tenant")); when(routingContext.request().params().get("agreementId")).thenReturn(a2); when(routingContext.request().params().get("format")).thenReturn("JOURNAL"); when(routingContext.request().params().get("startDate")).thenReturn("2020-05");