Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ee8a73f
Core - API - Added schema for storage block, main objects
GregJohnStewart Aug 17, 2025
a8b47b0
Core - API - Added schema for search results
GregJohnStewart Aug 17, 2025
e64cbe9
Core - API - Added schema notes for inventory items, stored
GregJohnStewart Aug 17, 2025
d474c4a
Lib - Core API for Quarkus - Added support for connecting to a runnin…
GregJohnStewart Apr 3, 2026
5c5b2e8
Lib - Core API for Quarkus - Version bumps for snapshot release
GregJohnStewart Apr 5, 2026
2851e73
Plugin - Alert Messenger - Initial work to get deps and core api lib …
GregJohnStewart Apr 5, 2026
b416e5b
Merge branch 'development' into dev/692-fr-core-api---review-update-i…
GregJohnStewart Apr 6, 2026
9f98fe8
Core - API - Fixing paging calc tests
GregJohnStewart Apr 6, 2026
9086707
Core - API - Fixing test
GregJohnStewart Apr 6, 2026
5a4129f
Core - API - Updates to attKeyword schema examples
GregJohnStewart Apr 6, 2026
f47b833
Core - API - Officially fixed ObjectId schema in openapi output
GregJohnStewart Apr 6, 2026
595ab14
Core - API - Adjusted, cleaned, and brought in line the file attachme…
GregJohnStewart Apr 7, 2026
5b2ece1
Core - API - Some tweak and addition of code generation notes
GregJohnStewart Apr 7, 2026
0a6a930
Core - API - Cleanup and verification of openapi schema for identifie…
GregJohnStewart Apr 7, 2026
638d652
Core - API - Fixed currency openapi schema
GregJohnStewart Apr 7, 2026
8b2f1c7
Core - API - Adjusted openapi schema for interacting entity endpoints
GregJohnStewart Apr 7, 2026
b1b1f56
Bump org.cyclonedx.bom in /software/core/oqm-core-api
dependabot[bot] Apr 7, 2026
17fd90a
Core - API - Adjusted openapi schema for inventory items and units en…
GregJohnStewart Apr 8, 2026
86614bf
Core - API - Adjusted openapi schema for inventory management endpoints
GregJohnStewart Apr 8, 2026
ca5127c
Core - API - excluding item list endpoints, fix test
GregJohnStewart Apr 8, 2026
5e3e3e7
Core - API - quarkus version bump
GregJohnStewart Apr 8, 2026
dd0ee9d
Core - API - Adjusted openapi schema for item categories
GregJohnStewart Apr 9, 2026
508e1ca
Core - API - Adjusted openapi schema for item checkouts
GregJohnStewart Apr 9, 2026
686a7eb
Core - API - Adjusted openapi schema for images
GregJohnStewart Apr 9, 2026
6820d2e
Core - API - Adjusted openapi schema for storage blocks
GregJohnStewart Apr 9, 2026
c994ef4
Core - API - Tweaks from review, snapshot version bump
GregJohnStewart Apr 9, 2026
3e57211
Merge pull request #1187 from Epic-Breakfast-Productions/dev/692-fr-c…
GregJohnStewart Apr 9, 2026
112ba52
Core - API - Moved away from ingesting String object ids in rest, rem…
GregJohnStewart Apr 9, 2026
ff3e9e0
Merge branch 'development' into dependabot/gradle/software/core/oqm-c…
GregJohnStewart Apr 9, 2026
d23c68e
Merge pull request #1188 from Epic-Breakfast-Productions/dependabot/g…
GregJohnStewart Apr 9, 2026
9b8bda0
Merge branch 'main' into development
GregJohnStewart Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions software/core/oqm-core-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ plugins {
id 'io.quarkus'
id "io.freefair.lombok" version "9.2.0"
id 'jacoco'
id 'org.cyclonedx.bom' version '3.2.2'
id 'org.cyclonedx.bom' version '3.2.3'
id("org.spdx.sbom") version "0.10.0"
}

group 'com.ebp.openQuarterMaster'
version '4.4.3'
version '4.4.4-SNAPSHOT'

repositories {
mavenCentral()
Expand Down
19 changes: 16 additions & 3 deletions software/core/oqm-core-api/clientGen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,20 @@
All commands listed to be run in this directory


##


## Running

```bash
docker run --rm \
-v ${PWD}:/local \
openapitools/openapi-generator-cli generate \
-i /local/openapi.yaml -g jaxrs-cxf-client -o /local/out/jaxrs -c /local/jaxrs-cxf-client-config.json
```

# References

- https://openapi-generator.tech
- https://openapi-generator.tech/docs/installation#docker
- Generators:
- https://openapi-generator.tech/docs/generators/java
- https://openapi-generator.tech/docs/generators/jaxrs-cxf-client

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"securityScheme": "JwtAuth"
}
4 changes: 2 additions & 2 deletions software/core/oqm-core-api/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#Gradle properties
quarkusPluginId=io.quarkus
quarkusPluginVersion=3.31.1
quarkusPlatformVersion=3.31.1
quarkusPluginVersion=3.34.2
quarkusPlatformVersion=3.34.2
quarkusPlatformGroupId=io.quarkus
quarkusPlatformArtifactId=quarkus-universe-bom
org.gradle.logging.level=INFO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.bson.types.ObjectId;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import tech.ebp.oqm.core.api.model.object.interactingEntity.InteractingEntity;
import tech.ebp.oqm.core.api.model.object.interactingEntity.InteractingEntityType;

Expand All @@ -18,10 +19,11 @@
@Singleton
@NoArgsConstructor
@BsonDiscriminator
@Schema(title = "CoreApiInteractingEntity", description = "The entity for the core API interacting entity. Used for internal actions, such as schema upgrades and marking as expired.")
public class CoreApiInteractingEntity extends InteractingEntity {

/**
* Don't change this. We ue this very specific ObjectId to identify the Base Station's specific entry in the db.
* Don't change this. We use this very specific ObjectId to identify the Base Station's specific entry in the db.
*/
public static final ObjectId BS_ID = new ObjectId("00000000AAAAAAAAAAFFFFFF");

Expand All @@ -42,6 +44,7 @@ public String getName() {

@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@Override
@Schema(constValue = "CORE_API", readOnly = true, required = true, examples = "CORE_API")
public InteractingEntityType getType() {
return InteractingEntityType.CORE_API;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package tech.ebp.oqm.core.api.config;

import io.quarkus.smallrye.openapi.OpenApiFilter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.openapi.OASFactory;
import org.eclipse.microprofile.openapi.OASFilter;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.eclipse.microprofile.openapi.models.media.Schema;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Tweaks the openapi schema. Used to hard override certain schemas.
* <p>
* <a href="https://quarkus.io/guides/openapi-swaggerui#enhancing-the-openapi-schema-with-filters">Quarkus guide section</a>
*/
@Slf4j
@OpenApiFilter(stages = {OpenApiFilter.RunStage.BUILD, OpenApiFilter.RunStage.RUNTIME_STARTUP, OpenApiFilter.RunStage.RUNTIME_PER_REQUEST})
public class OpenApiTweaks implements OASFilter {

private static Map<String, Schema> getSchemaOverrides(Map<String, Schema> existingSchemas) {
return new HashMap<>() {{
{// ObjectId
Schema objectIdSchema = OASFactory.createSchema();
objectIdSchema.setComment("Hex string representation of a MongoDB ObjectId");
objectIdSchema.setType(List.of(Schema.SchemaType.STRING));
objectIdSchema.setFormat("objectId");
objectIdSchema.setPattern("^[0-9a-fA-F]{24}$");
objectIdSchema.setExamples(List.of("null", "5f9222222222222222222222"));
put("ObjectId", objectIdSchema);
}
{// Currency
Schema objectIdSchema = OASFactory.createSchema();
objectIdSchema.setComment("Currency code from ISO 4217 / Java Currency");
objectIdSchema.setType(List.of(Schema.SchemaType.STRING));
objectIdSchema.setFormat("currency code");
objectIdSchema.setExamples(List.of("USD"));
put("Currency", objectIdSchema);
}
{// Unit
Schema unitSchema = OASFactory.createSchema();
unitSchema.setTitle("Unit");
unitSchema.setComment("Unit of measurement");
unitSchema.setType(List.of(Schema.SchemaType.OBJECT));

{
Schema nameSchema = OASFactory.createSchema();
nameSchema.type(List.of(Schema.SchemaType.STRING));
nameSchema.setReadOnly(true);
nameSchema.description("Name of the unit in 'normal' terms. Derived, provided for downstream usage.");
nameSchema.setExamples(List.of("Units"));

unitSchema.addProperty("name", nameSchema);
}
{
Schema symbolSchema = OASFactory.createSchema();
symbolSchema.type(List.of(Schema.SchemaType.STRING));
symbolSchema.setReadOnly(true);
symbolSchema.description("The symbol of the unit, as in 5{symbol}. Derived, provided for downstream usage.");
symbolSchema.setExamples(List.of("units"));

unitSchema.addProperty("symbol", symbolSchema);
}
{
Schema stringSchema = OASFactory.createSchema();
stringSchema.type(List.of(Schema.SchemaType.STRING));
stringSchema.description(
"The string representation of the unit, used in de/serialization. Is the only required field, the others are derived from the deserialized "
+ "unit.");
stringSchema.setExamples(List.of("units"));
unitSchema.addProperty("string", stringSchema);
}
unitSchema.setRequired(List.of("string"));
put("UnitObject", unitSchema); //when Unit<?>
put("UnitQuantity", unitSchema); //when Unit<?>?
put("Unit", unitSchema); //when Unit
}
{
Schema monetaryAmountSchema = OASFactory.createSchema();
monetaryAmountSchema.setComment("An amount of currency");
monetaryAmountSchema.setType(List.of(Schema.SchemaType.OBJECT));

{
Schema numberSchema = OASFactory.createSchema();
numberSchema.type(List.of(Schema.SchemaType.NUMBER));
numberSchema.description("The amount of the currency..");
numberSchema.setExamples(List.of("0.00", "0", "5"));

monetaryAmountSchema.addProperty("number", numberSchema);
}

monetaryAmountSchema.addProperty("currency", this.get("Currency"));

monetaryAmountSchema.setRequired(List.of("currency", "number"));
put("MonetaryAmount", monetaryAmountSchema);
}
{// Color
Schema colorSchema = OASFactory.createSchema();
colorSchema.setComment("A hex string representing a color.");
colorSchema.setType(List.of(Schema.SchemaType.STRING));
colorSchema.setFormat("Color");
colorSchema.setPattern("^#?([0-9a-f]{6}|[0-9a-f]{3})$");
colorSchema.setExamples(List.of("#FFFFFF"));
put("Color", colorSchema);
}
}};
}

@Override
public void filterOpenAPI(OpenAPI openAPI) {
log.info("Running OpenApiTweaks filter");

Map<String, Schema> schemas = new HashMap<>(openAPI.getComponents().getSchemas());
schemas.putAll(getSchemaOverrides(schemas));
openAPI.getComponents().setSchemas(schemas);

log.debug("Done OpenApiTweaks filter");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import tech.ebp.oqm.core.api.interfaces.endpoints.media.FileGet;
import tech.ebp.oqm.core.api.model.object.FileMainObject;
import tech.ebp.oqm.core.api.model.object.MainObject;
Expand All @@ -34,18 +35,18 @@
@NoArgsConstructor
public abstract class MainFileObjectProvider<T extends FileMainObject, U extends FileUploadBody, S extends FileSearchObject<T>, G extends MainObject & FileGet> extends ObjectProvider {


@Parameter(description = "The OQM database id or name to use for this request.")
@Getter
@PathParam("oqmDbIdOrName")
String oqmDbIdOrName;

public abstract MongoHistoriedFileService<T, U, S, G> getFileService();

protected Response.ResponseBuilder getSearchResponseBuilder(
protected SearchResult<G> getSearchResponseBuilder(
String oqmDbIdOrName,
S searchObject
) {
return this.getSearchResultResponseBuilder(this.getFileService().search(oqmDbIdOrName, searchObject));
return this.getFileService().search(oqmDbIdOrName, searchObject);
}

//<editor-fold desc="CRUD operations">
Expand Down Expand Up @@ -82,12 +83,12 @@ protected Response.ResponseBuilder getSearchResponseBuilder(
// )
// @Produces(MediaType.APPLICATION_JSON)
// @RolesAllowed(UserRoles.INVENTORY_VIEW)
public Response search(
public SearchResult<G> search(
// @BeanParam
S searchObject
) {
//TODO:: this should produce results of the G type, not T
return this.getSearchResponseBuilder(this.getOqmDbIdOrName(), searchObject).build();
return this.getSearchResponseBuilder(this.getOqmDbIdOrName(), searchObject);
}

protected abstract T getFileObjFromUpload(U upload);
Expand All @@ -114,16 +115,19 @@ public Response search(
// @RolesAllowed(Roles.INVENTORY_ADMIN)
// @Consumes(MediaType.MULTIPART_FORM_DATA)
// @Produces(MediaType.APPLICATION_JSON)
public Response add(
public G add(
//@BeanParam
U body
) throws IOException {
return Response.ok(this.getFileService().add(
return this.getFileService().fileObjToGet(
this.getOqmDbIdOrName(),
this.getFileObjFromUpload(body),
body,
this.getInteractingEntity()
)).build();
this.getFileService().add(
this.getOqmDbIdOrName(),
this.getFileObjFromUpload(body),
body,
this.getInteractingEntity()
)
);
}

// @Path("{id}")
Expand Down Expand Up @@ -160,7 +164,7 @@ public Response add(
// @RolesAllowed(UserRoles.INVENTORY_VIEW)
public G get(
// @PathParam("id")
String id
ObjectId id
) {
log.info("Retrieving object with id {}", id);
return this.getFileService().getObjGet(this.getOqmDbIdOrName(), id);
Expand Down Expand Up @@ -201,7 +205,7 @@ public G get(
// @Produces(MediaType.APPLICATION_JSON)
public Integer updateFile(
// @PathParam("id")
String id,
ObjectId id,
// @BeanParam
U body
) throws IOException {
Expand All @@ -210,7 +214,7 @@ public Integer updateFile(

public G updateObj(
// @PathParam("id")
String id,
ObjectId id,
// @BeanParam
ObjectNode updates
) {
Expand All @@ -226,7 +230,7 @@ public G updateObj(
);
}

protected <A> A getRevision(String id, String revision, Class<A> aClass) throws IOException {
protected <A> A getRevision(ObjectId id, String revision, Class<A> aClass) throws IOException {
int revisionNum;
if ("latest".equalsIgnoreCase(revision)) {
revisionNum = this.getFileService().getLatestVersionNum(this.getOqmDbIdOrName(), id);
Expand Down Expand Up @@ -278,7 +282,7 @@ protected <A> A getRevision(String id, String revision, Class<A> aClass) throws
// @RolesAllowed(UserRoles.INVENTORY_VIEW)
public FileMetadata getRevision(
// @PathParam("id")
String id,
ObjectId id,
// @PathParam("rev")
String revision
) throws IOException {
Expand Down Expand Up @@ -321,7 +325,7 @@ public FileMetadata getRevision(
// @RolesAllowed(UserRoles.INVENTORY_VIEW)
public Response getRevisionData(
// @PathParam("id")
String id,
ObjectId id,
// @PathParam("rev")
String revision
) throws IOException {
Expand Down Expand Up @@ -374,10 +378,10 @@ public Response getRevisionData(
// @RolesAllowed(Roles.INVENTORY_EDIT)
public G remove(
// @PathParam("id")
String id
ObjectId id
) {
log.info("Retrieving object with id {}", id);
return this.getFileService().removeFile(this.getOqmDbIdOrName(), null, new ObjectId(id), this.getInteractingEntity());
return this.getFileService().removeFile(this.getOqmDbIdOrName(), null, id, this.getInteractingEntity());
}

//</editor-fold>
Expand Down Expand Up @@ -411,18 +415,17 @@ public G remove(
// )
// @Produces(MediaType.APPLICATION_JSON)
// @RolesAllowed(Roles.INVENTORY_VIEW)
public Response getHistoryForObject(
public SearchResult<ObjectHistoryEvent> getHistoryForObject(
// @PathParam("id")
String id,
ObjectId id,
// @BeanParam
HistorySearch searchObject
) {
log.info("Retrieving specific {} history with id {} from REST interface", this.getFileService().getClazz().getSimpleName(), id);

searchObject.setObjectId(new ObjectId(id));
searchObject.setObjectId(id);

SearchResult<ObjectHistoryEvent> searchResult = this.getFileService().getFileObjectService().searchHistory(this.getOqmDbIdOrName(), searchObject, false);
return this.getSearchResultResponseBuilder(searchResult).build();
return this.getFileService().getFileObjectService().searchHistory(this.getOqmDbIdOrName(), searchObject, false);
}

// @GET
Expand Down
Loading
Loading