In order to mitigate against the brute force attacks against Gitlab accounts, we are moving to all edu-ID Logins. We would like to remind you to link your account with your edu-id. Login will be possible only by edu-ID after November 30, 2021. Here you can find the instructions for linking your account.

If you don't have a SWITCH edu-ID, you can create one with this guide here

kind regards

This Server has been upgraded to GitLab release 14.2.6

Commit ba74b75d authored by Jonas Waeber's avatar Jonas Waeber
Browse files

Implements person facet builder.

parent 105918af
/*
* search-doc-service
* Copyright (C) 2020 Memoriav
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase
object KEYS {
const val atType = "@type"
const val ricoType = "type"
const val firstName = "firstName"
const val lastName = "lastName"
const val name = "name"
const val agentIsTargetOfCreationRelation = "agentIsTargetOfCreationRelation"
const val contributor = "contributor"
const val creator = "creator"
const val Person = "Person"
const val Instantiation = "Instantiation"
}
/*
* search-doc-service
* Copyright (C) 2020 Memoriav
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase.builders
import com.beust.klaxon.JsonObject
interface IFieldBuilder {
fun filter(jsonObject: JsonObject, map: Map<String, JsonObject>): Boolean
fun append(jsonObject: JsonObject): String
fun build(): List<String>
}
/*
* search-doc-service
* Copyright (C) 2020 Memoriav
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase.builders
import com.beust.klaxon.JsonObject
import org.memobase.KEYS
import org.memobase.helpers.AsciiFolder
import org.memobase.helpers.Extract
import org.memobase.rdf.NS
class PersonFacetBuilder(private val ricoType: String) : IFieldBuilder {
private val separator = "~"
private val terminator = "#"
private val level1 = "0"
private val level2 = "1"
private val isAlphaChar = Regex("[A-Za-z]")
private val personFacetValues = mutableSetOf<String>()
override fun filter(jsonObject: JsonObject, map: Map<String, JsonObject>): Boolean {
return if (jsonObject[KEYS.atType].let {
when (it) {
is String -> it == NS.rico + KEYS.Person
else -> false
}
}) {
val ids = Extract.identifier(jsonObject[KEYS.agentIsTargetOfCreationRelation])
ids
.map { map[it] }
.map { it?.get(KEYS.ricoType) }
.any { it != null && it is String && it == ricoType }
} else {
false
}
}
override fun append(jsonObject: JsonObject): String {
val name = when {
jsonObject.containsKey("lastName") -> {
jsonObject["lastName"] as String
}
jsonObject.containsKey("name") -> {
jsonObject["name"] as String
}
else -> {
return "Failed to process person ${jsonObject["@id"]} for person facet, because the person does not have a name."
}
}
val displayName = jsonObject["lastName"].let { lastName ->
when (lastName) {
is String -> lastName + jsonObject["firstName"].let { if (it is String) ", $it" else "" }
else -> jsonObject["name"]
}
}
val foldedName = AsciiFolder.foldToASCII(name)
val firstChar = foldedName.first { isAlphaChar.matches(it.toString()) }
val capitalLetter = firstChar.toUpperCase()
personFacetValues.add("$level1$separator$capitalLetter$separator$terminator")
personFacetValues.add("$level2$separator$capitalLetter$separator$displayName$separator$terminator")
return "Successfully added person to facet list."
}
override fun build(): List<String> {
return personFacetValues.toList().sortedBy { v -> v.substring(2) }
}
}
This diff is collapsed.
......@@ -18,6 +18,7 @@
package org.memobase.helpers
import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject
import org.apache.logging.log4j.LogManager
import org.memobase.model.CreatorNameContainer
......@@ -186,4 +187,24 @@ object Extract {
emptyList()
}
}
fun identifier(value: Any?): List<String> {
return when (value) {
is String -> listOf(value)
is JsonObject -> value["@id"].let { if (it is String) listOf(it) else emptyList() }
is JsonArray<*> ->
value.mapNotNull { item ->
when (item) {
is String -> item
is JsonObject -> value["@id"].let { id: Any? ->
if (id is String)
id
else null
}
else -> null
}
}
else -> emptyList()
}
}
}
......@@ -29,7 +29,7 @@ import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.memobase.helpers.DateFacetBuilder
import org.memobase.params.TestParam
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class Test {
......@@ -40,123 +40,6 @@ class Test {
return File("$resourcePath/$fileName").readText(Charset.defaultCharset())
}
@ParameterizedTest
@MethodSource("testDates")
fun `test date facet`(date: TestDate) {
val result = when (date.type) {
"single" ->
DateFacetBuilder.buildFromNormalizedSingleDate(date.date)
"range" ->
DateFacetBuilder.buildFromNormalizedDateRange(date.date)
else ->
emptyList()
}
assertThat(result)
.isEqualTo(date.result)
}
private fun testDates() = Stream.of(
TestDate(
"1921-09-14",
"single",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921/1922",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921-05-01/02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921-05-01/06-02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921/1931",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#", "1~20.Jahrhundert~1931-1940~#")
),
TestDate(
"1921-04-01/1931-05-02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#", "1~20.Jahrhundert~1931-1940~#")
),
TestDate(
"1921/1951",
"range",
listOf(
"0~20.Jahrhundert~",
"1~20.Jahrhundert~1921-1930~#",
"1~20.Jahrhundert~1931-1940~#",
"1~20.Jahrhundert~1941-1950~#",
"1~20.Jahrhundert~1951-1960~#"
)
),
TestDate(
"1721/1951",
"range",
listOf(
"0~18.Jahrhundert~",
"0~19.Jahrhundert~",
"0~20.Jahrhundert~",
"1~18.Jahrhundert~1721-1730~#",
"1~18.Jahrhundert~1731-1740~#",
"1~18.Jahrhundert~1741-1750~#",
"1~18.Jahrhundert~1751-1760~#",
"1~18.Jahrhundert~1761-1770~#",
"1~18.Jahrhundert~1771-1780~#",
"1~18.Jahrhundert~1781-1790~#",
"1~18.Jahrhundert~1791-1800~#",
"1~19.Jahrhundert~1801-1810~#",
"1~19.Jahrhundert~1811-1820~#",
"1~19.Jahrhundert~1821-1830~#",
"1~19.Jahrhundert~1831-1840~#",
"1~19.Jahrhundert~1841-1850~#",
"1~19.Jahrhundert~1851-1860~#",
"1~19.Jahrhundert~1861-1870~#",
"1~19.Jahrhundert~1871-1880~#",
"1~19.Jahrhundert~1881-1890~#",
"1~19.Jahrhundert~1891-1900~#",
"1~20.Jahrhundert~1901-1910~#",
"1~20.Jahrhundert~1911-1920~#",
"1~20.Jahrhundert~1921-1930~#",
"1~20.Jahrhundert~1931-1940~#",
"1~20.Jahrhundert~1941-1950~#",
"1~20.Jahrhundert~1951-1960~#"
)
),
TestDate(
"1721/1822",
"range",
listOf(
"0~18.Jahrhundert~",
"0~19.Jahrhundert~",
"1~18.Jahrhundert~1721-1730~#",
"1~18.Jahrhundert~1731-1740~#",
"1~18.Jahrhundert~1741-1750~#",
"1~18.Jahrhundert~1751-1760~#",
"1~18.Jahrhundert~1761-1770~#",
"1~18.Jahrhundert~1771-1780~#",
"1~18.Jahrhundert~1781-1790~#",
"1~18.Jahrhundert~1791-1800~#",
"1~19.Jahrhundert~1801-1810~#",
"1~19.Jahrhundert~1811-1820~#",
"1~19.Jahrhundert~1821-1830~#"
)
)
)
@ParameterizedTest
@MethodSource("testParams")
fun `integration tests`(params: TestParam) {
......
/*
* search-doc-service
* Copyright (C) 2020 Memoriav
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase
import com.beust.klaxon.json
import java.util.stream.Stream
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.memobase.builders.PersonFacetBuilder
import org.memobase.helpers.DateFacetBuilder
import org.memobase.params.PersonFacetBuilderParams
import org.memobase.params.TestDate
import org.memobase.rdf.NS
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestFacetBuilders {
@ParameterizedTest
@MethodSource("testPersons")
fun `test person facet builder`(params: PersonFacetBuilderParams) {
val builder = PersonFacetBuilder(params.ricoType)
if (builder.filter(params.source, params.map)) {
val log = builder.append(params.source)
val result = builder.build()
assertAll("",
{ assertThat(log).isEqualTo(params.log) },
{ assertThat(params.result).containsAll(result) }
)
} else {
assertThat(params.source)
.hasEntrySatisfying("@type") { value -> value.let { if (it is String) NS.rico + "Person" == it else false } }
}
}
private fun testPersons() = Stream.of(
PersonFacetBuilderParams(
json { obj(Pair("@type", NS.rico + "Record")) },
mapOf(),
"",
"",
emptyList()
),
PersonFacetBuilderParams(
json {
obj(
Pair(KEYS.atType, NS.rico + "Person"),
Pair(KEYS.name, "Einstein, Albert"),
Pair(KEYS.agentIsTargetOfCreationRelation, "identifier")
)
},
mapOf(Pair("identifier", json { obj(Pair(KEYS.ricoType, KEYS.creator)) })),
KEYS.creator,
"Successfully added person to facet list.",
listOf(
"0~E~#",
"1~E~Einstein, Albert~#"
)
),
PersonFacetBuilderParams(
json {
obj(
Pair("@type", NS.rico + "Person"),
Pair(KEYS.name, "Albert Einstein"),
Pair(KEYS.lastName, "Einstein"),
Pair(KEYS.agentIsTargetOfCreationRelation, "identifier")
)
},
mapOf(Pair("identifier", json { obj(Pair(KEYS.ricoType, KEYS.contributor)) })),
KEYS.contributor,
"Successfully added person to facet list.",
listOf(
"0~E~#",
"1~E~Einstein~#"
)
)
)
@Test
fun `test multiple person facet builder`() {
val builder = PersonFacetBuilder("creator")
builder.append(json {
obj(
Pair(KEYS.atType, NS.rico + "Person"),
Pair(KEYS.name, "Einstein, Albert"),
Pair(KEYS.agentIsTargetOfCreationRelation, "identifier")
)
})
builder.append(json {
obj(
Pair(KEYS.atType, NS.rico + "Person"),
Pair(KEYS.name, "Albert, Einstein"),
Pair(KEYS.agentIsTargetOfCreationRelation, "identifier")
)
})
val result = builder.build()
assertThat(result)
.isSortedAccordingTo { s, s2 -> s.substring(2).compareTo(s2.substring(2)) }
.containsAll(
listOf(
"0~A~#", "1~A~Albert, Einstein~#", "0~E~#", "1~E~Einstein, Albert~#"
)
)
}
@ParameterizedTest
@MethodSource("testDates")
fun `test date facet`(date: TestDate) {
val result = when (date.type) {
"single" ->
DateFacetBuilder.buildFromNormalizedSingleDate(date.date)
"range" ->
DateFacetBuilder.buildFromNormalizedDateRange(date.date)
else ->
emptyList()
}
Assertions.assertThat(result)
.isEqualTo(date.result)
}
private fun testDates() = Stream.of(
TestDate(
"1921-09-14",
"single",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921/1922",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921-05-01/02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921-05-01/06-02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921/1931",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#", "1~20.Jahrhundert~1931-1940~#")
),
TestDate(
"1921-04-01/1931-05-02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#", "1~20.Jahrhundert~1931-1940~#")
),
TestDate(
"1921/1951",
"range",
listOf(
"0~20.Jahrhundert~",
"1~20.Jahrhundert~1921-1930~#",
"1~20.Jahrhundert~1931-1940~#",
"1~20.Jahrhundert~1941-1950~#",
"1~20.Jahrhundert~1951-1960~#"
)
),
TestDate(
"1721/1951",
"range",
listOf(
"0~18.Jahrhundert~",
"0~19.Jahrhundert~",
"0~20.Jahrhundert~",
"1~18.Jahrhundert~1721-1730~#",
"1~18.Jahrhundert~1731-1740~#",
"1~18.Jahrhundert~1741-1750~#",
"1~18.Jahrhundert~1751-1760~#",
"1~18.Jahrhundert~1761-1770~#",
"1~18.Jahrhundert~1771-1780~#",
"1~18.Jahrhundert~1781-1790~#",
"1~18.Jahrhundert~1791-1800~#",
"1~19.Jahrhundert~1801-1810~#",
"1~19.Jahrhundert~1811-1820~#",
"1~19.Jahrhundert~1821-1830~#",
"1~19.Jahrhundert~1831-1840~#",
"1~19.Jahrhundert~1841-1850~#",
"1~19.Jahrhundert~1851-1860~#",
"1~19.Jahrhundert~1861-1870~#",
"1~19.Jahrhundert~1871-1880~#",
"1~19.Jahrhundert~1881-1890~#",
"1~19.Jahrhundert~1891-1900~#",
"1~20.Jahrhundert~1901-1910~#",
"1~20.Jahrhundert~1911-1920~#",
"1~20.Jahrhundert~1921-1930~#",
"1~20.Jahrhundert~1931-1940~#",
"1~20.Jahrhundert~1941-1950~#",
"1~20.Jahrhundert~1951-1960~#"
)
),
TestDate(
"1721/1822",
"range",
listOf(
"0~18.Jahrhundert~",
"0~19.Jahrhundert~",
"1~18.Jahrhundert~1721-1730~#",
"1~18.Jahrhundert~1731-1740~#",
"1~18.Jahrhundert~1741-1750~#",
"1~18.Jahrhundert~1751-1760~#",
"1~18.Jahrhundert~1761-1770~#",
"1~18.Jahrhundert~1771-1780~#",
"1~18.Jahrhundert~1781-1790~#",
"1~18.Jahrhundert~1791-1800~#",
"1~19.Jahrhundert~1801-1810~#",
"1~19.Jahrhundert~1811-1820~#",
"1~19.Jahrhundert~1821-1830~#"
)
)
)
}
/*
* search-doc-service
* Copyright (C) 2020 Memoriav
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase.params
import com.beust.klaxon.JsonObject
data class PersonFacetBuilderParams(
val source: JsonObject,
val map: Map<String, JsonObject>,
val ricoType: String,
val log: String,
val result: List<String>
)
......@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase
package org.memobase.params
data class TestDate(
val date: String,
......
......@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase