diff --git a/src/main/java/no/ndla/taxonomy/domain/Context.java b/src/main/java/no/ndla/taxonomy/domain/Context.java index f9d77e83..b89087cc 100644 --- a/src/main/java/no/ndla/taxonomy/domain/Context.java +++ b/src/main/java/no/ndla/taxonomy/domain/Context.java @@ -25,7 +25,8 @@ * @param isActive Metadata from node. True if subjectCategory is active or otherResources. * @param isPrimary Is this context marked as primary. From nodeConnection. * @param relevanceId ID of relevance. From nodeConnection. - * @param contextId Hash of root publicId + nodeConnection publicId. Unique for this context. + * @param hash Hash of parent contextId + nodeConnection publicId. Unique for this context. + * @param contextId Short form of hash. * @param rank The rank of the context. From nodeConnection. * @param connectionId The id of the connection. From nodeConnection. */ @@ -41,6 +42,7 @@ public record Context( boolean isActive, boolean isPrimary, String relevanceId, + String hash, String contextId, int rank, String connectionId) {} diff --git a/src/main/java/no/ndla/taxonomy/domain/Version.java b/src/main/java/no/ndla/taxonomy/domain/Version.java index b10236ad..43822f6b 100644 --- a/src/main/java/no/ndla/taxonomy/domain/Version.java +++ b/src/main/java/no/ndla/taxonomy/domain/Version.java @@ -41,7 +41,7 @@ public class Version extends DomainEntity { public Version() { setPublicId(URI.create("urn:version:" + UUID.randomUUID())); - this.hash = HashUtil.shortHash(getPublicId()); + this.hash = new HashUtil(getPublicId(), "").shortHash(); this.created = Instant.now(); } diff --git a/src/main/java/no/ndla/taxonomy/service/ContextUpdaterServiceImpl.java b/src/main/java/no/ndla/taxonomy/service/ContextUpdaterServiceImpl.java index 5dc0804b..7c7e94ce 100644 --- a/src/main/java/no/ndla/taxonomy/service/ContextUpdaterServiceImpl.java +++ b/src/main/java/no/ndla/taxonomy/service/ContextUpdaterServiceImpl.java @@ -30,6 +30,7 @@ private Set createContexts(Node node) { .matches(String.format("%s|%s|%s", Constants.Active, Constants.Beta, Constants.OtherResources)); // This entity can be root path if (node.isContext()) { + var hash = new HashUtil(node.getPublicId(), ""); returnedContexts.add(new Context( node.getPublicId().toString(), LanguageField.fromNode(node), @@ -41,7 +42,8 @@ private Set createContexts(Node node) { activeContext, true, "urn:relevance:core", - HashUtil.semiHash(node.getPublicId()), + hash.fullHash(), + hash.semiHash(), 0, "")); } @@ -56,6 +58,7 @@ private Set createContexts(Node node) { parentContext.breadcrumbs(), LanguageField.fromNode(parent)); List parentIds = parentContext.parentIds(); parentIds.add(parent.getPublicId().toString()); + var hash = new HashUtil(parentContext.contextId(), parentConnection.getPublicId()); return new Context( parentContext.rootId(), parentContext.rootName(), @@ -71,7 +74,8 @@ private Set createContexts(Node node) { .flatMap(relevance -> Optional.of( relevance.getPublicId().toString())) .orElse("urn:relevance:core"), - HashUtil.semiHash(parentContext.rootId() + parentConnection.getPublicId()), + hash.fullHash(), + hash.semiHash(), parentConnection.getRank(), parentConnection.getPublicId().toString()); }) 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 0adf60db..fa9309ce 100644 --- a/src/main/java/no/ndla/taxonomy/service/dtos/NodeDTO.java +++ b/src/main/java/no/ndla/taxonomy/service/dtos/NodeDTO.java @@ -220,6 +220,7 @@ public Set getResourceTypes() { return resourceTypes; } + @JsonProperty public Set getSupportedLanguages() { return supportedLanguages; } diff --git a/src/main/java/no/ndla/taxonomy/util/HashUtil.java b/src/main/java/no/ndla/taxonomy/util/HashUtil.java index d3444989..03ce9e82 100644 --- a/src/main/java/no/ndla/taxonomy/util/HashUtil.java +++ b/src/main/java/no/ndla/taxonomy/util/HashUtil.java @@ -13,29 +13,38 @@ * Util for generating hashes in different lengths */ public class HashUtil { - private static String generateHash(Object original, int length) { - String hash = new DigestUtils("SHA3-256").digestAsHex(original.toString()); - if (length > 0) return hash.substring(0, length); - return hash; + + private final String hash; + + public HashUtil(Object parentId, Object connectionId) { + this.hash = generateHash(parentId, connectionId); + } + + public HashUtil(String hash) { + this.hash = hash; + } + + public String shortHash() { + return hash.substring(0, 4); } - public static String shortHash(Object original) { - return generateHash(original, 4); + public String mediumHash() { + return hash.substring(0, 8); } - public static String mediumHash(Object original) { - return generateHash(original, 8); + public String semiHash() { + return hash.substring(0, 12); } - public static String semiHash(Object original) { - return generateHash(original, 12); + public String longHash() { + return hash.substring(0, 16); } - public static String longHash(Object original) { - return generateHash(original, 16); + public String fullHash() { + return hash; } - public static String fullHash(Object original) { - return generateHash(original, 0); + private String generateHash(Object part1, Object part2) { + return new DigestUtils("SHA3-256").digestAsHex(part1.toString() + part2.toString()); } } diff --git a/src/main/resources/db-master-changelog.xml b/src/main/resources/db-master-changelog.xml index 867a4ae0..4185a508 100644 --- a/src/main/resources/db-master-changelog.xml +++ b/src/main/resources/db-master-changelog.xml @@ -1479,4 +1479,13 @@ + + + UPDATE node + SET contexts = ( + SELECT jsonb_agg(jsonb_set(obj, '{hash}', to_jsonb(obj->>'contextId'), true)) + FROM jsonb_array_elements(contexts) AS obj + ) + + diff --git a/src/test/java/no/ndla/taxonomy/domain/NodeTest.java b/src/test/java/no/ndla/taxonomy/domain/NodeTest.java index 980c150a..b5d62ecf 100644 --- a/src/test/java/no/ndla/taxonomy/domain/NodeTest.java +++ b/src/test/java/no/ndla/taxonomy/domain/NodeTest.java @@ -333,6 +333,7 @@ void pickTheCorrectContext() { true, "urn:relevance:core", "1", + "1", 0, "urn:connection1"); var context2 = new Context( @@ -349,6 +350,7 @@ void pickTheCorrectContext() { true, "urn:relevance:core", "2", + "2", 0, "urn:connection2"); var context3 = new Context( @@ -365,6 +367,7 @@ void pickTheCorrectContext() { true, "urn:relevance:core", "3", + "3", 0, "urn:connection3"); diff --git a/src/test/java/no/ndla/taxonomy/rest/v1/QueryTest.java b/src/test/java/no/ndla/taxonomy/rest/v1/QueryTest.java index bc6a2e8e..b61aed84 100644 --- a/src/test/java/no/ndla/taxonomy/rest/v1/QueryTest.java +++ b/src/test/java/no/ndla/taxonomy/rest/v1/QueryTest.java @@ -17,7 +17,6 @@ import no.ndla.taxonomy.rest.v1.dtos.searchapi.LanguageFieldDTO; import no.ndla.taxonomy.rest.v1.dtos.searchapi.TaxonomyContextDTO; import no.ndla.taxonomy.service.dtos.NodeDTO; -import no.ndla.taxonomy.util.HashUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockHttpServletResponse; @@ -402,14 +401,10 @@ public void that_contexts_can_be_found_by_path() throws Exception { .contentUri("urn:article:1") .publicId("urn:resource:1")))); Node resource = nodeRepository.getByPublicId(URI.create("urn:resource:1")); - String hash = HashUtil.semiHash(root.getPublicId().toString() - + resource.getParentConnections().stream() - .findFirst() - .get() - .getPublicId() - .toString()); - - var response = testUtils.getResource("/v1/queries/path?path=" + String.format("/one-fine-resource__%s", hash)); + var response = testUtils.getResource("/v1/queries/path?path=" + + String.format( + "/one-fine-resource__%s", + resource.getContexts().stream().findFirst().get().contextId())); var result = testUtils.getObject(TaxonomyContextDTO[].class, response); assertEquals(1, result.length); diff --git a/src/test/java/no/ndla/taxonomy/util/HashUtilTest.java b/src/test/java/no/ndla/taxonomy/util/HashUtilTest.java index 21132836..d9589ad2 100644 --- a/src/test/java/no/ndla/taxonomy/util/HashUtilTest.java +++ b/src/test/java/no/ndla/taxonomy/util/HashUtilTest.java @@ -15,11 +15,11 @@ public class HashUtilTest { @Test public void get_different_length_hashes() { - String shortHash = HashUtil.shortHash("original"); - String mediumHash = HashUtil.mediumHash("original"); - String semiHash = HashUtil.semiHash("original"); - String longHash = HashUtil.longHash("original"); - String fullHash = HashUtil.fullHash("original"); + String shortHash = new HashUtil("original", "").shortHash(); + String mediumHash = new HashUtil("original", "").mediumHash(); + String semiHash = new HashUtil("original", "").semiHash(); + String longHash = new HashUtil("original", "").longHash(); + String fullHash = new HashUtil("original", "").fullHash(); assertEquals(4, shortHash.length()); assertEquals(8, mediumHash.length()); @@ -30,9 +30,9 @@ public void get_different_length_hashes() { @Test public void same_string_gives_same_hashes() { - String hash1 = HashUtil.mediumHash("original"); - String hash2 = HashUtil.mediumHash("original"); - String hash3 = HashUtil.longHash("original"); + String hash1 = new HashUtil("original", "").mediumHash(); + String hash2 = new HashUtil("original", "").mediumHash(); + String hash3 = new HashUtil("original", "").longHash(); assertEquals(hash1, hash2); assertTrue(hash3.startsWith(hash2)); }