Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import uk.co.compendiumdev.thingifier.core.domain.definitions.relationship.RelationshipDefinition;
import uk.co.compendiumdev.thingifier.core.domain.instances.EntityInstance;
import uk.co.compendiumdev.thingifier.core.repository.ThingStore;
import uk.co.compendiumdev.thingifier.htmlgui.ThingifierGuiConfig;
import uk.co.compendiumdev.thingifier.reporting.ThingReporter;

/* Thingifier
Expand All @@ -33,6 +34,7 @@ public final class Thingifier implements AutoCloseable {
private final ThingifierApiConfig apiConfig;
private final ThingifierApiConfigProfiles apiConfigProfiles;
private final ThingifierApiSpec apiSpec;
private final ThingifierGuiConfig guiConfig;

public Thingifier() {
this(new EntityRelModel());
Expand All @@ -45,6 +47,7 @@ public Thingifier(final EntityRelModel erm) {
apiConfig = new ThingifierApiConfig("");
apiConfigProfiles = new ThingifierApiConfigProfiles();
apiSpec = new ThingifierApiSpec();
guiConfig = new ThingifierGuiConfig();
apiDocsConfig = new ApiDocsConfig();
}

Expand All @@ -62,6 +65,7 @@ public Thingifier(
this.apiConfig = apiConfig;
this.apiConfigProfiles = apiConfigProfiles;
this.apiSpec = new ThingifierApiSpec();
this.guiConfig = new ThingifierGuiConfig();
this.apiDocsConfig = apiDocsConfig;
}

Expand Down Expand Up @@ -216,6 +220,10 @@ public ThingifierApiSpec apiSpec() {
return apiSpec;
}

public ThingifierGuiConfig guiConfig() {
return guiConfig;
}

public void configureWithProfile(final ThingifierApiConfigProfile profileToUse) {
if (profileToUse == null) {
System.out.println("API System Defaults Used");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.Map;
import uk.co.compendiumdev.thingifier.api.response.ResponseHeader;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityViewDefinition;

public final class ApiRoutingDefinition {

Expand Down Expand Up @@ -58,6 +59,11 @@ public void addObjectSchema(EntityDefinition entityDefn) {

// and as plural for array responses
objectSchemas.put(entityDefn.getPlural(), entityDefn);

for (EntityViewDefinition view : entityDefn.getViews()) {
objectSchemas.put(view.getName(), entityDefn);
objectSchemas.put("create_" + view.getName(), entityDefn);
}
}

public boolean hasObjectSchemaNamed(String aName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,17 @@ public JsonObject asJsonObjectTypedArrayWithContentsUntyped(

public JsonObject asJsonObjectTypedDraftArrayWithContentsUntyped(
final List<EntityInstanceDraft> things, String typeName) {
return asJsonObjectTypedDraftArrayWithContentsUntyped(things, typeName, null);
}

public JsonObject asJsonObjectTypedDraftArrayWithContentsUntyped(
final List<EntityInstanceDraft> things,
String typeName,
final EntityViewDefinition view) {
final JsonObject arrayObj = new JsonObject();
JsonArray drafts = new JsonArray();
for (EntityInstanceDraft draft : things) {
drafts.add(asJsonObject(draft));
drafts.add(asJsonObject(draft, view));
}
arrayObj.add(typeName, drafts);
return arrayObj;
Expand Down Expand Up @@ -252,6 +259,11 @@ private JsonObject asFieldJsonObject(
}

public JsonObject asJsonObject(final EntityInstanceDraft draft) {
return asJsonObject(draft, null);
}

public JsonObject asJsonObject(
final EntityInstanceDraft draft, final EntityViewDefinition view) {
final JsonObject jsonobj = new JsonObject();

if (draft == null) {
Expand All @@ -268,6 +280,9 @@ public JsonObject asJsonObject(final EntityInstanceDraft draft) {
}

for (String fieldName : entity.getFieldNames()) {
if (view != null && !view.isResponseVisible(fieldName)) {
continue;
}
Field field = entity.getField(fieldName);
String fieldValue = draftValueFor(field, values.get(fieldName.toLowerCase()));
if (fieldValue == null) {
Expand Down Expand Up @@ -524,8 +539,13 @@ public JsonObject asNamedJsonObject(
}

public JsonObject asNamedJsonObject(final EntityInstanceDraft draft) {
return asNamedJsonObject(draft, null);
}

public JsonObject asNamedJsonObject(
final EntityInstanceDraft draft, final EntityViewDefinition view) {
final JsonObject retObj = new JsonObject();
retObj.add(draft.getEntity().getName(), asJsonObject(draft));
retObj.add(draft.getEntity().getName(), asJsonObject(draft, view));
return retObj;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ public String getSingleObjectXml(
}

public String getSingleObjectXml(final EntityInstanceDraft draft) {
String parseForXMLOutput = jsonConvertor.asNamedJsonObject(draft).toString();
return getSingleObjectXml(draft, null);
}

public String getSingleObjectXml(
final EntityInstanceDraft draft, final EntityViewDefinition view) {
String parseForXMLOutput = jsonConvertor.asNamedJsonObject(draft, view).toString();
return XML.toString(new JSONObject(parseForXMLOutput));
}

Expand Down Expand Up @@ -78,10 +83,17 @@ public String getCollectionOfThings(
public String getCollectionOfDrafts(
final List<EntityInstanceDraft> thingsToReturn,
final EntityDefinition typeOfThingReturned) {
return getCollectionOfDrafts(thingsToReturn, typeOfThingReturned, null);
}

public String getCollectionOfDrafts(
final List<EntityInstanceDraft> thingsToReturn,
final EntityDefinition typeOfThingReturned,
final EntityViewDefinition view) {
String parseForXMLOutput =
jsonConvertor
.asJsonObjectTypedDraftArrayWithContentsUntyped(
thingsToReturn, typeOfThingReturned.getPlural())
thingsToReturn, typeOfThingReturned.getPlural(), view)
.toString();

String output = XML.toString(new JSONObject(parseForXMLOutput));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package uk.co.compendiumdev.thingifier.htmlgui;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityViewDefinition;

public final class ThingifierGuiConfig {

private final DataExplorerConfig dataExplorer;

public ThingifierGuiConfig() {
dataExplorer = new DataExplorerConfig();
}

public DataExplorerConfig dataExplorer() {
return dataExplorer;
}

public static final class DataExplorerConfig {
private final Map<String, String> responseViewNamesByEntity;

private DataExplorerConfig() {
responseViewNamesByEntity = new HashMap<>();
}

public DataExplorerConfig responseView(final String entityName, final String viewName) {
final String normalizedEntityName = normalize(entityName);
final String normalizedViewName = viewName == null ? "" : viewName.trim();
if (normalizedEntityName.isEmpty()) {
throw new IllegalArgumentException("Entity name is required");
}
if (normalizedViewName.isEmpty()) {
throw new IllegalArgumentException("View name is required");
}
responseViewNamesByEntity.put(normalizedEntityName, normalizedViewName);
return this;
}

public Optional<String> responseViewNameFor(final EntityDefinition definition) {
if (definition == null) {
return Optional.empty();
}
String viewName = responseViewNamesByEntity.get(normalize(definition.getName()));
if (viewName == null) {
viewName = responseViewNamesByEntity.get(normalize(definition.getPlural()));
}
return Optional.ofNullable(viewName);
}

public EntityViewDefinition responseViewFor(final EntityDefinition definition) {
if (definition == null) {
return null;
}
return responseViewNameFor(definition)
.filter(definition::hasViewNamed)
.map(definition::getViewNamed)
.orElse(null);
Comment on lines +56 to +59

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject unknown response views instead of exposing every field

When a configured view name is misspelled, renamed, or registered against the wrong entity, this filter silently converts the configuration to null; DefaultGuiHtmlPages.isResponseFieldVisible and the JSON/XML converters interpret null as no projection and render every field. A typo in a view intended to hide tokens or other internal data therefore fails open in the Data Explorer rather than producing a configuration error or an empty projection.

Useful? React with 👍 / 👎.

}

private static String normalize(final String value) {
return value == null ? "" : value.trim().toLowerCase();
}
}
}
Loading
Loading