From 1000b863df9114fe01ab9dcf1904f23392b525cd Mon Sep 17 00:00:00 2001 From: "Gantner, Florian Klaus" Date: Wed, 6 Sep 2023 13:39:01 +0200 Subject: [PATCH 1/2] orgunittree services and rest endpoints --- .../CrisLayoutOrgunittreeComponent.java | 40 ++ .../dspace/uniba/orgunittree/Orgunittree.java | 62 +++ .../uniba/orgunittree/OrgunittreeMetrics.java | 46 ++ .../OrgunittreeMetricsConfiguration.java | 54 +++ .../uniba/orgunittree/OrgunittreeNode.java | 108 +++++ .../uniba/orgunittree/OrgunittreeService.java | 415 ++++++++++++++++++ .../app/rest/OrgunittreeRestController.java | 172 ++++++++ ...isLayoutOrgunittreeComponentConverter.java | 38 ++ .../converter/OrgunittreeNodeConverter.java | 71 +++ .../link/OrgunittreeNodeHalLinkFactory.java | 49 +++ .../app/rest/model/CrisLayoutSectionRest.java | 157 +++++++ .../app/rest/model/OrgunittreeNodeRest.java | 120 +++++ .../org/dspace/app/rest/model/RestModel.java | 1 + .../hateoas/OrgunittreeNodeResource.java | 18 + .../repository/OrgunittreeRestRepository.java | 63 +++ dspace/config/modules/rest.cfg | 2 + dspace/config/spring/api/cris-sections.xml | 7 + dspace/config/spring/api/orgunittree.xml | 97 ++++ 18 files changed, 1520 insertions(+) create mode 100644 dspace-api/src/main/java/org/dspace/layout/CrisLayoutOrgunittreeComponent.java create mode 100644 dspace-api/src/main/java/org/dspace/uniba/orgunittree/Orgunittree.java create mode 100644 dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeMetrics.java create mode 100644 dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeMetricsConfiguration.java create mode 100644 dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeNode.java create mode 100644 dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeService.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/OrgunittreeRestController.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CrisLayoutOrgunittreeComponentConverter.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/OrgunittreeNodeConverter.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/link/OrgunittreeNodeHalLinkFactory.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/OrgunittreeNodeRest.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/OrgunittreeNodeResource.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/OrgunittreeRestRepository.java create mode 100644 dspace/config/spring/api/orgunittree.xml diff --git a/dspace-api/src/main/java/org/dspace/layout/CrisLayoutOrgunittreeComponent.java b/dspace-api/src/main/java/org/dspace/layout/CrisLayoutOrgunittreeComponent.java new file mode 100644 index 000000000000..21e26d6efc84 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/layout/CrisLayoutOrgunittreeComponent.java @@ -0,0 +1,40 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.layout; + +/** + * + * Implementation of {@link CrisLayoutSectionComponent} that allows definition + * of a section containing some trees or orgunits list of counters. + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + * + */ +public class CrisLayoutOrgunittreeComponent implements CrisLayoutSectionComponent { + + private String style = ""; + + private String title = ""; + + @Override + public String getStyle() { + return style; + } + + public void setStyle(String style) { + this.style = style; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/dspace-api/src/main/java/org/dspace/uniba/orgunittree/Orgunittree.java b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/Orgunittree.java new file mode 100644 index 000000000000..5cde7141cd51 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/Orgunittree.java @@ -0,0 +1,62 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.uniba.orgunittree; + +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +/** + * The OrgUnitTree model + * Contains a list of rootnodes and some hashmap of all nodes for easier access + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + * + */ +public class Orgunittree { + private Date date; + private List rootnodes = new LinkedList<>(); + + public Orgunittree() { + this.date = new Date(); + } + + public void addRoot(OrgunittreeNode node) { + if (!this.rootnodes.contains(node)) { + rootnodes.add(node); + } + } + + public List getNodes() { + return this.rootnodes; + } + + public OrgunittreeNode findNodeByUUID(UUID uuid) { + OrgunittreeNode res = null; + for (OrgunittreeNode root : rootnodes) { + if (res != null) { + return res; + } + res = recursiveSearch(uuid, root); + } + return res; + } + + private OrgunittreeNode recursiveSearch(UUID uuid,OrgunittreeNode node) { + if (node.getUuid().equals(uuid)) { + return node; + } + List children = node.getChild(); + OrgunittreeNode res = null; + for (int i = 0; res == null && i < children.size(); i++) { + res = recursiveSearch(uuid, children.get(i)); + } + return res; + } +} diff --git a/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeMetrics.java b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeMetrics.java new file mode 100644 index 000000000000..c42434b78f0f --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeMetrics.java @@ -0,0 +1,46 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.uniba.orgunittree; + +/** + * The OrgunittreeMetrics to some single orgunittreenode + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + */ +public class OrgunittreeMetrics { + + private Integer value; + + private String shortname; + + private boolean aggregated; + + public String getShortname() { + return shortname; + } + + public void setShortname(String shortname) { + this.shortname = shortname; + } + + public Integer getValue() { + return value; + } + + public void setValue(Integer value) { + this.value = value; + } + + public boolean getAggregated() { + return aggregated; + } + + public void setAggregated(boolean aggregated) { + this.aggregated = aggregated; + } +} diff --git a/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeMetricsConfiguration.java b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeMetricsConfiguration.java new file mode 100644 index 000000000000..22d2f7b08059 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeMetricsConfiguration.java @@ -0,0 +1,54 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.uniba.orgunittree; + +import java.util.ArrayList; +import java.util.List; + +/** + * The OrgUnitTreeNode Metrics configuration settings + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + * + */ +public class OrgunittreeMetricsConfiguration { + + public OrgunittreeMetricsConfiguration() { + this.filterquery = new ArrayList<>(); + } + private String shortname; + private boolean aggregate = false; + private String query; + private List filterquery; + + public void setShortname(String shortname) { + this.shortname = shortname; + } + public String getShortname() { + return this.shortname; + } + + public void setQuery(String query) { + this.query = query; + } + public String getQuery() { + return this.query; + } + public void setAggregate(boolean aggregate) { + this.aggregate = aggregate; + } + public boolean isAggregate() { + return this.aggregate; + } + public void setFilterquery(List filterquery) { + this.filterquery = filterquery; + } + public List getFilterquery() { + return this.filterquery; + } +} diff --git a/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeNode.java b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeNode.java new file mode 100644 index 000000000000..b803ddd5c067 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeNode.java @@ -0,0 +1,108 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.uniba.orgunittree; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.dspace.content.Item; +import org.dspace.util.UUIDUtils; + +/** + * The OrgUnitTreeNode Model + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + * + */ +public class OrgunittreeNode { + + public OrgunittreeNode(Item item) { + this.item = item; + this.uuid = item.getID(); + this.displayname = item.getName(); + this.childs = new ArrayList<>(); + this.child_uuid = new ArrayList<>(); + this.metrics = new HashMap<>(); + } + + private Map metrics; + private final List childs; + private final List child_uuid; + + //The item of the node + private Item item; + + //uuid of the dspace object + private UUID uuid; + //displayname (as fallback) + private String displayname; + + public void addChild(OrgunittreeNode node) { + if (!this.getChild().contains(node)) { + this.getChild().add(node); + } + } + + public void addChild_UUID(UUID id) { + if (!this.getChild_uuid().contains(id)) { + this.getChild_uuid().add(id); + } + } + + public List getChild() { + return this.childs; + } + + public UUID getUuid() { + return uuid; + } + + public String getUuidString() { + return UUIDUtils.toString(uuid); + } + + public void setUuid(UUID uuid) { + this.uuid = uuid; + } + + public String getDisplayname() { + return displayname; + } + + public void setDisplayname(String displayname) { + this.displayname = displayname; + } + + public Item getItem() { + return item; + } + + public void setItem(Item item) { + this.item = item; + } + + public Map getMetrics() { + return metrics; + } + + public void setMetrics(HashMap metrics) { + this.metrics = metrics; + } + public void addMetric(OrgunittreeMetrics node) { + if (!this.metrics.containsKey(node.getShortname())) { + this.metrics.put(node.getShortname(),node); + } + } + + public List getChild_uuid() { + return child_uuid; + } +} diff --git a/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeService.java b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeService.java new file mode 100644 index 000000000000..a354a0a2dfdd --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/uniba/orgunittree/OrgunittreeService.java @@ -0,0 +1,415 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.uniba.orgunittree; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.common.SolrDocumentList; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Item; +import org.dspace.content.logic.DefaultFilter; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.dspace.core.CrisConstants; +import org.dspace.discovery.SearchUtils; +import org.dspace.discovery.SolrSearchCore; +import org.dspace.eperson.Group; +import org.dspace.eperson.service.GroupService; +import org.dspace.util.UUIDUtils; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * The OrgunitTreeService contains all functionalities to create trees + * and their structure on given metadatafields, orders and conditions + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + * + */ +public class OrgunittreeService { + private String entity; + + private List root; + private DefaultFilter rootcondition; + private DefaultFilter generalcondition; + + private List metricsconfiguration; + private String verticalrelationfield; + + @Autowired + ItemService itemService; + + @Autowired + GroupService groupService; + + @Autowired + SolrSearchCore solrSearchCore; + + private boolean onlyAnonymous; + + public String ANONYMOUS_GROUP_SOLR; + + private static final Logger log = LogManager.getLogger(); + + //singleton instance of tree + private Orgunittree instance; + + List traversal_order = new ArrayList<>(); + + + public void setEntity(String entity) { + this.entity = entity; + } + + public void setRoot(List root) { + this.root = root; + } + + public void setMetricsconfiguration(List metricsconfiguration) { + this.metricsconfiguration = metricsconfiguration; + } + + public String getEntity() { + return entity; + } + + public List getRoot() { + return root; + } + + public List getMetricsconfiguration() { + return metricsconfiguration; + } + public void setVerticalrelationfield(String verticalrelationfield) { + this.verticalrelationfield = verticalrelationfield; + } + + public String getVerticalrelationfield() { + return verticalrelationfield; + } + + public void setRootcondition(DefaultFilter rootcondition) { + this.rootcondition = rootcondition; + } + + public DefaultFilter getRootcondition() { + return rootcondition; + } + + public void setGeneralcondition(DefaultFilter generalcondition) { + this.generalcondition = generalcondition; + } + + public DefaultFilter getGeneralcondition() { + return generalcondition; + } + + + public List getRootTree(Context context) { + if (instance == null) { + try { + instance = createTree(context); + + if (isOnlyAnonymous() && Objects.isNull(ANONYMOUS_GROUP_SOLR)) { + try { + Group a = groupService.findByName(context, Group.ANONYMOUS); + ANONYMOUS_GROUP_SOLR = 'g' + UUIDUtils.toString(a.getID()); + } catch (SQLException e) { + log.debug(e.getMessage()); + } + } + + calculateMetrics(instance); + log.info("Orgunit Tree created!"); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + List res = instance.getNodes(); + for (OrgunittreeNode r : res) { + r = reloadItem(r, context); + } + return res; + } + + public List recreateTree(Context context) { + instance = null; + log.info("deleted tree - recreate orgunittree"); + return getRootTree(context); + } + + public OrgunittreeNode getNode(Context context, UUID uuid) { + + if (instance == null) { + //recreate tree + try { + instance = createTree(context); + + if (isOnlyAnonymous() && Objects.isNull(ANONYMOUS_GROUP_SOLR)) { + try { + Group a = groupService.findByName(context, Group.ANONYMOUS); + ANONYMOUS_GROUP_SOLR = 'g' + UUIDUtils.toString(a.getID()); + } catch (SQLException e) { + log.debug(e.getMessage()); + } + } + + calculateMetrics(instance); + log.info("Orgunit Tree created!"); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + return reloadItem(instance.findNodeByUUID(uuid), context); + } + + public Orgunittree createTree(Context context) { + Orgunittree newtree = new Orgunittree(); + /* + * 1. Get all instances of dspace.entity.type getEntity() + * */ + List root = new ArrayList<>(); + List childs = new ArrayList<>(); + try { + Iterator items = + itemService.findArchivedByMetadataField(context, CrisConstants.MD_ENTITY_TYPE.toString(), getEntity()); + while (items.hasNext()) { + Item item = items.next(); + // check rootcondition + if (!getGeneralcondition().getResult(context, item)) { + continue; + } + + if (getRootcondition().getResult(context, item)) { + root.add(item); + } else { + childs.add(item); + } + } + } catch (SQLException | AuthorizeException e) { + log.debug(e.getMessage()); + } + /* + * 1. Assign the root nodes to the tree + */ + for (Item rootnode : root) { + newtree.addRoot(new OrgunittreeNode((rootnode))); + } + + /* + * 2: get all Entities which are children and append to root structure + */ + try { + List unassigned = childs; + + //Loop through list (and new list) until no further child can be added + int newadded = unassigned.size(); + while (newadded > 0) { + List tocheck = new ArrayList<>(); + newadded = 0 ; + for (Item it : unassigned) { + try { + UUID relateduuid = + UUIDUtils.fromString(itemService.getMetadataByMetadataString(it, + getVerticalrelationfield()).get(0).getAuthority()); + OrgunittreeNode nd = newtree.findNodeByUUID(relateduuid); + if (nd != null) { + OrgunittreeNode itnode = new OrgunittreeNode(it); + nd.addChild(itnode); + nd.addChild_UUID(it.getID()); + newadded++; + } else { + tocheck.add(it); + } + } catch (Exception e) { + //ignore these orgunits where some error occurs + //nor some child or parent orgunit + log.error(e.getMessage(), e); + } + } + //assign list for next loop + unassigned = tocheck; + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return newtree; + } + + private void calculateMetrics(Orgunittree newtree) { + //this is repeated for every subordinate node; + + for (OrgunittreeNode node : newtree.getNodes()) { + traversal_order = new ArrayList<>(); // new list for every root node! + visitAllNodesAndAddToList(node); + Collections.reverse(traversal_order); + for (OrgunittreeMetricsConfiguration conf : getMetricsconfiguration()) { + //performed on reveres traversal order of nodes + if (conf.isAggregate()) { + assignMetricsByAggregating(conf,traversal_order); + } else { + //perfomed on all nodes + assignMetricsBySolr(conf,node); + } + } + } + } + + /* Every node */ + private void assignMetricsBySolr(OrgunittreeMetricsConfiguration conf, OrgunittreeNode node) { + try { + OrgunittreeMetrics c = new OrgunittreeMetrics(); + int number = getQuery(conf, node.getUuidString()); + c.setValue(number); + c.setShortname(conf.getShortname()); + node.addMetric(c); + } catch (Exception e) { + log.debug(e.getMessage()); + } + // repeat for every child node and every depth until no children exist (base case) + if (!node.getChild().isEmpty()) { + for (OrgunittreeNode childnode : node.getChild()) { + assignMetricsBySolr(conf, childnode); + } + } + } + + + /* From depth to root */ + private void assignMetricsByAggregating(OrgunittreeMetricsConfiguration conf, List nodelist) { + for (OrgunittreeNode actualnode : nodelist) { + //already visited. should not occur + if (hasNodeMetrics(conf, actualnode)) { + log.error("already visited!"); + continue; + } + if (!actualnode.getChild().isEmpty()) { + //check, if some children exist. + //add values form children and sum up together + //children should already have some value + int aggregatedvalue = 0; + for (OrgunittreeNode child : actualnode.getChild()) { + if (!hasNodeMetrics(conf, child)) { + log.error("no metrics!"); + } + // add already aggregated values from childs + try { + aggregatedvalue += child.getMetrics().get(conf.getShortname()).getValue(); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + //add count from actual node! + try { + aggregatedvalue += actualnode.getMetrics().get(conf.getQuery()).getValue(); + } catch (Exception e) { + log.error(e.getMessage()); + } + addAggregatedMetrics(conf, actualnode, aggregatedvalue); + } else { + //If no child nodes, set Value + int value = 0; + try { + value += actualnode.getMetrics().get(conf.getQuery()).getValue(); + } catch (Exception e) { + log.error(e.getMessage()); + } + addAggregatedMetrics(conf, actualnode, value); + + } + } + } + + private void visitAllNodesAndAddToList(OrgunittreeNode node) { + if (!traversal_order.contains(node)) { + traversal_order.add(node); + } + if (!node.getChild().isEmpty()) { + for (OrgunittreeNode child : node.getChild()) { + visitAllNodesAndAddToList(child); + } + } + } + + private void addAggregatedMetrics( + OrgunittreeMetricsConfiguration conf, OrgunittreeNode node, int additionalnumber) { + try { + OrgunittreeMetrics c = new OrgunittreeMetrics(); + c.setValue(additionalnumber); + c.setShortname(conf.getShortname()); + c.setAggregated(true); + node.addMetric(c); + } catch (Exception e) { + log.debug(e.getMessage()); + } + } + + private boolean hasNodeMetrics(OrgunittreeMetricsConfiguration conf, OrgunittreeNode node) { + return node.getMetrics().containsKey(conf.getShortname()); + } + + private int getQuery(OrgunittreeMetricsConfiguration conf, String uuid) + throws SolrServerException, IOException { + SolrQuery sQuery; + + if (conf.getQuery() != null) { + sQuery = new SolrQuery(conf.getQuery().replaceAll("\\{0\\}", uuid)); + } else { + sQuery = new SolrQuery(); + } + sQuery.setParam("q.op","OR"); + + if (conf.getFilterquery() != null && !conf.getFilterquery().isEmpty()) { + sQuery.setFilterQueries((String[]) conf.getFilterquery().toArray()); + } + // add read condition for anonymous group! Considers "active" persons and projects + if (isOnlyAnonymous() && Objects.nonNull(ANONYMOUS_GROUP_SOLR)) { + sQuery.addFilterQuery("read:" + ANONYMOUS_GROUP_SOLR); + } + sQuery.setRows(Integer.MAX_VALUE); + sQuery.setFields(SearchUtils.RESOURCE_ID_FIELD); + QueryResponse qResp = solrSearchCore.getSolr().query(sQuery); + SolrDocumentList results = qResp.getResults(); + Long numResults = results.getNumFound(); + return numResults.intValue(); + } + + private OrgunittreeNode reloadItem(OrgunittreeNode node, Context context) { + if (node.getItem() != null) { + try { + String handle = node.getItem().getHandle(); + } catch (Exception e) { + try { + node.setItem(itemService.find(context, node.getUuid())); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + } + return node; + } + + public boolean isOnlyAnonymous() { + return onlyAnonymous; + } + + public void setOnlyAnonymous(boolean onlyAnonymous) { + this.onlyAnonymous = onlyAnonymous; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/OrgunittreeRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/OrgunittreeRestController.java new file mode 100644 index 000000000000..42fec4442aaa --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/OrgunittreeRestController.java @@ -0,0 +1,172 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dspace.app.rest.converter.ConverterService; +import org.dspace.app.rest.exception.PaginationException; +import org.dspace.app.rest.link.HalLinkService; +import org.dspace.app.rest.model.OrgunittreeNodeRest; +import org.dspace.app.rest.model.hateoas.OrgunittreeNodeResource; +import org.dspace.app.rest.repository.OrgunittreeRestRepository; +import org.dspace.app.rest.utils.Utils; +import org.dspace.services.ConfigurationService; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PagedResourcesAssembler; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.PagedModel; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * The controller for the orgunit tree endpoint + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + */ +@RestController +@RequestMapping("/api/" + OrgunittreeRestController.CATEGORY) +public class OrgunittreeRestController implements InitializingBean { + + public static final String CATEGORY = "orgunittree"; + private static final Logger log = LogManager.getLogger(); + + @Autowired + protected Utils utils; + + @Autowired + private DiscoverableEndpointsService discoverableEndpointsService; + + + @Autowired + private HalLinkService halLinkService; + + @Autowired + private ConverterService converter; + + @Autowired + private OrgunittreeRestRepository repository; + + @Autowired + protected ConfigurationService configurationService; + + @Override + public void afterPropertiesSet() throws Exception { + discoverableEndpointsService + .register(this, List.of(Link.of( + "/api/" + OrgunittreeRestController.CATEGORY, + OrgunittreeRestController.CATEGORY))); + } + + @RequestMapping(method = RequestMethod.GET) + @SuppressWarnings("unchecked") + public PagedModel getTree(HttpServletRequest request, + HttpServletResponse response, Pageable page, PagedResourcesAssembler assembler) { + if (!this.configurationService.getBooleanProperty("orgunittree.enabled")) { + response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + return null; + } + PagedModel result = null; + try { + Link link = linkTo(this.getClass(), CATEGORY, OrgunittreeNodeRest.NAME).withSelfRel(); + Page resources; + try { + Page tree = repository.findAll(page); + resources = tree.map(converter::toResource); + resources.forEach(orgunittreeNodeResource -> halLinkService.addLinks(orgunittreeNodeResource)); + } catch (PaginationException pe) { + resources = new PageImpl<>(new ArrayList<>(), page, pe.getTotal()); + } + result = assembler.toModel(resources, link); + response.setStatus(HttpServletResponse.SC_OK); + return result; + } catch (Exception e) { + log.error(e.getMessage(), e); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + return result; + } + + @RequestMapping(method = RequestMethod.GET, value = "/recreate") + @SuppressWarnings("unchecked") + @PreAuthorize("hasAuthority('ADMIN')") + public PagedModel getRecreation(HttpServletRequest request, + HttpServletResponse response, Pageable page, PagedResourcesAssembler assembler) { + if (!this.configurationService.getBooleanProperty("orgunittree.enabled")) { + response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + return null; + } + PagedModel result = null; + try { + Link link = linkTo(this.getClass(), CATEGORY, OrgunittreeNodeRest.NAME).withSelfRel(); + Page resources; + try { + Page tree = repository.RecreateAndfindAll(page); + resources = tree.map(converter::toResource); + resources.forEach(orgunittreeNodeResource -> halLinkService.addLinks(orgunittreeNodeResource)); + } catch (PaginationException pe) { + resources = new PageImpl<>(new ArrayList<>(), page, pe.getTotal()); + } + result = assembler.toModel(resources, link); + response.setStatus(HttpServletResponse.SC_OK); + return result; + } catch (Exception e) { + log.error(e.getMessage(), e); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + return result; + } + + @RequestMapping(method = RequestMethod.GET, value = "/{uuid}") + @SuppressWarnings("unchecked") + public OrgunittreeNodeResource getTreeNode(HttpServletRequest request, + HttpServletResponse response, + @PathVariable(name = "uuid", required = true) String uuid, + @RequestParam(name = "depth", required = false, defaultValue = "1") int depth) { + if (!this.configurationService.getBooleanProperty("orgunittree.enabled")) { + response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + return null; + } + OrgunittreeNodeResource result = null; + try { + UUID.fromString(uuid); + } catch (IllegalArgumentException e) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + } + try { + OrgunittreeNodeRest node = repository.findOne(UUID.fromString(uuid), depth); + result = converter.toResource(node); + Link link = linkTo(this.getClass(), CATEGORY).slash(uuid).withSelfRel(); + result.add(link); + halLinkService.addLinks(result); + response.setStatus(HttpServletResponse.SC_OK); + return result; + } catch (Exception e) { + log.error(e.getMessage(), e); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + return result; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CrisLayoutOrgunittreeComponentConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CrisLayoutOrgunittreeComponentConverter.java new file mode 100644 index 000000000000..0742ce65ee95 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CrisLayoutOrgunittreeComponentConverter.java @@ -0,0 +1,38 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter; + +import org.dspace.app.rest.model.CrisLayoutSectionRest.CrisLayoutOrgunittreeComponentRest; +import org.dspace.layout.CrisLayoutOrgunittreeComponent; +import org.dspace.layout.CrisLayoutSectionComponent; +import org.springframework.stereotype.Component; + +/** + * Implementation of {@link CrisLayoutSectionComponentConverter} for + * {@link CrisLayoutOrgunittreeComponent}. + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + */ +@Component +public class CrisLayoutOrgunittreeComponentConverter implements CrisLayoutSectionComponentConverter { + + @Override + public boolean support(CrisLayoutSectionComponent component) { + return component instanceof CrisLayoutOrgunittreeComponent; + } + + @Override + public CrisLayoutOrgunittreeComponentRest convert(CrisLayoutSectionComponent component) { + CrisLayoutOrgunittreeComponent orgunittreeComponent = (CrisLayoutOrgunittreeComponent) component; + CrisLayoutOrgunittreeComponentRest rest = new CrisLayoutOrgunittreeComponentRest(); + rest.setStyle(orgunittreeComponent.getStyle()); + rest.setTitle(orgunittreeComponent.getTitle()); + return rest; + } + +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/OrgunittreeNodeConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/OrgunittreeNodeConverter.java new file mode 100644 index 000000000000..50b0b1ec498f --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/OrgunittreeNodeConverter.java @@ -0,0 +1,71 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter; + +import java.util.Map; + +import org.dspace.app.rest.model.OrgunittreeNodeRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.uniba.orgunittree.OrgunittreeMetrics; +import org.dspace.uniba.orgunittree.OrgunittreeNode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * The OrgUnitTreeNode REST Converter + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + * + */ +@Component +public class OrgunittreeNodeConverter implements DSpaceConverter { + + // Must be loaded @Lazy, as ConverterService autowires all DSpaceConverter components + @Lazy + @Autowired + private ConverterService converter; + + @Override + public OrgunittreeNodeRest convert(OrgunittreeNode modelObject, Projection projection) { + OrgunittreeNodeRest outreeNodeRest = new OrgunittreeNodeRest(); + outreeNodeRest.setProjection(projection); + outreeNodeRest.setUuid(modelObject.getUuidString()); + try { + for (Map.Entry entry : modelObject.getMetrics().entrySet()) { + String key = (String) entry.getKey(); + OrgunittreeMetrics val = (OrgunittreeMetrics) entry.getValue(); + if (val.getAggregated()) { + outreeNodeRest.addAggregatedmetrics(key, val.getValue()); + } else { + outreeNodeRest.addMetrics(key, val.getValue()); + } + } + } catch (Exception e) { + // + } + for (OrgunittreeNode node : modelObject.getChild()) { + //convert node and add to rest object + // + outreeNodeRest.addChild(node.getUuidString()); + } + //convert the item + try { + outreeNodeRest.setItem(converter.toRest(modelObject.getItem(), projection)); + } catch (Exception e) { + // + e.printStackTrace(); + } + return outreeNodeRest; + } + + @Override + public Class getModelClass() { + return OrgunittreeNode.class; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/OrgunittreeNodeHalLinkFactory.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/OrgunittreeNodeHalLinkFactory.java new file mode 100644 index 000000000000..99d1f8a51a71 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/OrgunittreeNodeHalLinkFactory.java @@ -0,0 +1,49 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.link; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; + +import java.util.LinkedList; + +import org.atteo.evo.inflector.English; +import org.dspace.app.rest.RestResourceController; +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.model.hateoas.OrgunittreeNodeResource; +import org.springframework.data.domain.Pageable; +import org.springframework.hateoas.Link; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * This HalLinkFactory adds links to the OrgunittreeNode object + */ +@Component +public class OrgunittreeNodeHalLinkFactory + extends HalLinkFactory { + + @Override + protected void addLinks(OrgunittreeNodeResource halResource, Pageable pageable, LinkedList list) + throws Exception { + ItemRest item = halResource.getContent().getItem(); + UriComponentsBuilder uriComponentsBuilder = linkTo(getMethodOn(ItemRest.CATEGORY, ItemRest.NAME) + .findRel(null, null, ItemRest.CATEGORY, English.plural(ItemRest.NAME), + item.getId(), "", null, null)).toUriComponentsBuilder(); + String uribuilder = uriComponentsBuilder.build().toString(); + list.add(buildLink("items", uribuilder.substring(0, uribuilder.lastIndexOf("/")))); + } + + @Override + protected Class getControllerClass() { + return RestResourceController.class; + } + + protected Class getResourceClass() { + return OrgunittreeNodeResource.class; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CrisLayoutSectionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CrisLayoutSectionRest.java index a4e910e3d11a..027002f6876e 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CrisLayoutSectionRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CrisLayoutSectionRest.java @@ -10,6 +10,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonGetter; @@ -210,10 +211,14 @@ public static class CrisLayoutFacetComponentRest implements CrisLayoutSectionCom private String discoveryConfigurationName; + private String searchConfigurationName; + private String style; private Integer facetsPerRow; + private Integer maxFacetEntries; + public String getDiscoveryConfigurationName() { return discoveryConfigurationName; } @@ -246,12 +251,30 @@ public void setFacetsPerRow(Integer facetsPerRow) { public Integer getFacetsPerRow() { return facetsPerRow; } + + public String getSearchConfigurationName() { + return searchConfigurationName; + } + + public void setSearchConfigurationName(String searchConfigurationName) { + this.searchConfigurationName = searchConfigurationName; + } + + public Integer getMaxFacetEntries() { + return maxFacetEntries; + } + + public void setMaxFacetEntries(Integer maxFacetEntries) { + this.maxFacetEntries = maxFacetEntries; + } } public static class CrisLayoutSearchComponentRest implements CrisLayoutSectionComponentRest { private String discoveryConfigurationName; + private String searchFilterConfigurationName; + private String style; private String searchType; @@ -308,6 +331,14 @@ public void setDisplayTitle(boolean displayTitle) { public boolean getDisplayTitle() { return displayTitle; } + + public String getSearchFilterConfigurationName() { + return searchFilterConfigurationName; + } + + public void setSearchFilterConfigurationName(String searchFilterConfigurationName) { + this.searchFilterConfigurationName = searchFilterConfigurationName; + } } public static class CrisLayoutTextRowComponentRest implements CrisLayoutSectionComponentRest, @@ -376,6 +407,58 @@ public List getTextRows() { } } + public static class CrisLayoutLinkRowComponentRest implements CrisLayoutSectionComponentRest, + Comparable { + + private final String style; + private final String link; + private final String label; + private final String target; + private final String icon; + private final Integer order; + + public CrisLayoutLinkRowComponentRest(Integer order, String style, String link, String label, String target, + String icon) { + this.order = order; + this.style = style; + this.link = link; + this.label = label; + this.target = target; + this.icon = icon; + } + + @Override + public String getComponentType() { + return "text-link"; + } + + @Override + public String getStyle() { + return style; + } + + public String getLink() { + return link; + } + + public String getLabel() { + return label; + } + + public String getTarget() { + return target; + } + + public String getIcon() { + return icon; + } + + @Override + public int compareTo(CrisLayoutLinkRowComponentRest other) { + return this.order.compareTo(other.order); + } + } + public static class CrisLayoutCountersComponentRest implements CrisLayoutSectionComponentRest { private final String style; @@ -562,4 +645,78 @@ public String getTitleKey() { } } + public static class CrisLayoutAwardtreeComponentRest implements CrisLayoutSectionComponentRest { + + private String style; + private String title; + private Map rendering; + + @Override + public String getComponentType() { + return "awardtree"; + } + + @Override + public String getStyle() { + return style; + } + + public void setStyle(String style) { + this.style = style; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTitle() { + return this.title; + } + + public void setRendering(Map rendering) { + this.rendering = rendering; + } + + public Map getRendering() { + return this.rendering; + } + + } + + public static class CrisLayoutOrgunittreeComponentRest implements CrisLayoutSectionComponentRest { + + private String style; + private String title; + private Map rendering; + + @Override + public String getComponentType() { + return "orgunittree"; + } + + @Override + public String getStyle() { + return style; + } + + public void setStyle(String style) { + this.style = style; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTitle() { + return this.title; + } + + public void setRendering(Map rendering) { + this.rendering = rendering; + } + + public Map getRendering() { + return this.rendering; + } + } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/OrgunittreeNodeRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/OrgunittreeNodeRest.java new file mode 100644 index 000000000000..9469a4b0e3da --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/OrgunittreeNodeRest.java @@ -0,0 +1,120 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.dspace.app.rest.OrgunittreeRestController; +import org.dspace.app.rest.projection.Projection; + +/** + * The OrgUnitTreeNode REST Resource + * + * @author florian.gantner@uni-bamberg.de + * + */ +public class OrgunittreeNodeRest extends RestAddressableModel { + + public static final String NAME = "orgunittreenode"; + + public static final String CATEGORY = RestModel.ORGUNITTREE; + + private Projection projection = Projection.DEFAULT; + + private List childs = new ArrayList<>(); + private Map metrics = new HashMap<>(); + private Map aggregatedmetrics = new HashMap<>(); + private String uuid; + private ItemRest item; + + public OrgunittreeNodeRest() { + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Map getMetrics() { + return this.metrics; + } + + public void setMetrics(Map metrics) { + this.metrics = metrics; + } + + public void addMetrics(String name, Integer value) { + this.metrics.put(name, value); + } + + public void setAggregatedmetrics(Map aggregatedmetrics) { + this.aggregatedmetrics = aggregatedmetrics; + } + + public void addAggregatedmetrics(String name, Integer value) { + this.aggregatedmetrics.put(name, value); + } + + public Map getAggregatedmetrics() { + return this.aggregatedmetrics; + } + + @Override + public String getCategory() { + return CATEGORY; + } + + @Override + public Class getController() { + return OrgunittreeRestController.class; + } + + @JsonIgnore + public Projection getProjection() { + return projection; + } + + public void setProjection(Projection projection) { + this.projection = projection; + } + + + @Override + //@JsonIgnore + public String getType() { + return NAME; + } + + public ItemRest getItem() { + return item; + } + + public void setItem(ItemRest item) { + this.item = item; + } + + public List getChilds() { + return childs; + } + + public void setChild(List childs) { + this.childs = childs; + } + + public void addChild(String child) { + this.childs.add(child); + } +} + diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/RestModel.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/RestModel.java index fe9c8799311d..d3a316275fe8 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/RestModel.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/RestModel.java @@ -36,6 +36,7 @@ public interface RestModel extends Serializable { public static final String LAYOUT = "layout"; public static final String AUTHENTICATION = "authn"; public static final String TOOLS = "tools"; + public static final String ORGUNITTREE = "orgunittree"; public String getType(); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/OrgunittreeNodeResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/OrgunittreeNodeResource.java new file mode 100644 index 000000000000..4c777d955f33 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/OrgunittreeNodeResource.java @@ -0,0 +1,18 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model.hateoas; + +import org.dspace.app.rest.model.OrgunittreeNodeRest; + +public class OrgunittreeNodeResource extends HALResource { + + public OrgunittreeNodeResource(OrgunittreeNodeRest orgunittreenode) { + super(orgunittreenode); + } + +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/OrgunittreeRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/OrgunittreeRestRepository.java new file mode 100644 index 000000000000..5cea08113fa4 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/OrgunittreeRestRepository.java @@ -0,0 +1,63 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.util.List; +import java.util.UUID; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dspace.app.rest.link.HalLinkService; +import org.dspace.app.rest.model.OrgunittreeNodeRest; +import org.dspace.uniba.orgunittree.OrgunittreeNode; +import org.dspace.uniba.orgunittree.OrgunittreeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Component; + +/** + * This class' purpose is to return a REST object to the controller class. This repository handles all the + * information lookup + * that has to be done for the endpoint + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + */ +@Component(OrgunittreeNodeRest.CATEGORY + "." + OrgunittreeNodeRest.NAME) +public class OrgunittreeRestRepository extends AbstractDSpaceRestRepository { + + private static final Logger log = LogManager.getLogger(); + + @Autowired + private OrgunittreeService orgunittreeservice; + + @Autowired + private HalLinkService halLinkService; + + public Page findAll(Pageable pageable) { + List trees = orgunittreeservice.getRootTree(this.obtainContext()); + return converter.toRestPage(trees, pageable, utils.obtainProjection()); + } + + public Page findRoot(Pageable pageable) { + List trees = orgunittreeservice.getRootTree(this.obtainContext()); + return converter.toRestPage(trees, pageable, utils.obtainProjection()); + } + + public OrgunittreeNodeRest findOne(UUID uuid, int depth) { + OrgunittreeNode node = orgunittreeservice.getNode(obtainContext(), uuid); + return converter.toRest(node, utils.obtainProjection()); + } + + public Page RecreateAndfindAll(Pageable pageable) { + List trees = orgunittreeservice.recreateTree(this.obtainContext()); + return converter.toRestPage(trees, pageable, utils.obtainProjection()); + } + + +} diff --git a/dspace/config/modules/rest.cfg b/dspace/config/modules/rest.cfg index 9d2eb77be2cc..ca5997f890ff 100644 --- a/dspace/config/modules/rest.cfg +++ b/dspace/config/modules/rest.cfg @@ -87,6 +87,8 @@ rest.properties.exposed = cc.license.jurisdiction rest.properties.exposed = identifiers.item-status.register-doi rest.properties.exposed = authentication-password.domain.valid +rest.properties.exposed = orgunittree.enabled + #---------------------------------------------------------------# # These configs are used by the deprecated REST (v4-6) module # #---------------------------------------------------------------# diff --git a/dspace/config/spring/api/cris-sections.xml b/dspace/config/spring/api/cris-sections.xml index a5f8ffe9944f..1db153418748 100644 --- a/dspace/config/spring/api/cris-sections.xml +++ b/dspace/config/spring/api/cris-sections.xml @@ -177,7 +177,14 @@ + + + + + + + diff --git a/dspace/config/spring/api/orgunittree.xml b/dspace/config/spring/api/orgunittree.xml new file mode 100644 index 000000000000..7fd5163197a2 --- /dev/null +++ b/dspace/config/spring/api/orgunittree.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0588e95fa1e457c63d5f7318101e3e92904525a9 Mon Sep 17 00:00:00 2001 From: "Gantner, Florian Klaus" Date: Fri, 8 Sep 2023 17:58:07 +0200 Subject: [PATCH 2/2] fix wrong config property breaking tests --- dspace/config/local.cfg.EXAMPLE | 2 +- dspace/config/modules/rest.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace/config/local.cfg.EXAMPLE b/dspace/config/local.cfg.EXAMPLE index 78f5bad26770..e0a1bed1fbb2 100644 --- a/dspace/config/local.cfg.EXAMPLE +++ b/dspace/config/local.cfg.EXAMPLE @@ -243,7 +243,7 @@ db.schema = public # avoid trouble for such browsers (i.e. rest.cors.allowed-origins = ${dspace.ui.url}, https://samltest.id ) #rest.cors.allowed-origins = ${dspace.ui.url} -#rest.cors.bitstream-allowed-origins = ${dspace.ui.url} +#rest.cors.bitstream-allow-origins = ${dspace.ui.url} ################################################# # SPRING BOOT SETTINGS (Used by Server Webapp) # diff --git a/dspace/config/modules/rest.cfg b/dspace/config/modules/rest.cfg index ca5997f890ff..d261d8824fcd 100644 --- a/dspace/config/modules/rest.cfg +++ b/dspace/config/modules/rest.cfg @@ -136,7 +136,7 @@ rest.regex-clause = text_value ~ ? ##### Customize the REST origins allowed to retrieve the bitstreams ##### ##### default is set to pattern * - use this configuration to restrict/modify this behavior ##### This configuration doens't support the wildcard -bitstream.cors.allowed-origins = +rest.cors.bitstream-allow-origins = ##### Configure REST Report Filters #####