diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java index 4b741847a8..57c3b83ee7 100644 --- a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java +++ b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java @@ -128,7 +128,7 @@ public class ItemCountDAOSolr implements ItemCountDAO { DiscoverResult sResponse = null; try { - sResponse = searcher.search(context, query, false); + sResponse = searcher.search(context, query); List commCount = sResponse.getFacetResult("location.comm"); List collCount = sResponse.getFacetResult("location.coll"); for (FacetResult c : commCount) { diff --git a/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java b/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java index ae491ad935..087ec42774 100644 --- a/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java +++ b/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java @@ -169,9 +169,6 @@ public class SolrBrowseDAO implements BrowseDAO { private DiscoverResult sResponse = null; - private boolean itemsWithdrawn = false; - private boolean itemsDiscoverable = true; - private boolean showFrequencies; private DiscoverResult getSolrResponse() throws BrowseException { @@ -217,8 +214,7 @@ public class SolrBrowseDAO implements BrowseDAO { } } try { - sResponse = searcher.search(context, query, itemsWithdrawn - || !itemsDiscoverable); + sResponse = searcher.search(context, query); } catch (SearchServiceException e) { throw new BrowseException(e); } @@ -227,21 +223,14 @@ public class SolrBrowseDAO implements BrowseDAO { } private void addStatusFilter(DiscoverQuery query) { - if (itemsWithdrawn) { - query.addFilterQueries("withdrawn:true"); - } else if (!itemsDiscoverable) { - query.addFilterQueries("discoverable:false"); - // TODO - - try { - if (!authorizeService.isAdmin(context) - && (authorizeService.isCommunityAdmin(context) - || authorizeService.isCollectionAdmin(context))) { - query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context)); - } - } catch (SQLException ex) { - log.error(ex); + try { + if (!authorizeService.isAdmin(context) + && (authorizeService.isCommunityAdmin(context) + || authorizeService.isCollectionAdmin(context))) { + query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context)); } + } catch (SQLException ex) { + log.error("Error looking up authorization rights of current user", ex); } } @@ -363,10 +352,9 @@ public class SolrBrowseDAO implements BrowseDAO { query.setQuery("bi_" + column + "_sort" + ": {\"" + value + "\" TO *]"); query.addFilterQueries("-(bi_" + column + "_sort" + ":" + value + "*)"); } - boolean includeUnDiscoverable = itemsWithdrawn || !itemsDiscoverable; DiscoverResult resp = null; try { - resp = searcher.search(context, query, includeUnDiscoverable); + resp = searcher.search(context, query); } catch (SearchServiceException e) { throw new BrowseException(e); } @@ -693,11 +681,6 @@ public class SolrBrowseDAO implements BrowseDAO { */ @Override public void setTable(String table) { - if (table.equals(BrowseIndex.getWithdrawnBrowseIndex().getTableName())) { - itemsWithdrawn = true; - } else if (table.equals(BrowseIndex.getPrivateBrowseIndex().getTableName())) { - itemsDiscoverable = false; - } facetField = table; } diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java index 78d65800b1..83e91a2d7b 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java @@ -14,6 +14,8 @@ import java.util.Iterator; import java.util.List; import java.util.UUID; +import javax.annotation.Nullable; + import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; @@ -462,7 +464,9 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp return bitstreamDAO.getNotReferencedBitstreams(context); } - public Long getLastModified(Bitstream bitstream) { + @Nullable + @Override + public Long getLastModified(Bitstream bitstream) throws IOException { return bitstreamStorageService.getLastModified(bitstream); } } diff --git a/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java b/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java index 87f380cbca..4250041b5d 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java @@ -14,6 +14,8 @@ import java.util.Iterator; import java.util.List; import java.util.UUID; +import javax.annotation.Nullable; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; @@ -222,5 +224,13 @@ public interface BitstreamService extends DSpaceObjectService, DSpace List getNotReferencedBitstreams(Context context) throws SQLException; - public Long getLastModified(Bitstream bitstream); + /** + * Gets the last modified timestamp of the the given bitstream's content, if known. + * + * @param bitstream the bitstream. + * @return the timestamp in milliseconds, or {@code null} if unknown. + * @throws IOException if an unexpected io error occurs. + */ + @Nullable + Long getLastModified(Bitstream bitstream) throws IOException; } diff --git a/dspace-api/src/main/java/org/dspace/discovery/SearchService.java b/dspace-api/src/main/java/org/dspace/discovery/SearchService.java index 596e784bf7..31b114fb33 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SearchService.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SearchService.java @@ -51,29 +51,6 @@ public interface SearchService { DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery query) throws SearchServiceException; - /** - * @param context DSpace Context object. - * @param query the discovery query object. - * @param includeWithdrawn use true to include in the results also withdrawn - * items that match the query. - * @return discovery search result object - * @throws SearchServiceException if search error - */ - DiscoverResult search(Context context, DiscoverQuery query, - boolean includeWithdrawn) throws SearchServiceException; - - /** - * @param context DSpace Context object - * @param dso a DSpace Object to use as scope of the search (only results - * within this object) - * @param query the discovery query object - * @param includeWithdrawn use true to include in the results also withdrawn - * items that match the query - * @return discovery search result object - * @throws SearchServiceException if search error - */ - DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery query, boolean includeWithdrawn) - throws SearchServiceException; List search(Context context, String query, String orderfield, boolean ascending, int offset, int max, String... filterquery); diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java index 00865f919c..1d05425bdf 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java @@ -561,29 +561,40 @@ public class SolrServiceImpl implements SearchService, IndexingService { // Query for all indexed Items, Collections and Communities, // returning just their handle query.setFields(HANDLE_FIELD, RESOURCE_UNIQUE_ID, RESOURCE_ID_FIELD, RESOURCE_TYPE_FIELD); + query.addSort(RESOURCE_UNIQUE_ID, SolrQuery.ORDER.asc); query.setQuery(RESOURCE_TYPE_FIELD + ":" + type); - QueryResponse rsp = getSolr().query(query, SolrRequest.METHOD.POST); - SolrDocumentList docs = rsp.getResults(); - Iterator iter = docs.iterator(); - while (iter.hasNext()) { + // Get the total amount of results + QueryResponse totalResponse = getSolr().query(query); + long total = totalResponse.getResults().getNumFound(); - SolrDocument doc = (SolrDocument) iter.next(); + int start = 0; + int batch = 100; - String uniqueID = (String) doc.getFieldValue(RESOURCE_UNIQUE_ID); + query.setRows(batch); + while (start < total) { + query.setStart(start); + QueryResponse rsp = getSolr().query(query, SolrRequest.METHOD.POST); + SolrDocumentList docs = rsp.getResults(); - IndexableObject o = findIndexableObject(context, doc); + for (SolrDocument doc : docs) { + String uniqueID = (String) doc.getFieldValue(RESOURCE_UNIQUE_ID); - if (o == null) { - log.info("Deleting: " + uniqueID); - /* - * Use IndexWriter to delete, its easier to manage - * write.lock - */ - unIndexContent(context, uniqueID); - } else { - log.debug("Keeping: " + o.getUniqueIndexID()); + IndexableObject o = findIndexableObject(context, doc); + + if (o == null) { + log.info("Deleting: " + uniqueID); + /* + * Use IndexWriter to delete, its easier to manage + * write.lock + */ + unIndexContent(context, uniqueID); + } else { + log.debug("Keeping: " + o.getUniqueIndexID()); + } } + + start += batch; } } } catch (Exception e) { @@ -1855,21 +1866,10 @@ public class SolrServiceImpl implements SearchService, IndexingService { } //========== SearchService implementation - @Override - public DiscoverResult search(Context context, DiscoverQuery query) throws SearchServiceException { - return search(context, query, false); - } @Override - public DiscoverResult search(Context context, IndexableObject dso, - DiscoverQuery query) + public DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery discoveryQuery) throws SearchServiceException { - return search(context, dso, query, false); - } - - @Override - public DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery discoveryQuery, - boolean includeUnDiscoverable) throws SearchServiceException { if (dso != null) { if (dso instanceof Community) { discoveryQuery.addFilterQueries("location:m" + dso.getID()); @@ -1879,19 +1879,19 @@ public class SolrServiceImpl implements SearchService, IndexingService { discoveryQuery.addFilterQueries(HANDLE_FIELD + ":" + ((Item) dso).getHandle()); } } - return search(context, discoveryQuery, includeUnDiscoverable); + return search(context, discoveryQuery); } @Override - public DiscoverResult search(Context context, DiscoverQuery discoveryQuery, boolean includeUnDiscoverable) + public DiscoverResult search(Context context, DiscoverQuery discoveryQuery ) throws SearchServiceException { try { if (getSolr() == null) { return new DiscoverResult(); } - SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery, includeUnDiscoverable); + SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery); QueryResponse queryResponse = getSolr().query(solrQuery, SolrRequest.METHOD.POST); @@ -1902,8 +1902,8 @@ public class SolrServiceImpl implements SearchService, IndexingService { } } - protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery, - boolean includeUnDiscoverable) throws SearchServiceException { + protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery) + throws SearchServiceException { SolrQuery solrQuery = new SolrQuery(); String query = "*:*"; @@ -1929,11 +1929,6 @@ public class SolrServiceImpl implements SearchService, IndexingService { solrQuery.setParam("spellcheck", Boolean.TRUE); } - if (!includeUnDiscoverable) { - solrQuery.addFilterQuery("NOT(withdrawn:true)"); - solrQuery.addFilterQuery("NOT(discoverable:false)"); - } - for (int i = 0; i < discoveryQuery.getFilterQueries().size(); i++) { String filterQuery = discoveryQuery.getFilterQueries().get(i); solrQuery.addFilterQuery(filterQuery); @@ -2401,8 +2396,8 @@ public class SolrServiceImpl implements SearchService, IndexingService { } catch (Exception e) { log.error( - LogManager.getHeader(context, "Error while retrieving related items", "Handle: " + item.getHandle()), - e); + LogManager.getHeader(context, "Error while retrieving related items", "Handle: " + + item.getHandle()), e); } return results; } diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServicePrivateItemPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServicePrivateItemPlugin.java new file mode 100644 index 0000000000..47dea08fc8 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServicePrivateItemPlugin.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.discovery; + +import static org.apache.logging.log4j.LogManager.getLogger; + +import java.sql.SQLException; + +import org.apache.logging.log4j.Logger; +import org.apache.solr.client.solrj.SolrQuery; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.core.Context; +import org.dspace.core.LogManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * This plugin prevents discovery of private items by non-administrators. + */ +public class SolrServicePrivateItemPlugin implements SolrServiceSearchPlugin { + + private static final Logger log = getLogger(SolrServicePrivateItemPlugin.class.getSimpleName()); + + @Autowired(required = true) + protected AuthorizeService authorizeService; + + + @Autowired(required = true) + protected SearchService searchService; + + @Override + public void additionalSearchParameters(Context context, DiscoverQuery discoveryQuery, SolrQuery solrQuery) { + try { + // Prevents access if user has no administrative rights on the community or collection. + // NOTE: the resource restriction plugin adds location filters for community and collection admins. + if ( !authorizeService.isAdmin(context) && !authorizeService.isCommunityAdmin(context) + && !authorizeService.isCollectionAdmin(context)) { + solrQuery.addFilterQuery("NOT(discoverable:false)"); + } + } catch (SQLException ex) { + log.error(LogManager.getHeader(context, "Error looking up authorization rights of current user", + ""), ex); + } + } +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java index c63b4ebe7e..a0d9101fb8 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java @@ -16,6 +16,8 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import javax.annotation.Nullable; + import org.apache.commons.collections4.MapUtils; import org.apache.logging.log4j.Logger; import org.dspace.authorize.AuthorizeException; @@ -326,15 +328,16 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini } } - public Long getLastModified(Bitstream bitstream) { - Map wantedMetadata = new HashMap(); - wantedMetadata.put("modified", null); - try { - wantedMetadata = stores.get(incoming).about(bitstream, wantedMetadata); - } catch (IOException e) { - log.error(e); + @Nullable + @Override + public Long getLastModified(Bitstream bitstream) throws IOException { + Map attrs = new HashMap(); + attrs.put("modified", null); + attrs = stores.get(bitstream.getStoreNumber()).about(bitstream, attrs); + if (attrs == null || !attrs.containsKey("modified")) { + return null; } - return Long.valueOf(wantedMetadata.get("modified").toString()); + return Long.valueOf(attrs.get("modified").toString()); } /** diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java index 95963b14ca..209ef5d16b 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java @@ -12,6 +12,7 @@ import java.io.InputStream; import java.sql.SQLException; import java.util.Map; import java.util.UUID; +import javax.annotation.Nullable; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; @@ -181,11 +182,13 @@ public interface BitstreamStorageService { /** - * Get the last modified timestamp of the file linked to the given bitstream + * Gets the last modified timestamp of the the given bitstream's content, if known. * - * @param bitstream The bitstream for which to get the last modified timestamp - * @return The last modified timestamp in milliseconds + * @param bitstream the bitstream. + * @return the timestamp in milliseconds, or {@code null} if unknown. + * @throws IOException if an unexpected io error occurs. */ - public Long getLastModified(Bitstream bitstream); + @Nullable + Long getLastModified(Bitstream bitstream) throws IOException; } diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index fe8a940fc3..183bf62fd7 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -15,7 +15,7 @@ ${basedir}/.. - 3.2.10 + 3.2.11 5.87.0.RELEASE diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java index 8704324a88..0bf2fef557 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java @@ -448,6 +448,12 @@ public class XOAI { doc.addField("metadata.dc.format.mimetype", f); } + // Message output before processing - for debugging purposes + if (verbose) { + println(String.format("Item %s with handle %s is about to be indexed", + item.getID().toString(), handle)); + } + ByteArrayOutputStream out = new ByteArrayOutputStream(); XmlOutputContext xmlContext = XmlOutputContext.emptyContext(out, Second); retrieveMetadata(context, item).write(xmlContext); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java b/dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java index 10bbc61e70..5169b5523f 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java @@ -30,6 +30,7 @@ import org.dspace.content.authority.Choices; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.ItemService; +import org.dspace.content.service.RelationshipService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -44,18 +45,22 @@ public class ItemUtils { private static final Logger log = LogManager.getLogger(ItemUtils.class); private static final MetadataExposureService metadataExposureService - = UtilServiceFactory.getInstance().getMetadataExposureService(); + = UtilServiceFactory.getInstance().getMetadataExposureService(); private static final ItemService itemService - = ContentServiceFactory.getInstance().getItemService(); + = ContentServiceFactory.getInstance().getItemService(); + + private static final RelationshipService relationshipService + = ContentServiceFactory.getInstance().getRelationshipService(); private static final BitstreamService bitstreamService - = ContentServiceFactory.getInstance().getBitstreamService(); + = ContentServiceFactory.getInstance().getBitstreamService(); /** * Default constructor */ - private ItemUtils() { } + private ItemUtils() { + } private static Element getElement(List list, String name) { for (Element e : list) { @@ -73,228 +78,223 @@ public class ItemUtils { return e; } - private static Element.Field createValue( - String name, String value) { + private static Element.Field createValue(String name, String value) { Element.Field e = new Element.Field(); e.setValue(value); e.setName(name); return e; } + private static Element createBundlesElement(Context context, Item item) throws SQLException { + Element bundles = create("bundles"); + + List bs; + + bs = item.getBundles(); + for (Bundle b : bs) { + Element bundle = create("bundle"); + bundles.getElement().add(bundle); + bundle.getField().add(createValue("name", b.getName())); + + Element bitstreams = create("bitstreams"); + bundle.getElement().add(bitstreams); + List bits = b.getBitstreams(); + for (Bitstream bit : bits) { + Element bitstream = create("bitstream"); + bitstreams.getElement().add(bitstream); + String url = ""; + String bsName = bit.getName(); + String sid = String.valueOf(bit.getSequenceID()); + String baseUrl = ConfigurationManager.getProperty("oai", "bitstream.baseUrl"); + String handle = null; + // get handle of parent Item of this bitstream, if there + // is one: + List bn = bit.getBundles(); + if (!bn.isEmpty()) { + List bi = bn.get(0).getItems(); + if (!bi.isEmpty()) { + handle = bi.get(0).getHandle(); + } + } + if (bsName == null) { + List ext = bit.getFormat(context).getExtensions(); + bsName = "bitstream_" + sid + (ext.isEmpty() ? "" : ext.get(0)); + } + if (handle != null && baseUrl != null) { + url = baseUrl + "/bitstream/" + handle + "/" + sid + "/" + URLUtils.encode(bsName); + } else { + url = URLUtils.encode(bsName); + } + + String cks = bit.getChecksum(); + String cka = bit.getChecksumAlgorithm(); + String oname = bit.getSource(); + String name = bit.getName(); + String description = bit.getDescription(); + + if (name != null) { + bitstream.getField().add(createValue("name", name)); + } + if (oname != null) { + bitstream.getField().add(createValue("originalName", name)); + } + if (description != null) { + bitstream.getField().add(createValue("description", description)); + } + bitstream.getField().add(createValue("format", bit.getFormat(context).getMIMEType())); + bitstream.getField().add(createValue("size", "" + bit.getSizeBytes())); + bitstream.getField().add(createValue("url", url)); + bitstream.getField().add(createValue("checksum", cks)); + bitstream.getField().add(createValue("checksumAlgorithm", cka)); + bitstream.getField().add(createValue("sid", bit.getSequenceID() + "")); + } + } + + return bundles; + } + + private static Element createLicenseElement(Context context, Item item) + throws SQLException, AuthorizeException, IOException { + Element license = create("license"); + List licBundles; + licBundles = itemService.getBundles(item, Constants.LICENSE_BUNDLE_NAME); + if (!licBundles.isEmpty()) { + Bundle licBundle = licBundles.get(0); + List licBits = licBundle.getBitstreams(); + if (!licBits.isEmpty()) { + Bitstream licBit = licBits.get(0); + InputStream in; + + in = bitstreamService.retrieve(context, licBit); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Utils.bufferedCopy(in, out); + license.getField().add(createValue("bin", Base64Utils.encode(out.toString()))); + + } + } + return license; + } + + /** + * This method will add all sub-elements to a top element, like: dc, or dcterms, ... * + * @param schema Element argument passed by reference that will be changed + * @param val Metadatavalue that will be processed + * @throws SQLException + */ + private static void fillSchemaElement(Element schema, MetadataValue val) throws SQLException { + MetadataField field = val.getMetadataField(); + Element valueElem = schema; + + // Has element.. with XOAI one could have only schema and value + if (field.getElement() != null && !field.getElement().equals("")) { + Element element = getElement(schema.getElement(), field.getElement()); + if (element == null) { + element = create(field.getElement()); + schema.getElement().add(element); + } + valueElem = element; + + // Qualified element? + if (field.getQualifier() != null && !field.getQualifier().equals("")) { + Element qualifier = getElement(element.getElement(), field.getQualifier()); + if (qualifier == null) { + qualifier = create(field.getQualifier()); + element.getElement().add(qualifier); + } + valueElem = qualifier; + } + } + + // Language? + if (val.getLanguage() != null && !val.getLanguage().equals("")) { + Element language = getElement(valueElem.getElement(), val.getLanguage()); + if (language == null) { + language = create(val.getLanguage()); + valueElem.getElement().add(language); + } + valueElem = language; + } else { + Element language = getElement(valueElem.getElement(), "none"); + if (language == null) { + language = create("none"); + valueElem.getElement().add(language); + } + valueElem = language; + } + + valueElem.getField().add(createValue("value", val.getValue())); + if (val.getAuthority() != null) { + valueElem.getField().add(createValue("authority", val.getAuthority())); + if (val.getConfidence() != Choices.CF_NOVALUE) { + valueElem.getField().add(createValue("confidence", val.getConfidence() + "")); + } + } + } + + /** + * Utility method to retrieve a structured XML in XOAI format + * @param context + * @param item + * @return Structured XML Metadata in XOAI format + */ public static Metadata retrieveMetadata(Context context, Item item) { Metadata metadata; // read all metadata into Metadata Object metadata = new Metadata(); + List vals = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); for (MetadataValue val : vals) { MetadataField field = val.getMetadataField(); - - // Don't expose fields that are hidden by configuration try { - if (metadataExposureService.isHidden(context, - field.getMetadataSchema().getName(), - field.getElement(), - field.getQualifier())) { + // Don't expose fields that are hidden by configuration + if (metadataExposureService.isHidden(context, field.getMetadataSchema().getName(), field.getElement(), + field.getQualifier())) { continue; } + + Element schema = getElement(metadata.getElement(), field.getMetadataSchema().getName()); + if (schema == null) { + schema = create(field.getMetadataSchema().getName()); + metadata.getElement().add(schema); + } + + fillSchemaElement(schema, val); } catch (SQLException se) { throw new RuntimeException(se); } - - Element valueElem = null; - Element schema = getElement(metadata.getElement(), field.getMetadataSchema().getName()); - if (schema == null) { - schema = create(field.getMetadataSchema().getName()); - metadata.getElement().add(schema); - } - valueElem = schema; - - // Has element.. with XOAI one could have only schema and value - if (field.getElement() != null && !field.getElement().equals("")) { - Element element = getElement(schema.getElement(), - field.getElement()); - if (element == null) { - element = create(field.getElement()); - schema.getElement().add(element); - } - valueElem = element; - - // Qualified element? - if (field.getQualifier() != null && !field.getQualifier().equals("")) { - Element qualifier = getElement(element.getElement(), - field.getQualifier()); - if (qualifier == null) { - qualifier = create(field.getQualifier()); - element.getElement().add(qualifier); - } - valueElem = qualifier; - } - } - - // Language? - if (val.getLanguage() != null && !val.getLanguage().equals("")) { - Element language = getElement(valueElem.getElement(), - val.getLanguage()); - if (language == null) { - language = create(val.getLanguage()); - valueElem.getElement().add(language); - } - valueElem = language; - } else { - Element language = getElement(valueElem.getElement(), - "none"); - if (language == null) { - language = create("none"); - valueElem.getElement().add(language); - } - valueElem = language; - } - - valueElem.getField().add(createValue("value", val.getValue())); - if (val.getAuthority() != null) { - valueElem.getField().add(createValue("authority", val.getAuthority())); - if (val.getConfidence() != Choices.CF_NOVALUE) { - valueElem.getField().add(createValue("confidence", val.getConfidence() + "")); - } - } } + // Done! Metadata has been read! // Now adding bitstream info - Element bundles = create("bundles"); - metadata.getElement().add(bundles); - - List bs; try { - bs = item.getBundles(); - for (Bundle b : bs) { - Element bundle = create("bundle"); - bundles.getElement().add(bundle); - bundle.getField() - .add(createValue("name", b.getName())); - - Element bitstreams = create("bitstreams"); - bundle.getElement().add(bitstreams); - List bits = b.getBitstreams(); - for (Bitstream bit : bits) { - Element bitstream = create("bitstream"); - bitstreams.getElement().add(bitstream); - String url = ""; - String bsName = bit.getName(); - String sid = String.valueOf(bit.getSequenceID()); - String baseUrl = ConfigurationManager.getProperty("oai", - "bitstream.baseUrl"); - String handle = null; - // get handle of parent Item of this bitstream, if there - // is one: - List bn = bit.getBundles(); - if (!bn.isEmpty()) { - List bi = bn.get(0).getItems(); - if (!bi.isEmpty()) { - handle = bi.get(0).getHandle(); - } - } - if (bsName == null) { - List ext = bit.getFormat(context).getExtensions(); - bsName = "bitstream_" + sid - + (ext.isEmpty() ? "" : ext.get(0)); - } - if (handle != null && baseUrl != null) { - url = baseUrl + "/bitstream/" - + handle + "/" - + sid + "/" - + URLUtils.encode(bsName); - } else { - url = URLUtils.encode(bsName); - } - - String cks = bit.getChecksum(); - String cka = bit.getChecksumAlgorithm(); - String oname = bit.getSource(); - String name = bit.getName(); - String description = bit.getDescription(); - - if (name != null) { - bitstream.getField().add( - createValue("name", name)); - } - if (oname != null) { - bitstream.getField().add( - createValue("originalName", name)); - } - if (description != null) { - bitstream.getField().add( - createValue("description", description)); - } - bitstream.getField().add( - createValue("format", bit.getFormat(context) - .getMIMEType())); - bitstream.getField().add( - createValue("size", "" + bit.getSizeBytes())); - bitstream.getField().add(createValue("url", url)); - bitstream.getField().add( - createValue("checksum", cks)); - bitstream.getField().add( - createValue("checksumAlgorithm", cka)); - bitstream.getField().add( - createValue("sid", bit.getSequenceID() - + "")); - } - } - } catch (SQLException e1) { - e1.printStackTrace(); + Element bundles = createBundlesElement(context, item); + metadata.getElement().add(bundles); + } catch (SQLException e) { + log.warn(e.getMessage(), e); } - // Other info Element other = create("others"); - other.getField().add( - createValue("handle", item.getHandle())); - other.getField().add( - createValue("identifier", DSpaceItem.buildIdentifier(item.getHandle()))); - other.getField().add( - createValue("lastModifyDate", item - .getLastModified().toString())); + other.getField().add(createValue("handle", item.getHandle())); + other.getField().add(createValue("identifier", DSpaceItem.buildIdentifier(item.getHandle()))); + other.getField().add(createValue("lastModifyDate", item.getLastModified().toString())); metadata.getElement().add(other); // Repository Info Element repository = create("repository"); - repository.getField().add( - createValue("name", - ConfigurationManager.getProperty("dspace.name"))); - repository.getField().add( - createValue("mail", - ConfigurationManager.getProperty("mail.admin"))); + repository.getField().add(createValue("url", ConfigurationManager.getProperty("dspace.baseUrl"))); + repository.getField().add(createValue("name", ConfigurationManager.getProperty("dspace.name"))); + repository.getField().add(createValue("mail", ConfigurationManager.getProperty("mail.admin"))); metadata.getElement().add(repository); // Licensing info - Element license = create("license"); - List licBundles; try { - licBundles = itemService.getBundles(item, Constants.LICENSE_BUNDLE_NAME); - if (!licBundles.isEmpty()) { - Bundle licBundle = licBundles.get(0); - List licBits = licBundle.getBitstreams(); - if (!licBits.isEmpty()) { - Bitstream licBit = licBits.get(0); - InputStream in; - try { - in = bitstreamService.retrieve(context, licBit); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - Utils.bufferedCopy(in, out); - license.getField().add( - createValue("bin", - Base64Utils.encode(out.toString()))); - metadata.getElement().add(license); - } catch (AuthorizeException | IOException | SQLException e) { - log.warn(e.getMessage(), e); - } - - } - } - } catch (SQLException e1) { - log.warn(e1.getMessage(), e1); + Element license = createLicenseElement(context, item); + metadata.getElement().add(license); + } catch (AuthorizeException | IOException | SQLException e) { + log.warn(e.getMessage(), e); } return metadata; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java index 1ecd7a33ff..ba2c66c734 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java @@ -127,10 +127,13 @@ public class BitstreamRestController { .withLength(bitstreamTuple.getRight()) .withChecksum(bit.getChecksum()) .withMimetype(mimetype) - .withLastModified(lastModified) .with(request) .with(response); + if (lastModified != null) { + sender.withLastModified(lastModified); + } + //Determine if we need to send the file as a download or if the browser can open it inline long dispositionThreshold = configurationService.getLongProperty("webui.content_disposition_threshold"); if (dispositionThreshold >= 0 && bitstreamTuple.getRight() > dispositionThreshold) { diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java index cdee407282..1212704c92 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java @@ -3582,4 +3582,139 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest } + @Test + public void discoverSearchObjectsTestForWithdrawnOrPrivateItemsNonAdmin() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. One public item, one private, one withdrawn. + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("WithdrawnTest 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .withdrawn() + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Private Test item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + + String query = "Test"; + //** WHEN ** + //A non-admin user browses this endpoint to find the withdrawn or private objects in the system + //With a query stating 'Test' + getClient().perform(get("/api/discover/search/objects") + .param("configuration", "undiscoverable") + .param("query", query)) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results should be an empty list. + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.empty())) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + + ; + + } + + @Test + public void discoverSearchObjectsTestForWithdrawnOrPrivateItemsByAdminUser() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. One public item, one private, one withdrawn. + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Withdrawn Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .withdrawn() + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Private Test item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + context.restoreAuthSystemState(); + + String query = "Test"; + String adminToken = getAuthToken(admin.getEmail(), password); + //** WHEN ** + // A system admin user browses this endpoint to find the withdrawn or private objects in the system + // With a query stating 'Test' + getClient(adminToken).perform(get("/api/discover/search/objects") + .param("configuration", "undiscoverable") + .param("query", query)) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results should be an empty list. + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", + Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Private Test item 2"), + SearchResultMatcher.matchOnItemName("item", "items", "Withdrawn Test 2") + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + + ; + + } + } \ No newline at end of file diff --git a/dspace/config/crosswalks/oai/metadataFormats/oai_openaire.xsl b/dspace/config/crosswalks/oai/metadataFormats/oai_openaire.xsl new file mode 100644 index 0000000000..4f0cfcaad2 --- /dev/null +++ b/dspace/config/crosswalks/oai/metadataFormats/oai_openaire.xsl @@ -0,0 +1,1537 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Organizational + + + Personal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Organizational + + + + Personal + + + + + + + + + + + + + + + + + + + + + + + + + + + e-mail + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fulltext + + + + other + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AlternativeTitle + + + Subtitle + + + TranslatedTitle + + + Other + + + + + + + + + + + + + + + Supervisor + + + Editor + + + Other + + + + + + + + + + + + + + + Available + + + Collected + + + Copyrighted + + + Created + + + Submitted + + + Updated + + + Valid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ARK + + + arXiv + + + bibcode + + + DOI + + + EAN13 + + + EISSN + + + Handle + + + IGSN + + + ISBN + + + ISSN + + + ISTC + + + LISSN + + + LSID + + + PMID + + + PURL + + + UPC + + + URL + + + URN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Handle + + + DOI + + + URL + + + N/A + + + + + + + + + + + + + + + literature + + + literature + + + literature + + + literature + + + literature + + + dataset + + + software + + + other research product + + + + + + + + + + + + + + + http://purl.org/coar/resource_type/c_1162 + + + http://purl.org/coar/resource_type/c_0640 + + + http://purl.org/coar/resource_type/c_6501 + + + http://purl.org/coar/resource_type/c_6501 + + + http://purl.org/coar/resource_type/c_b239 + + + http://purl.org/coar/resource_type/c_7a1f + + + http://purl.org/coar/resource_type/c_86bc + + + http://purl.org/coar/resource_type/c_2f33 + + + http://purl.org/coar/resource_type/c_3248 + + + http://purl.org/coar/resource_type/c_ba08 + + + http://purl.org/coar/resource_type/c_7ad9 + + + http://purl.org/coar/resource_type/c_e9a0 + + + http://purl.org/coar/resource_type/c_f744 + + + http://purl.org/coar/resource_type/c_c94f + + + http://purl.org/coar/resource_type/c_5794 + + + http://purl.org/coar/resource_type/c_6670 + + + http://purl.org/coar/resource_type/c_3e5a + + + http://purl.org/coar/resource_type/c_beb9 + + + http://purl.org/coar/resource_type/c_ddb1 + + + http://purl.org/coar/resource_type/c_db06 + + + http://purl.org/coar/resource_type/c_c513 + + + http://purl.org/coar/resource_type/c_8544 + + + http://purl.org/coar/resource_type/c_0857 + + + http://purl.org/coar/resource_type/c_bdcc + + + http://purl.org/coar/resource_type/c_8a7e + + + http://purl.org/coar/resource_type/c_2659 + + + http://purl.org/coar/resource_type/c_545b + + + http://purl.org/coar/resource_type/c_15cd + + + http://purl.org/coar/resource_type/c_816b + + + http://purl.org/coar/resource_type/c_93fc + + + http://purl.org/coar/resource_type/c_ba1f + + + http://purl.org/coar/resource_type/c_baaf + + + http://purl.org/coar/resource_type/c_efa0 + + + http://purl.org/coar/resource_type/c_5ce6 + + + http://purl.org/coar/resource_type/c_ecc8 + + + http://purl.org/coar/resource_type/c_71bd + + + http://purl.org/coar/resource_type/c_393c + + + http://purl.org/coar/resource_type/c_8042 + + + http://purl.org/coar/resource_type/c_46ec + + + http://purl.org/coar/resource_type/c_12cc + + + http://purl.org/coar/resource_type/c_12cd + + + http://purl.org/coar/resource_type/c_12ce + + + http://purl.org/coar/resource_type/c_18cc + + + http://purl.org/coar/resource_type/c_18cd + + + http://purl.org/coar/resource_type/c_18cf + + + http://purl.org/coar/resource_type/c_18cp + + + http://purl.org/coar/resource_type/c_18co + + + http://purl.org/coar/resource_type/c_18cw + + + http://purl.org/coar/resource_type/c_18ww + + + http://purl.org/coar/resource_type/c_18wz + + + http://purl.org/coar/resource_type/c_18wq + + + http://purl.org/coar/resource_type/c_186u + + + http://purl.org/coar/resource_type/c_18op + + + http://purl.org/coar/resource_type/c_18hj + + + http://purl.org/coar/resource_type/c_18ws + + + http://purl.org/coar/resource_type/c_18gh + + + http://purl.org/coar/resource_type/c_dcae04bc + + + http://purl.org/coar/resource_type/c_2df8fbb1 + + + + http://purl.org/coar/resource_type/c_1843 + + + + + + + + + + + + + + + http://purl.org/coar/access_right/c_abf2 + + + http://purl.org/coar/access_right/c_f1cf + + + http://purl.org/coar/access_right/c_16ec + + + http://purl.org/coar/access_right/c_14cb + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dspace/config/crosswalks/oai/transformers/openaire4.xsl b/dspace/config/crosswalks/oai/transformers/openaire4.xsl new file mode 100644 index 0000000000..81829025a5 --- /dev/null +++ b/dspace/config/crosswalks/oai/transformers/openaire4.xsl @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eng + + + eng + + + spa + + + deu + + + fra + + + ita + + + jap + + + zho + + + por + + + tur + + + + + + + + + + + + + + + + + + + + + + open access + + + embargoed access + + + restricted access + + + metadata only access + + + + + + + + + + + + + + + + + + annotation + + + journal + + + journal article + + + editorial + + + bachelor thesis + + + bibliography + + + book + + + book part + + + book review + + + website + + + interactive resource + + + conference proceedings + + + conference object + + + conference paper + + + conference poster + + + contribution to journal + + + data paper + + + dataset + + + doctoral thesis + + + image + + + lecture + + + letter + + + master thesis + + + moving image + + + periodical + + + letter to the editor + + + patent + + + preprint + + + report + + + report part + + + research proposal + + + review + + + software + + + still image + + + technical documentation + + + workflow + + + working paper + + + thesis + + + cartographic material + + + map + + + video + + + sound + + + musical composition + + + text + + + conference paper not in proceedings + + + conference poster not in proceedings + + + musical notation + + + internal report + + + memorandum + + + other type of report + + + policy report + + + project deliverable + + + report to funding agency + + + research report + + + technical report + + + review article + + + research article + + + other + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/crosswalks/oai/xoai.xml b/dspace/config/crosswalks/oai/xoai.xml index 868382ccf0..3d79520eef 100644 --- a/dspace/config/crosswalks/oai/xoai.xml +++ b/dspace/config/crosswalks/oai/xoai.xml @@ -1,7 +1,6 @@ + maxListSetsSize="100" stylesheet="static/style.xsl" xmlns="http://www.lyncode.com/XOAIConfiguration"> @@ -70,6 +69,28 @@ This contexts complies with OpenAIRE Guidelines for Literature Repositories v3.0. + + + + + + + + + + + This contexts complies with OpenAIRE Guidelines for Literature Repositories v4.0. + + + @@ -155,6 +176,15 @@ http://irdb.nii.ac.jp/oai http://irdb.nii.ac.jp/oai/junii2-3-1.xsd + + + oai_openaire + metadataFormats/oai_openaire.xsl + http://namespace.openaire.eu/schema/oaire/ + https://www.openaire.eu/schema/repo-lit/4.0/openaire.xsd + @@ -164,6 +194,9 @@ transformers/openaire.xsl + + transformers/openaire4.xsl + @@ -286,22 +319,83 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + - + + + + + + + + + + + + - + @@ -398,6 +492,30 @@ info:eu-repo/grantAgreement/ + + + + org.dspace.xoai.filter.DSpaceMetadataExistsFilter + + relationship.type + + + + + + org.dspace.xoai.filter.DSpaceAtLeastOneMetadataFilter + + relationship.type + equal + + Publication + publication + + + + + diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index 3da454ba09..be03cd70d0 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -27,6 +27,7 @@ + @@ -51,9 +52,9 @@ - + - + @@ -249,6 +250,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + search.resourcetype:2 + + withdrawn:true OR discoverable:false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + dc.title + dc.contributor.author + dc.creator + dc.subject + + + + + + + + + + + + + diff --git a/dspace/config/spring/api/virtual-metadata.xml.openaire4 b/dspace/config/spring/api/virtual-metadata.xml.openaire4 new file mode 100644 index 0000000000..909468e088 --- /dev/null +++ b/dspace/config/spring/api/virtual-metadata.xml.openaire4 @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + person.familyName + person.givenName + organization.legalName + + + + , + + + + + + + + person.givenName + + + + + + + person.familyName + + + + + + + person.affiliation.name + + + + + + + person.identifier + + + + + + + person.identifier.scopus-author-id + + + + + + + person.identifier.rid + + + + + + + person.identifier.ciencia-id + + + + + + + person.identifier.gsid + + + + + + + person.identifier.orcid + + + + + + + person.identifier.isni + + + + + + + organization.legalName + + + + + + + organization.identifier + + + + + + + + + + + + + + + + + + + dc.title + + + + + + + oaire.fundingStream + + + + + + + dc.identifier + + + + + + + dc.identifier.uri + + + + + + + + + + + + + + + + + + + + + + + + + + + organization.legalName + + + + + + + organization.identifier + + + + \ No newline at end of file