Skip to content

Commit

Permalink
Merge pull request 'Release v24.05' (!332) from release_24.05 into ma…
Browse files Browse the repository at this point in the history
…ster
  • Loading branch information
janvonde committed Jun 10, 2024
2 parents c9fbff5 + 661ef55 commit 65384a6
Show file tree
Hide file tree
Showing 34 changed files with 864 additions and 218 deletions.
9 changes: 7 additions & 2 deletions install/rulesets/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3608,7 +3608,7 @@
<language name="en">Page</language>
<language name="rusdml">page</language>
<language name="es">Página</language>
<allowedchildtype>area</allowedchildtype>
<!-- <allowedchildtype>area</allowedchildtype> -->
<metadata num="1m">logicalPageNumber</metadata>
<metadata num="*">_ucc_id</metadata>
<metadata num="1m">physPageNumber</metadata>
Expand Down Expand Up @@ -3638,6 +3638,10 @@
<metadata num="1m">logicalPageNumber</metadata>
<metadata num="1m">physPageNumber</metadata>
</DocStrctType>
<!-- deactivated pare area in metadata editor. Uncomment this to enable it.
If area is used, it must be used for all pages within a book.
Pages and areas cannot not be mixed within a record, otherwise the record cannot be imported into the DDB -->
<!--
<DocStrctType>
<Name>area</Name>
<language name="de">Region</language>
Expand All @@ -3648,7 +3652,8 @@
<metadata num="1o">_SHAPE</metadata>
<metadata num="1m">physPageNumber</metadata>
<metadata num="1m">logicalPageNumber</metadata>
</DocStrctType>
</DocStrctType>
-->
<DocStrctType>
<Name>BoundBook</Name>
<language name="de">Gebundenes Buch</language>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>io.goobi.workflow</groupId>
<artifactId>workflow-base</artifactId>
<version>24.04.30</version>
<version>24.05</version>
<relativePath/>
</parent>
<artifactId>workflow-core</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/de/sub/goobi/config/ConfigurationHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,10 @@ public boolean isMetsEditorShowOCRButton() {
return getLocalBoolean("showOcrButton", false);
}

public boolean isShowNamedEntityEditor() {
return getLocalBoolean("showNamedEntityEditor", false);
}

public boolean isMetsEditorDisplayFileManipulation() {
return getLocalBoolean("MetsEditorDisplayFileManipulation", false);
}
Expand Down
60 changes: 55 additions & 5 deletions src/main/java/de/sub/goobi/metadaten/AltoSaver.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang.StringUtils;
import org.goobi.beans.AltoChange;
import org.jdom2.Document;
import org.jdom2.Element;
Expand All @@ -43,7 +48,9 @@

import de.sub.goobi.helper.StorageProvider;
import de.sub.goobi.helper.XmlTools;
import lombok.extern.log4j.Log4j2;

@Log4j2
public class AltoSaver {
private static SAXBuilder sax = XmlTools.getSAXBuilder();
private static XPathFactory xFactory = XPathFactory.instance();
Expand All @@ -54,18 +61,61 @@ public static void saveAltoChanges(Path altoFile, AltoChange[] changes) throws J
}
Document doc = sax.build(altoFile.toFile());
Namespace namespace = Namespace.getNamespace("alto", doc.getRootElement().getNamespaceURI());
boolean writeTags = Arrays.stream(changes).anyMatch(change -> "setNamedEntity".equals(change.getAction()));
//first remove all tags and tagrefs. Create new Tags element if necessary
XPathExpression<Element> tagsXPath = xFactory.compile("//alto:Tags", Filters.element(), null, namespace);
Element tagsElement = tagsXPath.evaluateFirst(doc);
if (writeTags) {
if (tagsElement == null) {
int layoutIndex = doc.getRootElement().indexOf(doc.getRootElement().getChild("Layout", namespace));
tagsElement = new Element("Tags", doc.getRootElement().getNamespace());
doc.getRootElement().addContent(layoutIndex, tagsElement);
}
tagsElement.removeChildren("NamedEntityTag", namespace);
XPathExpression<Element> stringsXPath = xFactory.compile("//alto:String", Filters.element(), null, namespace);
List<Element> stringElements = stringsXPath.evaluate(doc);
stringElements.forEach(string -> string.removeAttribute("TAGREFS"));
}
int tagCounter = 0;

for (AltoChange change : changes) {
String xpath = String.format("//alto:String[@ID='%s']", change.getWordId());
XPathExpression<Element> compXpath = xFactory.compile(xpath, Filters.element(), null, namespace);
Element stringEl = compXpath.evaluateFirst(doc);
if (stringEl != null) {
stringEl.setAttribute("CONTENT", change.getValue());
Element stringEl = getWordById(doc, namespace, change.getWordId());
if ("changeContent".equals(change.getAction())) {
if (stringEl != null) {
stringEl.setAttribute("CONTENT", change.getValue());
}
} else if ("setNamedEntity".equals(change.getAction())) {
String tagId = String.format("Tag%d", ++tagCounter);
Element namedEntityTag = new Element("NamedEntityTag", doc.getRootElement().getNamespace());
namedEntityTag.setAttribute("ID", tagId);
if (StringUtils.isNotBlank(change.getEntity().getLabel())) {
namedEntityTag.setAttribute("LABEL", change.getEntity().getLabel());
}
if (StringUtils.isNotBlank(change.getEntity().getType())) {
namedEntityTag.setAttribute("TYPE", change.getEntity().getType());
}
if (StringUtils.isNotBlank(change.getEntity().getUri())) {
namedEntityTag.setAttribute("URI", change.getEntity().getUri());
}
tagsElement.addContent(namedEntityTag);
change.getWords().stream().map(id -> getWordById(doc, namespace, id)).filter(Objects::nonNull).forEach(ele -> {
String tagRefs = Optional.ofNullable(ele.getAttributeValue("TAGREFS")).orElse("").trim();
tagRefs = (tagRefs + " " + tagId).trim();
ele.setAttribute("TAGREFS", tagRefs);
});
} else {
log.error("Cannot add alto change: Unknown action {}", change.getAction());
}
}
try (OutputStream out = StorageProvider.getInstance().newOutputStream(altoFile)) {
XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
xmlOut.output(doc, out);
}
}

public static Element getWordById(Document doc, Namespace namespace, String id) {
String xpath = String.format("//alto:String[@ID='%s']", id);
XPathExpression<Element> compXpath = xFactory.compile(xpath, Filters.element(), null, namespace);
return compXpath.evaluateFirst(doc);
}
}
38 changes: 37 additions & 1 deletion src/main/java/de/sub/goobi/metadaten/Metadaten.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import org.goobi.api.display.helper.ConfigDisplayRules;
import org.goobi.api.display.helper.NormDatabase;
import org.goobi.beans.AltoChange;
import org.goobi.beans.AuthorityData;
import org.goobi.beans.ImageComment;
import org.goobi.beans.Process;
import org.goobi.beans.Processproperty;
Expand Down Expand Up @@ -1826,7 +1827,7 @@ public String XMLschreiben() {
this.myProzess.setSortHelperMetadata(zaehlen.getNumberOfUghElements(this.logicalTopstruct, CountType.METADATA));
try {
this.myProzess
.setSortHelperImages(StorageProvider.getInstance().getNumberOfFiles(Paths.get(this.myProzess.getImagesOrigDirectory(true))));
.setSortHelperImages(StorageProvider.getInstance().getNumberOfFiles(Paths.get(this.myProzess.getImagesOrigDirectory(true))));
ProcessManager.saveProcess(this.myProzess);
} catch (DAOException e) {
Helper.setFehlerMeldung("fehlerNichtSpeicherbar", e);
Expand Down Expand Up @@ -3681,6 +3682,10 @@ public void saveAlto() {
}
}

public boolean isShowNamedEntityEditor() {
return ConfigurationHelper.getInstance().isShowNamedEntityEditor();
}

public String getOcrAddress() {
int startseite = -1;
int endseite = -1;
Expand Down Expand Up @@ -5185,4 +5190,35 @@ private void readMetadataEditorExtensions() {
extension = extensions.get(0);
}
}

public String getAuthorityMetadataJSON() {
List<Person> persons =
getMyPersonen().stream().filter(p -> StringUtils.isNotBlank(p.getNormdataValue())).map(MetaPerson::getP).collect(Collectors.toList());
List<Corporate> corporates =
getCorporates().stream()
.filter(p -> StringUtils.isNotBlank(p.getNormdataValue()))
.map(MetaCorporate::getCorporate)
.collect(Collectors.toList());
List<Metadata> metadata =
getMyMetadaten().stream()
.filter(p -> StringUtils.isNotBlank(p.getNormdataValue()))
.map(MetadatumImpl::getMd)
.collect(Collectors.toList());

List<AuthorityData> authorityList = new ArrayList<>();
for (Person person : persons) {
AuthorityData data = new AuthorityData(person.getDisplayname(), person.getAuthorityURI() + person.getAuthorityValue());
authorityList.add(data);
}
for (Corporate corporate : corporates) {
AuthorityData data = new AuthorityData(corporate.getMainName(), corporate.getAuthorityURI() + corporate.getAuthorityValue());
authorityList.add(data);
}
for (Metadata md : metadata) {
AuthorityData data = new AuthorityData(md.getValue(), md.getAuthorityURI() + md.getAuthorityValue());
authorityList.add(data);
}

return new Gson().toJson(authorityList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ public Document createDocument(Process process, boolean addNamespace, boolean in
if (s.getBearbeitungsbenutzer() != null && s.getBearbeitungsbenutzer().getNachVorname() != null) {
Element user = new Element(ELEMENT_USER, namespace);
user.setText(s.getBearbeitungsbenutzer().getNachVorname());
user.setAttribute(ATTRIBUTE_LOCATION, s.getBearbeitungsbenutzer().getStandort());
stepElement.addContent(user);
}
Element editType = new Element(ELEMENT_EDITTYPE, namespace);
Expand Down
29 changes: 10 additions & 19 deletions src/main/java/org/goobi/api/rest/AuthorizationFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public class AuthorizationFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {

// first try to get basic authentication
// try to get basic authentication
String authentication = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);

// get token, decode it, check if token exists in db
Expand All @@ -82,25 +82,17 @@ public void filter(ContainerRequestContext requestContext) throws IOException {
String tokenHash = new Sha256Hash(keyName, ConfigurationHelper.getInstance().getApiTokenSalt(), 10000).toBase64();

AuthenticationToken token = UserManager.getAuthenticationToken(tokenHash);
if (token == null) {
// token does not exist, abort
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
.entity("API Token is invalid.")
.build());
return;
}
//if token exists, check if token has the permission to access the current request
String methodType = requestContext.getMethod();
String requestUri = req.getPathInfo();
for (AuthenticationMethodDescription method : token.getMethods()) {
if (method.isSelected() && methodType.equalsIgnoreCase(method.getMethodType()) && Pattern.matches(method.getUrl(), requestUri)) {
return;
if (token != null) {

//if token exists, check if token has the permission to access the current request
String methodType = requestContext.getMethod();
String requestUri = req.getPathInfo();
for (AuthenticationMethodDescription method : token.getMethods()) {
if (method.isSelected() && methodType.equalsIgnoreCase(method.getMethodType()) && Pattern.matches(method.getUrl(), requestUri)) {
return;
}
}
}
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
.entity("The API token has no access to the Goobi REST API for " + requestUri)
.build());
return;
}

// get token
Expand Down Expand Up @@ -151,7 +143,6 @@ public void filter(ContainerRequestContext requestContext) throws IOException {
try {
conf = RestConfig.getConfigForPath(pathInfo);
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
log.error(e);
}
if (conf != null && !conf.getCorsMethods().isEmpty()) {
Expand Down
70 changes: 40 additions & 30 deletions src/main/java/org/goobi/api/rest/Login.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
Expand Down Expand Up @@ -99,20 +100,25 @@ public void openIdLogin(@FormParam("error") String error, @FormParam("id_token")

// get the user by the configured claim from the JWT
String login = jwt.getClaim(config.getOIDCIdClaim()).asString();
log.debug("logging in user " + login);
User user = UserManager.getUserBySsoId(login);
if (user == null) {
userBean.setSsoError("Could not find user in Goobi database. Please contact your admin to add your SSO ID to the database.");
servletResponse.sendRedirect("/goobi/uii/logout.xhtml");
return;
if (StringUtils.isBlank(login)) {
log.error("The configured claim '{}' is not present in the response.", config.getOIDCIdClaim());
} else {
log.debug("logging in user ");
User user = UserManager.getUserBySsoId(login);
if (user == null) {
userBean.setSsoError(
"Could not find user in Goobi database. Please contact your admin to add your SSO ID to the database.");
servletResponse.sendRedirect("/goobi/uii/logout.xhtml");
return;
}
userBean.setSsoError(null);
user.lazyLoad();
userBean.setMyBenutzer(user);
userBean.setRoles(user.getAllUserRoles());
userBean.setMyBenutzer(user);
//add the user to the sessionform that holds information about all logged in users
sessionForm.updateSessionUserName(servletRequest.getSession(), user);
}
userBean.setSsoError(null);
user.lazyLoad();
userBean.setMyBenutzer(user);
userBean.setRoles(user.getAllUserRoles());
userBean.setMyBenutzer(user);
//add the user to the sessionform that holds information about all logged in users
sessionForm.updateSessionUserName(servletRequest.getSession(), user);
} else {
if (!nonce.equals(jwt.getClaim("nonce").asString())) {
log.error("nonce does not match. Not logging user in");
Expand Down Expand Up @@ -184,22 +190,26 @@ public void openIdLoginAuthFlow(@FormParam("error") String error, @FormParam("co

// get the user by the configured claim from the JWT
String login = jwt.getClaim(config.getOIDCIdClaim()).asString();
log.debug("logging in user " + login);
User user = UserManager.getUserBySsoId(login);
System.out.println("Trying to log in user with SSOID; " + login);
if (user == null) {
userBean.setSsoError(
"Could not find user in Goobi database. Please contact your admin to add your SSO ID to the database.");
servletResponse.sendRedirect("/goobi/uii/logout.xhtml");
return;
if (StringUtils.isBlank(login)) {
log.error("The configured claim '{}' is not present in the response.", config.getOIDCIdClaim());
log.error("The following are available: {}", String.join(",", jwt.getClaims().keySet()));
} else {
log.debug("logging in user ");
User user = UserManager.getUserBySsoId(login);
if (user == null) {
userBean.setSsoError(
"Could not find user in Goobi database. Please contact your admin to add your SSO ID to the database.");
servletResponse.sendRedirect("/goobi/uii/logout.xhtml");
return;
}
userBean.setSsoError(null);
user.lazyLoad();
userBean.setMyBenutzer(user);
userBean.setRoles(user.getAllUserRoles());
userBean.setMyBenutzer(user);
//add the user to the sessionform that holds information about all logged in users
sessionForm.updateSessionUserName(servletRequest.getSession(), user);
}
userBean.setSsoError(null);
user.lazyLoad();
userBean.setMyBenutzer(user);
userBean.setRoles(user.getAllUserRoles());
userBean.setMyBenutzer(user);
//add the user to the sessionform that holds information about all logged in users
sessionForm.updateSessionUserName(servletRequest.getSession(), user);
} else {
if (!nonce.equals(jwt.getClaim("nonce").asString())) {
log.error("nonce does not match. Not logging user in");
Expand Down Expand Up @@ -255,12 +265,12 @@ public String apacheHeaderLogin() throws IOException {
LoginBean userBean = Helper.getLoginBeanFromSession(servletRequest.getSession());
User user = UserManager.getUserBySsoId(ssoId);
if (user == null) {
log.debug(LoginBean.LOGIN_LOG_PREFIX + "There is no user with ssoId \"" + ssoId + "\".");
log.debug(LoginBean.LOGIN_LOG_PREFIX + "There is no user with this ssoId.");
userBean.setSsoError("Could not find user in Goobi database. Please contact your admin to add your SSO ID to the database.");
servletResponse.sendRedirect("/goobi/uii/logout.xhtml");
return "";
}
log.debug(LoginBean.LOGIN_LOG_PREFIX + "User \"" + user.getLogin() + "\" can be logged in via SSO:");
log.debug(LoginBean.LOGIN_LOG_PREFIX + "User can be logged in via SSO:");
userBean.setSsoError(null);
user.lazyLoad();
userBean.setMyBenutzer(user);
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/goobi/beans/AltoChange.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@
*/
package org.goobi.beans;

import java.util.List;

import lombok.Data;

@Data
public class AltoChange {
private String wordId;
private String action;
private String value;
private List<String> words;
private NamedEntity entity;
}
Loading

0 comments on commit 65384a6

Please sign in to comment.