Skip to content

Commit

Permalink
Merge branch 'EMC-381_restructure_schema.org' into 'develop'
Browse files Browse the repository at this point in the history
Resolve EMC-381 "Restructure schema.org"

Closes EMC-381

See merge request eip/catalogue!779
  • Loading branch information
hkhan38 committed Dec 17, 2024
2 parents 4c498e4 + a484a44 commit 2d26bd7
Show file tree
Hide file tree
Showing 23 changed files with 1,181 additions and 389 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
@Template(called = "html/gemini.ftlh", whenRequestedAs = MediaType.TEXT_HTML_VALUE),
@Template(called = "xml/gemini.ftlx", whenRequestedAs = GEMINI_XML_VALUE),
@Template(called = "rdf/ttl.ftl", whenRequestedAs = RDF_TTL_VALUE),
@Template(called = "schema.org/schema.org.ftlh", whenRequestedAs = RDF_SCHEMAORG_VALUE),
@Template(called = "schema.org/schema.org.ftl", whenRequestedAs = RDF_SCHEMAORG_VALUE),
@Template(called = "rocrate/rocrate.ftl", whenRequestedAs = ROCRATE_VALUE),
@Template(called = "rocrate/rocrate_attached.ftl", whenRequestedAs = ROCRATE_ATTACHED_VALUE),
@Template(called = "ceda/ceda.ftlh", whenRequestedAs = CEDA_YAML_VALUE)
Expand Down Expand Up @@ -323,6 +323,21 @@ public long getIncomingCitationCount() {
.orElse(0);
}

public List<ResourceConstraint> getLicences() {
return Optional.ofNullable(useConstraints)
.orElseGet(Collections::emptyList)
.stream().filter(resourceConstraint -> resourceConstraint.getCode().equalsIgnoreCase("license"))
.collect(Collectors.toCollection(ArrayList::new));
}

public List<OnlineResource> getInfoLinks() {
return Optional.ofNullable(onlineResources)
.orElseGet(Collections::emptyList)
.stream()
.filter(onlineResource -> onlineResource.getFunction().equalsIgnoreCase("information"))
.collect(Collectors.toCollection(ArrayList::new));
}

private static @NonNull String convertEmail(@NonNull String email) {
return email.endsWith("@ceh.ac.uk") ? "enquiries@ceh.ac.uk" : email;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private String path(boolean isAttached, String fileId, String path){
}

@lombok.Value
public class Part {
public static class Part {
String id, type, name, encodingFormat, contentUrl;
Long bytes;
LocalDateTime lastModified;
Expand Down
6 changes: 3 additions & 3 deletions java/src/test/java/templates/DataciteTemplateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ void related() {
gemini.setUri(uri);
val jena = mock(JenaLookupService.class);
configuration.setSharedVariable("jena", jena);
val expected = expected("related-full.xml");
val expected = expected("datacite/related-full.xml");

given(jena.relationships(uri, "https://vocabs.ceh.ac.uk/eidc#supersedes")).willReturn(List.of(
Link.builder().href("https://catalogue.ceh.ac.uk/id/847463839").build()
Expand Down Expand Up @@ -140,7 +140,7 @@ void full() {
.build()
));

val expected = expected("subjects-full.xml");
val expected = expected("datacite/subjects-full.xml");

//when
val actual = template("_subjects.ftlx");
Expand Down Expand Up @@ -195,7 +195,7 @@ void full() {
custodian
));

val expected = expected("contributors-full.xml");
val expected = expected("datacite/contributors-full.xml");

//when
val actual = template("_contributors.ftlx");
Expand Down
243 changes: 243 additions & 0 deletions java/src/test/java/templates/RoCrateTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package templates;

import freemarker.template.Configuration;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import uk.ac.ceh.gateway.catalogue.citation.Citation;
import uk.ac.ceh.gateway.catalogue.gemini.*;
import uk.ac.ceh.gateway.catalogue.geometry.BoundingBox;
import uk.ac.ceh.gateway.catalogue.model.ObservedProperty;
import uk.ac.ceh.gateway.catalogue.model.ResponsibleParty;
import uk.ac.ceh.gateway.catalogue.model.Supplemental;
import uk.ac.ceh.gateway.catalogue.templateHelpers.CodeLookupService;
import uk.ac.ceh.gateway.catalogue.templateHelpers.FileDetailsService;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;

@Slf4j
@DisplayName("RO-Crate")
@ExtendWith(MockitoExtension.class)
public class RoCrateTest {

Configuration configuration;
GeminiDocument gemini;
@Mock
CodeLookupService codeLookupService;
@Mock
FileDetailsService fileDetailsService;

private void givenCodeLookupService() {
given(codeLookupService.lookup("datacite.resourceTypeGeneral", "resourceType"))
.willReturn("Resource Type");
}

private void givenFileDetailsServiceDetached(String fileId) {
given(fileDetailsService.getDetailsFor(fileId, false))
.willReturn(List.of(
new FileDetailsService.Part(fileId, "File", "name1", "text/csv", "https://example.com/name1", 12L, LocalDateTime.of(2024,12,9,15, 34)),
new FileDetailsService.Part(fileId, "File", "name2", "text/csv", "https://example.com/name2", 9832L, LocalDateTime.of(2020,5,6,23, 59))
));
}

private void givenFileDetailsServiceAttached(String fileId) {
given(fileDetailsService.getDetailsFor(fileId, true))
.willReturn(List.of(
new FileDetailsService.Part(fileId, "File", "name1", "text/csv", "data/name4", 542L, LocalDateTime.of(2024,12,9,15, 34)),
new FileDetailsService.Part(fileId, "File", "name2", "text/csv", "data/name5", 32L, LocalDateTime.of(2020,5,6,23, 59))
));
}

private GeminiDocument createGeminiDocument(String fileId) {
val gemini = new GeminiDocument();
gemini.setUri("https://example.org/id/" + fileId);
gemini.setId(fileId);
gemini.setTitle("Title");
gemini.setType("dataset");
return gemini;
}

@SneakyThrows
private String expected(String filename) {
val expected = Objects.requireNonNull(getClass().getResourceAsStream(filename));
return IOUtils.toString(expected, StandardCharsets.UTF_8);
}

@SneakyThrows
private String template(String templateFilename) {
return FreeMarkerTemplateUtils.processTemplateIntoString(
configuration.getTemplate(templateFilename),
gemini
);
}

@SneakyThrows
@BeforeEach
void init() {
configuration = new Configuration(Configuration.VERSION_2_3_33);
configuration.setDirectoryForTemplateLoading(new File("../templates"));
configuration.setSharedVariable("codes", codeLookupService);
configuration.setSharedVariable("fileDetails", fileDetailsService);
}

@Nested
@DisplayName("Attached")
class Attached {

@SneakyThrows
@Test
void rocrateAttachedMinimal() {
//given
val expected = expected("rocrate/attached-minimal.json");
val fileId = "123456789";
gemini = createGeminiDocument(fileId);
givenFileDetailsServiceAttached(fileId);

//when
val actual = template("rocrate/rocrate_attached.ftl");

//then
JSONAssert.assertEquals(expected, actual, true);
verify(fileDetailsService).getDetailsFor(fileId, true);
}
}

@Nested
@DisplayName("Detached")
class Detached {

@SneakyThrows
@Test
void rocrateMinimal() {
//given
val expected = expected("rocrate/minimal.json");
val fileId = "09837382";
gemini = createGeminiDocument(fileId);
givenFileDetailsServiceDetached(fileId);

//when
val actual = template("rocrate/rocrate.ftl");

//then
JSONAssert.assertEquals(expected, actual, true);
verify(fileDetailsService).getDetailsFor(fileId, false);
}

@SneakyThrows
@Test
void rocrateFull() {
//given
val expected = expected("rocrate/full.json");

val fileId = "882739943";
gemini = createGeminiDocument(fileId);

// partsList & partDetails
givenFileDetailsServiceDetached(fileId);

// datacite
givenCodeLookupService();
gemini.setDatacitable(true);
gemini.setCitation(Citation.builder()
.doi("10.5285/" + fileId)
.authors(List.of("Able", "Bracken", "Charles"))
.year(2020)
.title("Title")
.publisher("Publisher")
.resourceTypeGeneral("resourceType")
.build());

// resourceStatus not Deleted
gemini.setAccessLimitation(AccessLimitation.builder()
.code("Available")
.build());
gemini.setDescription("Description");
gemini.setAlternateTitles(List.of("Alternate Title 1", "Alternate Title 2"));

// creation & publication dates
gemini.setDatasetReferenceDate(DatasetReferenceDate.builder()
.creationDate(LocalDate.of(2024, 1, 28))
.publicationDate(LocalDate.of(2024, 9, 7))
.build());

// observed properties
gemini.setObservedProperty(List.of(
ObservedProperty.builder().title("observed property 1").uri("https://example.com/op/1").unitsUri("https://example.com/units/m").units("metre").build(),
ObservedProperty.builder().value("observed property 2 value").build()
));

// keywords
gemini.setKeywordsPlace(List.of(
Keyword.builder().value("Lancaster").URI("https://example.com/lacaster").build(),
Keyword.builder().value("Bangor").URI("https://example.com/bangor").build()
));

// authors and points of contact
gemini.setResponsibleParties(List.of(
ResponsibleParty.builder().role("author").individualName("Donald").email("donald@example.com").nameIdentifier("https://orcid.org/0000-1234-5678-9101").build(),
ResponsibleParty.builder().role("pointOfContact").organisationName("TMSP").email("pocs@example.com").organisationIdentifier("https://example.com/TMSP").build()
));

// incoming citations
gemini.setIncomingCitations(List.of(
Supplemental.builder().url("https://example.com/citations/0").description("description").build(),
Supplemental.builder().url("https://example.com/citations/1").build(),
Supplemental.builder().name("something else").build()
));

// temporal extents
gemini.setTemporalExtents(List.of(
TimePeriod.builder().begin("2024-02-01").end("2024-10-28").build(),
TimePeriod.builder().begin("2019-08-22").build(),
TimePeriod.builder().end("2018-11-30").build()
));

// bounding boxes
gemini.setBoundingBoxes(List.of(
BoundingBox.builder().northBoundLatitude("46.2").eastBoundLongitude("2.3").southBoundLatitude("45.7").westBoundLongitude("0.4").build(),
BoundingBox.builder().northBoundLatitude("36.8").eastBoundLongitude("48.7").southBoundLatitude("-11.6").westBoundLongitude("-120.5").build()
));

gemini.setFunding(List.of(
Funding.builder().funderName("UKRI").build(),
Funding.builder().funderName("University of Oxford").build()
));

// OGL licences
gemini.setUseConstraints(List.of(
ResourceConstraint.builder().code("license").uri("https://eidc.ceh.ac.uk/licences/OGL/plain").build()
));

// downloads
gemini.setOnlineResources(List.of(
OnlineResource.builder().function("download").url("https://example.com/download/0").build(),
OnlineResource.builder().function("order").url("https://example.com/order/1").build()
));

//when
val actual = template("rocrate/rocrate.ftl");

//then
JSONAssert.assertEquals(expected, actual, true);
verify(fileDetailsService).getDetailsFor(fileId, false);
}
}
}
69 changes: 69 additions & 0 deletions java/src/test/java/templates/SchemaDotOrgTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package templates;

import freemarker.template.Configuration;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import uk.ac.ceh.gateway.catalogue.gemini.GeminiDocument;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

@Slf4j
public class SchemaDotOrgTest {

Configuration configuration;
GeminiDocument gemini;

@SneakyThrows
private String expected(String filename) {
val expected = Objects.requireNonNull(getClass().getResourceAsStream(filename));
return IOUtils.toString(expected, StandardCharsets.UTF_8);
}

@SneakyThrows
private String template(String templateFilename) {
return FreeMarkerTemplateUtils.processTemplateIntoString(
configuration.getTemplate(templateFilename),
gemini
);
}

private GeminiDocument createGeminiDocument(String fileId) {
val gemini = new GeminiDocument();
gemini.setUri("https://example.org/id/" + fileId);
gemini.setId(fileId);
gemini.setTitle("Title");
gemini.setType("dataset");
return gemini;
}

@SneakyThrows
@BeforeEach
void init() {
configuration = new Configuration(Configuration.VERSION_2_3_33);
configuration.setDirectoryForTemplateLoading(new File("../templates"));
}

@SneakyThrows
@Test
void schemaDotOrgMinimal() {
//given
val expected = expected("schemaDotOrg/minimal.json");
val fileId = "123456789";
gemini = createGeminiDocument(fileId);

//when
val actual = template("schema.org/schema.org.ftl");
log.info(actual);

//then
JSONAssert.assertEquals(expected, actual, true);
}
}
Loading

0 comments on commit 2d26bd7

Please sign in to comment.