Skip to content

Commit

Permalink
Set up detail pages for authorities
Browse files Browse the repository at this point in the history
See #14
  • Loading branch information
fsteeg committed Aug 17, 2017
1 parent 94166c8 commit 63cf416
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 14 deletions.
28 changes: 21 additions & 7 deletions app/controllers/HomeController.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.typesafe.config.ConfigObject;

import apps.Convert;
import models.AuthorityResource;
import modules.IndexComponent;
import play.Environment;
import play.Logger;
Expand Down Expand Up @@ -88,21 +89,33 @@ public Result api() {
controllers.routes.HomeController.search("type:CorporateBody", 0, 10, format).toString(), //
"Pagination", controllers.routes.HomeController.search("london", 50, 100, format).toString());
ImmutableMap<String, String> getSamples = ImmutableMap.of(//
"London", controllers.routes.HomeController.authority("4074335-4").toString(), //
"hbz", controllers.routes.HomeController.authority("2047974-8").toString(), //
"Goethe", controllers.routes.HomeController.authority("118540238").toString());
"London", controllers.routes.HomeController.authorityJson("4074335-4").toString(), //
"hbz", controllers.routes.HomeController.authorityJson("2047974-8").toString(), //
"Goethe", controllers.routes.HomeController.authorityJson("118540238").toString());
return ok(views.html.api.render(searchSamples, getSamples));
}

public Result authority(String id) {
public Result authorityJson(String id) {
String jsonLd = getAuthorityResource(id);
return jsonLd == null ? gnd(id) : ok(prettyJsonString(Json.parse(jsonLd))).as(config("index.content"));
}

public Result authorityHtml(String id) {
String jsonLd = getAuthorityResource(id);
JsonNode json = Json.parse(jsonLd);
AuthorityResource entity = Json.fromJson(json, AuthorityResource.class);
entity.index = index;
return ok(views.html.details.render(entity));
}

private String getAuthorityResource(String id) {
GetResponse response = index.client().prepareGet(config("index.name"), config("index.type"), id).get();
response().setHeader("Access-Control-Allow-Origin", "*");
if (!response.isExists()) {
Logger.warn("{} does not exists in index, falling back to live version from GND", id);
return gnd(id);
return null;
}
String jsonLd = response.getSourceAsString();
return ok(prettyJsonString(Json.parse(jsonLd))).as(config("index.content"));
return response.getSourceAsString();
}

public Result context() {
Expand Down Expand Up @@ -188,4 +201,5 @@ private static String prettyJsonString(JsonNode jsonNode) {
return null;
}
}

}
211 changes: 211 additions & 0 deletions app/models/AuthorityResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package models;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.lang3.tuple.Pair;
import org.elasticsearch.action.get.GetResponse;

import controllers.HomeController;
import modules.IndexComponent;
import play.Logger;

public class AuthorityResource {

private final static String DNB_PREFIX = "http://d-nb.info/gnd/";

public enum Values {
JOINED, MULTI_LINE
}

public IndexComponent index;

private String id;
private List<String> type;

public Map<String, Object> definition;
public Map<String, Object> biographicalOrHistoricalInformation;
public List<Map<String, Object>> hasGeometry;
public List<String> gndIdentifier;
public List<String> preferredName;
public List<String> variantName;
public List<String> sameAs;
public List<String> geographicAreaCode;
public List<String> relatedTerm;
public List<String> relatedPerson;
public List<String> relatedWork;
public List<String> broaderTermInstantial;
public List<String> broaderTermGeneral;
public List<String> broaderTermPartitive;
public List<String> dateOfConferenceOrEvent;
public List<String> placeOfConferenceOrEvent;
public List<String> spatialAreaOfActivity;
public List<String> dateOfEstablishment;
public List<String> placeOfBusiness;
public List<String> wikipedia;
public List<String> homepage;
public List<String> topic;
public List<String> gender;
public List<String> professionOrOccupation;
public List<String> precedingPlaceOrGeographicName;
public List<String> succeedingPlaceOrGeographicName;
public List<String> dateOfTermination;
public List<String> academicDegree;
public List<String> acquaintanceshipOrFriendship;
public List<String> familialRelationship;
public List<String> placeOfActivity;
public List<String> dateOfBirth;
public List<String> placeOfBirth;
public List<String> placeOfDeath;
public List<String> dateOfDeath;
public List<String> professionalRelationship;
public List<String> hierarchicalSuperiorOfTheCorporateBody;
public List<String> firstAuthor;
public List<String> publication;
public List<String> dateOfProduction;
public List<String> mediumOfPerformance;
public List<String> firstComposer;
public List<String> dateOfPublication;

public String getId() {
return id.substring(DNB_PREFIX.length());
}

public void setId(String id) {
this.id = id;
}

public List<String> getType() {
return type.stream().filter(t -> !t.equals("AuthorityResource")).collect(Collectors.toList());
}

public void setType(List<String> type) {
this.type = type;
}

@Override
public String toString() {
return "AuthorityResource [id=" + id + "]";
}

public String title() {
return preferredName.get(0);
}

public String subtitle() {
return getType().stream().collect(Collectors.joining("; "));
}

public List<Pair<String, String>> generalFields() {
List<Pair<String, String>> fields = new ArrayList<>();
add("Bevorzugter Name", preferredName, Values.JOINED, fields);
add("Varianter Name", variantName, Values.JOINED, fields);
add("Entitätstyp", getType(), Values.JOINED, fields);
add("GND-ID", gndIdentifier, Values.JOINED, fields);
add("Ländercode", geographicAreaCode, Values.MULTI_LINE, fields);
add("Siehe auch", sameAs != null
? sameAs.stream().filter(v -> !v.startsWith(DNB_PREFIX)).collect(Collectors.toList()) : sameAs,
Values.MULTI_LINE, fields);
return fields;
}

public List<Pair<String, String>> specialFields() {
List<Pair<String, String>> fields = new ArrayList<>();
@SuppressWarnings("unchecked")
Map<String, Object> location = hasGeometry != null
? ((List<Map<String, Object>>) hasGeometry.get(0).get("asWKT")).get(0) : null;
add("Definition", definition, Values.JOINED, fields);
add("Oberbegriff partitiv", broaderTermPartitive, Values.MULTI_LINE, fields);
add("Oberbegriff instantiell", broaderTermInstantial, Values.MULTI_LINE, fields);
add("Oberbegriff allgemein", broaderTermGeneral, Values.MULTI_LINE, fields);
add("Verwandter Begriff", relatedTerm, Values.MULTI_LINE, fields);
add("Veranstalungsdaten", dateOfConferenceOrEvent, Values.MULTI_LINE, fields);
add("Veranstaltungsort", placeOfConferenceOrEvent, Values.MULTI_LINE, fields);
add("Geographischer Wirkungsbereich", spatialAreaOfActivity, Values.MULTI_LINE, fields);
add("In Beziehung stehende Person", relatedPerson, Values.MULTI_LINE, fields);
add("Gründungsdatum", dateOfEstablishment, Values.JOINED, fields);
add("Sitz", placeOfBusiness, Values.MULTI_LINE, fields);
add("Wikipedia", wikipedia, Values.JOINED, fields);
add("Thema", topic, Values.JOINED, fields);
add("Homepage", homepage, Values.JOINED, fields);
add("Biografische oder historische Angaben", biographicalOrHistoricalInformation, Values.JOINED, fields);
add("Geschlecht", gender, Values.MULTI_LINE, fields);
add("Beruf oder Beschäftigung", professionOrOccupation, Values.MULTI_LINE, fields);
add("Vorheriges Geografikum", precedingPlaceOrGeographicName, Values.MULTI_LINE, fields);
add("Nachfolgendes Geografikum", succeedingPlaceOrGeographicName, Values.MULTI_LINE, fields);
add("Auflösungsdatum", dateOfTermination, Values.JOINED, fields);
add("Akademischer Grad", academicDegree, Values.JOINED, fields);
add("Bekannt mit", acquaintanceshipOrFriendship, Values.MULTI_LINE, fields);
add("Beziehung, Bekanntschaft, Freundschaft", familialRelationship, Values.MULTI_LINE, fields);
add("Wirkungsort", placeOfActivity, Values.MULTI_LINE, fields);
add("Geburtsdatum", dateOfBirth, Values.JOINED, fields);
add("Geburtsort", placeOfBirth, Values.JOINED, fields);
add("Sterbedatum", dateOfDeath, Values.JOINED, fields);
add("Sterbeort", placeOfDeath, Values.JOINED, fields);
add("In Beziehung stehendes Werk", relatedWork, Values.MULTI_LINE, fields);
add("Beruflich Beziehung", professionalRelationship, Values.MULTI_LINE, fields);
add("Erste Verfasserschaft", firstAuthor, Values.MULTI_LINE, fields);
add("Administrative Überordnung der Körperschaft", hierarchicalSuperiorOfTheCorporateBody, Values.MULTI_LINE,
fields);
add("Titelangabe", publication, Values.MULTI_LINE, fields);
add("Erstellungszeit", dateOfProduction, Values.MULTI_LINE, fields);
add("Besetzung im Musikbereich", mediumOfPerformance, Values.MULTI_LINE, fields);
add("Erster Komponist", firstComposer, Values.MULTI_LINE, fields);
add("Erscheinungszeit", dateOfPublication, Values.MULTI_LINE, fields);
add("Ort", location, Values.MULTI_LINE, fields);
return fields;
}

private void add(String label, Map<String, Object> map, Values joined, List<Pair<String, String>> fields) {
add(label, map != null ? map.values().stream().map(Object::toString).collect(Collectors.toList()) : null,
joined, fields);
}

private void add(String label, List<String> list, Values values, List<Pair<String, String>> result) {
if (list != null && list.size() > 0) {
switch (values) {
case JOINED: {
String value = list.stream().map(v -> process(v)).collect(Collectors.joining("; "));
result.add(Pair.of(label, value));
break;
}
case MULTI_LINE: {
result.add(Pair.of(label, process(list.get(0))));
list.subList(1, list.size()).forEach(e -> {
result.add(Pair.of("", process(e)));
});
break;
}
}
}
}

private String process(String string) {
String label = string;
String link = string;
if (string.startsWith(DNB_PREFIX)) {
label = labelFor(string.substring(DNB_PREFIX.length()));
link = string.replace(DNB_PREFIX, "/authorities/") + ".html";
if (label == null) {
label = string;
link = string;
}
}
return string.startsWith("http") ? String.format("<a href='%s'>%s</a>", link, label) : link;
}

public String labelFor(String id) {
GetResponse response = index.client()
.prepareGet(HomeController.config("index.name"), HomeController.config("index.type"), id).get();
if (!response.isExists()) {
Logger.warn("{} does not exists in index", id);
return null;
}
@SuppressWarnings("unchecked")
List<String> preferredName = (List<String>) response.getSourceAsMap().get("preferredName");
return preferredName.get(0).toString();
}

}
2 changes: 1 addition & 1 deletion app/views/api.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ <h2>Search: <code>@Html(controllers.routes.HomeController.search("text").toStrin
}
</dl>

<h2>GET by ID: <code>@Html(controllers.routes.HomeController.authority("&lt;id&gt;").toString)</code></h2>
<h2>GET by ID: <code>@Html(controllers.routes.HomeController.authorityJson("&lt;id&gt;").toString)</code></h2>

<dl>
@for((key,value) <- getSamples) {
Expand Down
29 changes: 29 additions & 0 deletions app/views/details.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@* Copyright 2017 Fabian Steeg, hbz. Licensed under the GPLv2 *@

@(resource: models.AuthorityResource)

@import play.api.libs.json._

@main("", "lobid-resources - Details") {
<div class="page-header">
<h1>@resource.title <small>&mdash; @resource.subtitle <a title="JSON-LD-Indexdaten anzeigen" href='@routes.HomeController.authorityJson(resource.getId)'><img class='json-ld-icon' src='@routes.Assets.versioned("images/json-ld.png")'></a></small></h1>
</div>
<div class="row">
<div class="col-md-@if(resource.specialFields.size==0){12}else{6} intro">
<table class='table table-striped table-condensed'>
@for(f <- resource.generalFields) {
<tr><td>@f.getLeft</td><td>@Html(f.getRight)</td>
}
</table>
</div>
@if(resource.specialFields.size>0){
<div class="col-md-6 intro">
<table class='table table-striped table-condensed'>
@for(f <- resource.specialFields) {
<tr><td>@f.getLeft</td><td>@Html(f.getRight)</td>
}
</table>
</div>
}
</div>
}
2 changes: 1 addition & 1 deletion app/views/search.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
@result_short(id:String, doc: play.api.libs.json.JsValue, i: Int = -1) = {
<tr>
<td><i class='@iconFor((doc \ "type").as[Seq[String]])' aria-hidden='true' title='@(typeFor((doc \ "type").as[Seq[String]]).toString.trim)'></i></td>
<td class='text-left'><a href='@routes.HomeController.authority(id)'>@((doc \ "preferredName").asOpt[Seq[String]].getOrElse(Seq()).head)</a></td>
<td class='text-left'><a href='@routes.HomeController.authorityHtml(id)'>@((doc \ "preferredName").asOpt[Seq[String]].getOrElse(Seq()).head)</a></td>
<td class='text-right'>@((doc \ "variantName").asOpt[Seq[String]].getOrElse(Seq()).take(3).mkString("; "))</td>
<td class='text-right'><a href='@((doc \ "id").asOpt[String].getOrElse(""))' title='DNB-Link'>@((doc \ "gndIdentifier").asOpt[Seq[String]].getOrElse(Seq()).take(1))</td>
</tr>
Expand Down
1 change: 1 addition & 0 deletions conf/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,5 @@ icons {
PlaceOrGeographicName : "fa fa-globe"
Person : "fa fa-user"
Family : "fa fa-users"
Gods : "glyphicon glyphicon-flash"
}
4 changes: 3 additions & 1 deletion conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ GET /authorities/api controllers.HomeController.api

GET /authorities/context.jsonld controllers.HomeController.context()

GET /authorities/:id.json controllers.HomeController.authority(id)
GET /authorities/:id.json controllers.HomeController.authorityJson(id)

GET /authorities/:id.html controllers.HomeController.authorityHtml(id)

GET /authorities/search controllers.HomeController.search(q ?= "*", from: Int ?= 0, size: Int ?= 10, format ?= "html")

Expand Down
Binary file added public/images/json-ld.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions test/controllers/HomeControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ public class HomeControllerTest extends WithApplication {
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] { //
{ routes.HomeController.index().toString(), Status.OK }, //
{ routes.HomeController.authority("2-4").toString(), Status.OK }, //
{ routes.HomeController.authority("1077774206").toString(), Status.OK }, //
{ routes.HomeController.authority("1072719991").toString(), Status.OK }, //
{ routes.HomeController.authorityJson("2-4").toString(), Status.OK }, //
{ routes.HomeController.authorityJson("1077774206").toString(), Status.OK }, //
{ routes.HomeController.authorityJson("1072719991").toString(), Status.OK }, //
{ routes.HomeController.search("*", 0, 10, "json").toString(), Status.OK },
{ routes.HomeController.authority("---").toString(), Status.NOT_FOUND } });
{ routes.HomeController.authorityJson("---").toString(), Status.NOT_FOUND } });
}

public HomeControllerTest(String route, int status) {
Expand Down
32 changes: 32 additions & 0 deletions test/models/ModelTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package models;

import java.io.FileNotFoundException;
import java.io.FileReader;

import org.junit.Assert;
import org.junit.Test;

import com.fasterxml.jackson.databind.JsonNode;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;

import apps.Convert;
import play.libs.Json;

public class ModelTest {

@Test
public void testModelCreation() throws FileNotFoundException {
String jsonLd = jsonLdFor("4074335-4");
JsonNode json = Json.parse(jsonLd);
AuthorityResource res = Json.fromJson(json, AuthorityResource.class);
Assert.assertNotNull(res.getId());
Assert.assertNotNull(res.getType());
}

private String jsonLdFor(String id) throws FileNotFoundException {
Model sourceModel = ModelFactory.createDefaultModel();
sourceModel.read(new FileReader("test/ttl/" + id + ".ttl"), null, "TTL");
return Convert.toJsonLd(id, sourceModel, true);
}
}

0 comments on commit 63cf416

Please sign in to comment.