From 3047249d7dd8d9ee1222bc7867093083041fe71b Mon Sep 17 00:00:00 2001 From: Gunnar Velle Date: Fri, 9 Aug 2024 15:06:11 +0200 Subject: [PATCH 1/2] Adds rootId and parentId when fetching nodes to pick correct context --- .../config/WarningSuppressionLogFilter.java | 23 ++++--- .../java/no/ndla/taxonomy/domain/Node.java | 14 ++--- .../java/no/ndla/taxonomy/rest/v1/Nodes.java | 18 ++++-- .../no/ndla/taxonomy/rest/v1/Resources.java | 8 ++- .../no/ndla/taxonomy/rest/v1/Subjects.java | 8 ++- .../java/no/ndla/taxonomy/rest/v1/Topics.java | 8 ++- .../no/ndla/taxonomy/service/NodeService.java | 27 +++++--- .../taxonomy/service/dtos/NodeChildDTO.java | 10 --- .../no/ndla/taxonomy/domain/NodeTest.java | 2 +- .../no/ndla/taxonomy/rest/v1/NodesTest.java | 62 ++++++++++++++++++- 10 files changed, 127 insertions(+), 53 deletions(-) diff --git a/src/main/java/no/ndla/taxonomy/config/WarningSuppressionLogFilter.java b/src/main/java/no/ndla/taxonomy/config/WarningSuppressionLogFilter.java index 33ac0c20..89d76b88 100644 --- a/src/main/java/no/ndla/taxonomy/config/WarningSuppressionLogFilter.java +++ b/src/main/java/no/ndla/taxonomy/config/WarningSuppressionLogFilter.java @@ -15,20 +15,19 @@ public class WarningSuppressionLogFilter extends Filter { final String[] warningsToSuppress = { - // https://github.com/javamelody/javamelody/issues/1222 - "Bean 'net.bull.javamelody.JavaMelodyAutoConfiguration' of type [net.bull.javamelody.JavaMelodyAutoConfiguration$$SpringCGLIB$$0] is not eligible for getting processed by all BeanPostProcessors", - "Bean 'monitoringSpringAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", - "Bean 'monitoringSpringServiceAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", - "Bean 'monitoringSpringControllerAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", - "Bean 'monitoringSpringRestControllerAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", - "Bean 'monitoringSpringAsyncAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", - "Bean 'monitoringSpringScheduledAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", - // NOTE: These are logged because we use `runAlways=true` in the liquibase configuration - "schema \"extensions\" already exists, skipping", - "extension \"btree_gist\" already exists, skipping", + // https://github.com/javamelody/javamelody/issues/1222 + "Bean 'net.bull.javamelody.JavaMelodyAutoConfiguration' of type [net.bull.javamelody.JavaMelodyAutoConfiguration$$SpringCGLIB$$0] is not eligible for getting processed by all BeanPostProcessors", + "Bean 'monitoringSpringAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", + "Bean 'monitoringSpringServiceAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", + "Bean 'monitoringSpringControllerAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", + "Bean 'monitoringSpringRestControllerAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", + "Bean 'monitoringSpringAsyncAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", + "Bean 'monitoringSpringScheduledAdvisor' of type [net.bull.javamelody.MonitoringSpringAdvisor] is not eligible for getting processed by all BeanPostProcessors", + // NOTE: These are logged because we use `runAlways=true` in the liquibase configuration + "schema \"extensions\" already exists, skipping", + "extension \"btree_gist\" already exists, skipping", }; - @Override public FilterReply decide(ILoggingEvent event) { if (event.getLevel() == Level.WARN) { diff --git a/src/main/java/no/ndla/taxonomy/domain/Node.java b/src/main/java/no/ndla/taxonomy/domain/Node.java index d5b481b6..048106a8 100644 --- a/src/main/java/no/ndla/taxonomy/domain/Node.java +++ b/src/main/java/no/ndla/taxonomy/domain/Node.java @@ -254,17 +254,15 @@ public Optional pickContext( if (maybeContext.isPresent()) { return maybeContext; } - var withParent = parent.map(p -> contexts.stream() + var containsParent = parent.map(p -> contexts.stream() .filter(c -> c.parentIds().contains(p.getPublicId().toString())) .collect(Collectors.toSet())) .orElse(contexts); - var withRoot = root.flatMap(r -> withParent.stream() - .filter(c -> c.rootId().equals(r.getPublicId().toString())) - .findFirst()); - if (withRoot.isPresent()) { - return withRoot; - } - return contexts.stream().min((context1, context2) -> { + var containsRoot = root.map(p -> containsParent.stream() + .filter(c -> c.parentIds().contains(p.getPublicId().toString())) + .collect(Collectors.toSet())) + .orElse(containsParent); + return containsRoot.stream().min((context1, context2) -> { final var inPath1 = context1.path().contains(root.map(Node::getPathPart).orElse("other")); final var inPath2 = diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java b/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java index d88b4492..1d8f9df1 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java @@ -110,13 +110,17 @@ public List getAllNodes( Optional includeContexts, @Parameter(description = "Filter out programme contexts") @RequestParam(value = "filterProgrammes", required = false, defaultValue = "false") - boolean filterProgrammes) { + boolean filterProgrammes, + @Parameter(description = "Id to root id in context.") @RequestParam(value = "rootId", required = false) + Optional rootId, + @Parameter(description = "Id to parent id in context.") @RequestParam(value = "parentId", required = false) + Optional parentId) { MetadataFilters metadataFilters = new MetadataFilters(key, value, isVisible); var isRootOrContext = isRoot.isPresent() ? isRoot : isContext; var defaultNodeTypes = getDefaultNodeTypes(nodeType, contentUri, contextId, isRootOrContext, metadataFilters); return nodeService.getNodesByType( Optional.of(defaultNodeTypes), - language, + language.orElse(Constants.DefaultLanguage), publicIds, contentUri, contextId, @@ -124,7 +128,9 @@ public List getAllNodes( isContext, metadataFilters, includeContexts, - filterProgrammes); + filterProgrammes, + rootId, + parentId); } @GetMapping("/search") @@ -222,10 +228,14 @@ public SearchResultDTO getNodePage( @Transactional(readOnly = true) public NodeDTO getNode( @PathVariable("id") URI id, + @Parameter(description = "Id to root id in context.") @RequestParam(value = "rootId", required = false) + Optional rootId, + @Parameter(description = "Id to parent id in context.") @RequestParam(value = "parentId", required = false) + Optional parentId, @Parameter(description = "ISO-639-1 language code", example = "nb") @RequestParam(value = "language", required = false, defaultValue = Constants.DefaultLanguage) Optional language) { - return nodeService.getNode(id, language, Optional.of(true)); + return nodeService.getNode(id, language, Optional.of(true), rootId, parentId); } @PostMapping diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Resources.java b/src/main/java/no/ndla/taxonomy/rest/v1/Resources.java index f7b8e64a..47357c0c 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Resources.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Resources.java @@ -83,7 +83,7 @@ public List getAllResources( MetadataFilters metadataFilters = new MetadataFilters(key, value, isVisible); return nodeService.getNodesByType( Optional.of(List.of(NodeType.RESOURCE)), - language, + language.orElse(Constants.DefaultLanguage), Optional.empty(), contentUri, Optional.empty(), @@ -91,7 +91,9 @@ public List getAllResources( Optional.empty(), metadataFilters, Optional.of(false), - false); + false, + Optional.empty(), + Optional.empty()); } @Deprecated @@ -167,7 +169,7 @@ public NodeDTO getResource( @Parameter(description = "ISO-639-1 language code", example = "nb") @RequestParam(value = "language", required = false, defaultValue = Constants.DefaultLanguage) Optional language) { - return nodeService.getNode(id, language, Optional.of(false)); + return nodeService.getNode(id, language, Optional.of(false), Optional.empty(), Optional.empty()); } @Deprecated diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Subjects.java b/src/main/java/no/ndla/taxonomy/rest/v1/Subjects.java index 99be69e0..5250621c 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Subjects.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Subjects.java @@ -80,7 +80,7 @@ public List getAllSubjects( MetadataFilters metadataFilters = new MetadataFilters(key, value, isVisible); return nodeService.getNodesByType( Optional.of(List.of(NodeType.SUBJECT)), - language, + language.orElse(Constants.DefaultLanguage), Optional.empty(), Optional.empty(), Optional.empty(), @@ -88,7 +88,9 @@ public List getAllSubjects( Optional.empty(), metadataFilters, Optional.of(false), - false); + false, + Optional.empty(), + Optional.empty()); } @Deprecated @@ -167,7 +169,7 @@ public NodeDTO getSubject( @Parameter(description = "ISO-639-1 language code", example = "nb") @RequestParam(value = "language", required = false, defaultValue = Constants.DefaultLanguage) Optional language) { - return nodeService.getNode(id, language, Optional.of(false)); + return nodeService.getNode(id, language, Optional.of(false), Optional.empty(), Optional.empty()); } @Deprecated diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Topics.java b/src/main/java/no/ndla/taxonomy/rest/v1/Topics.java index d7103a18..94eba885 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Topics.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Topics.java @@ -68,7 +68,7 @@ public List getAllTopics( MetadataFilters metadataFilters = new MetadataFilters(key, value, isVisible); return nodeService.getNodesByType( Optional.of(List.of(NodeType.TOPIC)), - language, + language.orElse(Constants.DefaultLanguage), Optional.empty(), contentUri, Optional.empty(), @@ -76,7 +76,9 @@ public List getAllTopics( Optional.empty(), metadataFilters, Optional.of(false), - false); + false, + Optional.empty(), + Optional.empty()); } @Deprecated @@ -151,7 +153,7 @@ public NodeDTO getTopic( @Parameter(description = "ISO-639-1 language code", example = "nb") @RequestParam(value = "language", required = false, defaultValue = Constants.DefaultLanguage) Optional language) { - return nodeService.getNode(id, language, Optional.of(false)); + return nodeService.getNode(id, language, Optional.of(false), Optional.empty(), Optional.empty()); } @Deprecated diff --git a/src/main/java/no/ndla/taxonomy/service/NodeService.java b/src/main/java/no/ndla/taxonomy/service/NodeService.java index 077742f2..e6d5ef71 100644 --- a/src/main/java/no/ndla/taxonomy/service/NodeService.java +++ b/src/main/java/no/ndla/taxonomy/service/NodeService.java @@ -89,7 +89,7 @@ public Specification nodeHasOneOfNodeType(List nodeType) { public List getNodesByType( Optional> nodeType, - Optional language, + String language, Optional> publicIds, Optional contentUri, Optional contextId, @@ -97,7 +97,9 @@ public List getNodesByType( Optional isContext, MetadataFilters metadataFilters, Optional includeContexts, - boolean filterProgrammes) { + boolean filterProgrammes, + Optional rootId, + Optional parentId) { final List listToReturn = new ArrayList<>(); List ids; if (contextId.isPresent()) { @@ -114,6 +116,8 @@ public List getNodesByType( isContext); } final var counter = new AtomicInteger(); + var root = rootId.map(this::getNode); + var parent = parentId.map(this::getNode); ids.stream() .collect(Collectors.groupingBy(i -> counter.getAndIncrement() / 1000)) .values() @@ -121,10 +125,10 @@ public List getNodesByType( final var nodes = nodeRepository.findByIds(idChunk); var dtos = nodes.stream() .map(node -> new NodeDTO( - Optional.empty(), - Optional.empty(), + root, + parent, node, - language.get(), + language, contextId, includeContexts, filterProgrammes, @@ -162,11 +166,18 @@ public List getFilteredChildConnections(URI nodePublicId, String l return topicTreeSorter.sortList(wrappedList); } - public NodeDTO getNode(URI publicId, Optional language, Optional includeContexts) { + public NodeDTO getNode( + URI publicId, + Optional language, + Optional includeContexts, + Optional rootId, + Optional parentId) { var node = getNode(publicId); + var root = rootId.map(this::getNode); + var parent = parentId.map(this::getNode); return new NodeDTO( - Optional.empty(), - Optional.empty(), + root, + parent, node, language.orElse(Constants.DefaultLanguage), Optional.empty(), diff --git a/src/main/java/no/ndla/taxonomy/service/dtos/NodeChildDTO.java b/src/main/java/no/ndla/taxonomy/service/dtos/NodeChildDTO.java index 5a79b6bf..0bc1380d 100644 --- a/src/main/java/no/ndla/taxonomy/service/dtos/NodeChildDTO.java +++ b/src/main/java/no/ndla/taxonomy/service/dtos/NodeChildDTO.java @@ -106,11 +106,6 @@ public boolean equals(Object o) { public NodeChildDTO() {} - @Deprecated - public URI getParent() { - return parentId; - } - public URI getParentId() { return parentId; } @@ -132,11 +127,6 @@ public boolean isPrimary() { return isPrimary; } - @Deprecated - public boolean getPrimary() { - return isPrimary; - } - public void setPrimary(boolean primary) { isPrimary = primary; } diff --git a/src/test/java/no/ndla/taxonomy/domain/NodeTest.java b/src/test/java/no/ndla/taxonomy/domain/NodeTest.java index 075cbfe1..4561600a 100644 --- a/src/test/java/no/ndla/taxonomy/domain/NodeTest.java +++ b/src/test/java/no/ndla/taxonomy/domain/NodeTest.java @@ -403,7 +403,7 @@ void pickTheCorrectContext() { assertEquals(context3.contextId(), context.get().contextId()); } { - Optional context = node.pickContext(Optional.empty(), Optional.empty(), Optional.of(node)); + Optional context = node.pickContext(Optional.empty(), Optional.empty(), Optional.empty()); assertEquals(context1.contextId(), context.get().contextId()); } { diff --git a/src/test/java/no/ndla/taxonomy/rest/v1/NodesTest.java b/src/test/java/no/ndla/taxonomy/rest/v1/NodesTest.java index 34bb973e..d30672f8 100644 --- a/src/test/java/no/ndla/taxonomy/rest/v1/NodesTest.java +++ b/src/test/java/no/ndla/taxonomy/rest/v1/NodesTest.java @@ -67,6 +67,66 @@ public void can_get_single_node() throws Exception { assertTrue(node.getMetadata().isVisible()); } + @Test + void can_get_single_node_with_wanted_context() throws Exception { + Node resource = builder.node(NodeType.RESOURCE, r -> r.name("Resource").publicId("urn:resource:1")); + builder.node(NodeType.SUBJECT, s1 -> s1.isContext(true) + .name("Subject1") + .publicId("urn:subject:1") + .child( + NodeType.TOPIC, + t1 -> t1.name("Topic1").publicId("urn:topic:1").resource(resource))); + builder.node(NodeType.SUBJECT, s2 -> s2.isContext(true) + .name("Subject2") + .publicId("urn:subject:2") + .child(NodeType.TOPIC, t2 -> t2.name("Topic2") + .publicId("urn:topic:2") + .isContext(true) + .child(resource) + .child( + NodeType.TOPIC, + t3 -> t3.name("Topic3").publicId("urn:topic:3").resource(resource)))); + + // Specifying rootId and/or parentId picks wanted path + { + var response = testUtils.getResource("/v1/nodes/urn:resource:1?rootId=urn:subject:1"); + final var node = testUtils.getObject(NodeDTO.class, response); + assertEquals("Resource", node.getName()); + assertEquals(5, node.getContexts().size()); + assertEquals("/subject:1/topic:1/resource:1", node.getPath()); + } + { + var response = testUtils.getResource("/v1/nodes/urn:resource:1?parentId=urn:topic:1"); + final var node = testUtils.getObject(NodeDTO.class, response); + assertEquals("Resource", node.getName()); + assertEquals("/subject:1/topic:1/resource:1", node.getPath()); + } + { + var response = testUtils.getResource("/v1/nodes/urn:resource:1?rootId=urn:subject:2"); + final var node = testUtils.getObject(NodeDTO.class, response); + assertEquals("Resource", node.getName()); + assertEquals("/subject:2/topic:2/resource:1", node.getPath()); + } + { + var response = testUtils.getResource("/v1/nodes/urn:resource:1?rootId=urn:topic:2"); + final var node = testUtils.getObject(NodeDTO.class, response); + assertEquals("Resource", node.getName()); + assertEquals("/topic:2/resource:1", node.getPath()); + } + { + var response = testUtils.getResource("/v1/nodes/urn:resource:1?rootId=urn:topic:2&parentId=urn:topic:3"); + final var node = testUtils.getObject(NodeDTO.class, response); + assertEquals("Resource", node.getName()); + assertEquals("/topic:2/topic:3/resource:1", node.getPath()); + } + { + var response = testUtils.getResource("/v1/nodes/urn:resource:1?rootId=urn:subject:2&parentId=urn:topic:3"); + final var node = testUtils.getObject(NodeDTO.class, response); + assertEquals("Resource", node.getName()); + assertEquals("/subject:2/topic:2/topic:3/resource:1", node.getPath()); + } + } + @Test public void single_node_has_no_url() throws Exception { builder.node(NodeType.NODE, t -> t.publicId("urn:node:1")); @@ -470,7 +530,7 @@ void fetching_subnodes_uses_correct_context() throws Exception { assertAllTrue(nodes, t -> t.getPath().contains("/subject:1/topic:1")); } { - var response = testUtils.getResource("/v1/nodes/urn:topic:1/nodes?nodeType=RESOURCE"); + var response = testUtils.getResource("/v1/nodes/urn:topic:1/nodes?nodeType=RESOURCE&includeContexts=true"); final var nodes = testUtils.getObject(NodeChildDTO[].class, response); assertEquals(1, nodes.length); assertEquals("Leaf", nodes[0].getName()); From 9816ec5dc30c1b30921acf486180d2171346bc81 Mon Sep 17 00:00:00 2001 From: Gunnar Velle Date: Fri, 9 Aug 2024 15:48:25 +0200 Subject: [PATCH 2/2] Add context object for selected context. Add more params to fetching single node. --- .../java/no/ndla/taxonomy/rest/v1/Nodes.java | 8 +- .../no/ndla/taxonomy/rest/v1/Resources.java | 2 +- .../no/ndla/taxonomy/rest/v1/Subjects.java | 2 +- .../java/no/ndla/taxonomy/rest/v1/Topics.java | 2 +- .../no/ndla/taxonomy/service/NodeService.java | 7 +- .../ndla/taxonomy/service/dtos/NodeDTO.java | 85 ++++++++++--------- typescript/taxonomy-api.ts | 8 +- 7 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java b/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java index 1d8f9df1..f0f410e3 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java @@ -232,10 +232,16 @@ public NodeDTO getNode( Optional rootId, @Parameter(description = "Id to parent id in context.") @RequestParam(value = "parentId", required = false) Optional parentId, + @Parameter(name = "includeContexts", description = "Include all contexts") + @RequestParam(value = "includeContexts", required = false, defaultValue = "true") + Optional includeContexts, + @Parameter(description = "Filter out programme contexts") + @RequestParam(value = "filterProgrammes", required = false, defaultValue = "false") + boolean filterProgrammes, @Parameter(description = "ISO-639-1 language code", example = "nb") @RequestParam(value = "language", required = false, defaultValue = Constants.DefaultLanguage) Optional language) { - return nodeService.getNode(id, language, Optional.of(true), rootId, parentId); + return nodeService.getNode(id, language, rootId, parentId, includeContexts, filterProgrammes); } @PostMapping diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Resources.java b/src/main/java/no/ndla/taxonomy/rest/v1/Resources.java index 47357c0c..85c597bc 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Resources.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Resources.java @@ -169,7 +169,7 @@ public NodeDTO getResource( @Parameter(description = "ISO-639-1 language code", example = "nb") @RequestParam(value = "language", required = false, defaultValue = Constants.DefaultLanguage) Optional language) { - return nodeService.getNode(id, language, Optional.of(false), Optional.empty(), Optional.empty()); + return nodeService.getNode(id, language, Optional.empty(), Optional.empty(), Optional.of(false), false); } @Deprecated diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Subjects.java b/src/main/java/no/ndla/taxonomy/rest/v1/Subjects.java index 5250621c..a85a366f 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Subjects.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Subjects.java @@ -169,7 +169,7 @@ public NodeDTO getSubject( @Parameter(description = "ISO-639-1 language code", example = "nb") @RequestParam(value = "language", required = false, defaultValue = Constants.DefaultLanguage) Optional language) { - return nodeService.getNode(id, language, Optional.of(false), Optional.empty(), Optional.empty()); + return nodeService.getNode(id, language, Optional.empty(), Optional.empty(), Optional.of(false), false); } @Deprecated diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Topics.java b/src/main/java/no/ndla/taxonomy/rest/v1/Topics.java index 94eba885..dae41329 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Topics.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Topics.java @@ -153,7 +153,7 @@ public NodeDTO getTopic( @Parameter(description = "ISO-639-1 language code", example = "nb") @RequestParam(value = "language", required = false, defaultValue = Constants.DefaultLanguage) Optional language) { - return nodeService.getNode(id, language, Optional.of(false), Optional.empty(), Optional.empty()); + return nodeService.getNode(id, language, Optional.empty(), Optional.empty(), Optional.of(false), false); } @Deprecated diff --git a/src/main/java/no/ndla/taxonomy/service/NodeService.java b/src/main/java/no/ndla/taxonomy/service/NodeService.java index e6d5ef71..9de4f42a 100644 --- a/src/main/java/no/ndla/taxonomy/service/NodeService.java +++ b/src/main/java/no/ndla/taxonomy/service/NodeService.java @@ -169,9 +169,10 @@ public List getFilteredChildConnections(URI nodePublicId, String l public NodeDTO getNode( URI publicId, Optional language, - Optional includeContexts, Optional rootId, - Optional parentId) { + Optional parentId, + Optional includeContexts, + boolean filterProgrammes) { var node = getNode(publicId); var root = rootId.map(this::getNode); var parent = parentId.map(this::getNode); @@ -182,7 +183,7 @@ public NodeDTO getNode( language.orElse(Constants.DefaultLanguage), Optional.empty(), includeContexts, - false, + filterProgrammes, newUrlSeparator); } diff --git a/src/main/java/no/ndla/taxonomy/service/dtos/NodeDTO.java b/src/main/java/no/ndla/taxonomy/service/dtos/NodeDTO.java index b397acd9..fd354aeb 100644 --- a/src/main/java/no/ndla/taxonomy/service/dtos/NodeDTO.java +++ b/src/main/java/no/ndla/taxonomy/service/dtos/NodeDTO.java @@ -78,6 +78,10 @@ public class NodeDTO { @Schema(description = "A list of all contexts this node is part of") private List contexts = new ArrayList<>(); + @JsonProperty + @Schema(description = "The context object selected when fetching node") + private Optional context = Optional.empty(); + @Schema(description = "The language code for which name is returned", example = "nb") private String language; @@ -112,6 +116,7 @@ public NodeDTO( Optional relevance = entity.getParentConnections().stream().findFirst().flatMap(NodeConnection::getRelevance); + var relevanceName = relevance.map(LanguageField::fromNode).orElse(new LanguageField()); this.relevanceId = relevance.map(Relevance::getPublicId); this.translations = entity.getTranslations().stream() @@ -138,8 +143,8 @@ public NodeDTO( this.nodeType = entity.getNodeType(); - Optional context = entity.pickContext(contextId, parent, root); - context.ifPresent(ctx -> { + Optional selected = entity.pickContext(contextId, parent, root); + selected.ifPresent(ctx -> { this.path = ctx.path(); // TODO: this changes the content in context breadcrumbs LanguageField> breadcrumbList = @@ -156,52 +161,54 @@ public NodeDTO( ctx.contextId(), entity.getNodeType(), newUrlSeparator); + + this.context = Optional.of(getTaxonomyContextDTO(entity, newUrlSeparator, ctx, relevanceName)); }); includeContexts.filter(Boolean::booleanValue).ifPresent(includeCtx -> { - var relevanceName = new LanguageField(); - if (relevance.isPresent()) { - relevanceName = LanguageField.fromNode(relevance.get()); - } - LanguageField finalRelevanceName = relevanceName; this.contexts = entity.getContexts().stream() .filter(ctx -> !filterProgrammes || !ctx.rootId().contains(NodeType.PROGRAMME.getName())) - .map(ctx -> new TaxonomyContextDTO( - entity.getPublicId(), - URI.create(ctx.rootId()), - LanguageFieldDTO.fromLanguageField(ctx.rootName()), - ctx.path(), - LanguageFieldDTO.fromLanguageFieldList(ctx.breadcrumbs()), - entity.getContextType(), - URI.create(ctx.relevanceId()), - LanguageFieldDTO.fromLanguageField(finalRelevanceName), - entity.getResourceTypes().stream() - .sorted((o1, o2) -> { - if (o1.getParent().isEmpty()) return -1; - if (o2.getParent().isEmpty()) return 1; - return 0; - }) - .map(SearchableTaxonomyResourceType::new) - .toList(), - ctx.parentIds().stream().map(URI::create).toList(), - ctx.parentContextIds(), - ctx.isPrimary(), - ctx.isActive(), - ctx.isVisible(), - ctx.contextId(), - ctx.rank(), - ctx.connectionId(), - PrettyUrlUtil.createPrettyUrl( - Optional.of(ctx.rootName()), - LanguageField.fromNode(entity), - this.language, - ctx.contextId(), - entity.getNodeType(), - newUrlSeparator))) + .map(ctx -> getTaxonomyContextDTO(entity, newUrlSeparator, ctx, relevanceName)) .toList(); }); } + private TaxonomyContextDTO getTaxonomyContextDTO( + Node entity, boolean newUrlSeparator, TaxonomyContext ctx, LanguageField finalRelevanceName) { + return new TaxonomyContextDTO( + entity.getPublicId(), + URI.create(ctx.rootId()), + LanguageFieldDTO.fromLanguageField(ctx.rootName()), + ctx.path(), + LanguageFieldDTO.fromLanguageFieldList(ctx.breadcrumbs()), + entity.getContextType(), + URI.create(ctx.relevanceId()), + LanguageFieldDTO.fromLanguageField(finalRelevanceName), + entity.getResourceTypes().stream() + .sorted((o1, o2) -> { + if (o1.getParent().isEmpty()) return -1; + if (o2.getParent().isEmpty()) return 1; + return 0; + }) + .map(SearchableTaxonomyResourceType::new) + .toList(), + ctx.parentIds().stream().map(URI::create).toList(), + ctx.parentContextIds(), + ctx.isPrimary(), + ctx.isActive(), + ctx.isVisible(), + ctx.contextId(), + ctx.rank(), + ctx.connectionId(), + PrettyUrlUtil.createPrettyUrl( + Optional.of(ctx.rootName()), + LanguageField.fromNode(entity), + this.language, + ctx.contextId(), + entity.getNodeType(), + newUrlSeparator)); + } + public URI getId() { return id; } diff --git a/typescript/taxonomy-api.ts b/typescript/taxonomy-api.ts index a0fbb1be..79909fe5 100644 --- a/typescript/taxonomy-api.ts +++ b/typescript/taxonomy-api.ts @@ -32,6 +32,10 @@ export interface Node { baseName: string; breadcrumbs: string[]; contentUri?: string; + /** + * The context object selected when fetching node + */ + context?: TaxonomyContext; /** * An id unique for this context. */ @@ -65,10 +69,6 @@ export interface Node { export interface NodeChild extends Node { connectionId: string; isPrimary: boolean; - /** - * @deprecated - */ - parent: string; parentId: string; rank: number; }