diff --git a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java index 3ad03377cb27..cfad7f87dba5 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -298,9 +298,7 @@ private List getThumbnailFields(List crisLayoutT * @param context * @param item * @param bundle - * @param metadata * @param value - * @param requireOriginal * @throws SQLException * @return Bitstream */ @@ -2138,4 +2136,12 @@ public boolean isLatestVersion(Context context, Item item) throws SQLException { } + @Override + public void addResourcePolicy(Context context, Item item, int actionID, EPerson eperson) + throws SQLException, AuthorizeException { + ResourcePolicy resourcePolicy = + this.authorizeService.createResourcePolicy(context, item, null, eperson, actionID, null); + item.getResourcePolicies().add(resourcePolicy); + } + } diff --git a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java index e6823690743d..44ba4a6bcd99 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java @@ -922,4 +922,17 @@ public Iterator findRelatedItemsByAuthorityControlledFields(Context contex */ public boolean isLatestVersion(Context context, Item item) throws SQLException; + /** + * Adds a resource policy to the specified item for the given action and EPerson. + * + * @param context the DSpace context + * @param item the item to add the policy to + * @param actionID the ID of the action to add the policy for + * @param eperson the EPerson to add the policy for + * @throws SQLException if a database error occurs + * @throws AuthorizeException if the current user is not authorized to perform this action + */ + void addResourcePolicy(Context context, Item item, int actionID, EPerson eperson) + throws SQLException, AuthorizeException; + } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationUtilsService.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationUtilsService.java index e2e83920eb70..3db9e04c2694 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationUtilsService.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationUtilsService.java @@ -52,6 +52,7 @@ public Iterator findByRelation(Context context, Item item, String relation DiscoverQuery discoverQuery = new DiscoverQuery(); discoverQuery.setDSpaceObjectFilter(IndexableItem.TYPE); discoverQuery.setDiscoveryConfigurationName(discoveryConfiguration.getId()); + discoverQuery.setScopeObject(new IndexableItem(item)); List defaultFilterQueries = discoveryConfiguration.getDefaultFilterQueries(); for (String defaultFilterQuery : defaultFilterQueries) { discoverQuery.addFilterQueries(MessageFormat.format(defaultFilterQuery, item.getID())); diff --git a/dspace-api/src/main/java/org/dspace/importer/external/bibtex/service/BibtexImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/bibtex/service/BibtexImportMetadataSourceServiceImpl.java index 0014088c8650..4b6a5aa92e72 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/bibtex/service/BibtexImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/bibtex/service/BibtexImportMetadataSourceServiceImpl.java @@ -117,4 +117,9 @@ public void setMetadataFieldMap(@SuppressWarnings("rawtypes") Map metadataFieldM super.setMetadataFieldMap(metadataFieldMap); } + @Override + public boolean canImportMultipleRecords() { + return true; + } + } diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/ImportService.java b/dspace-api/src/main/java/org/dspace/importer/external/service/ImportService.java index 28df30b345bc..a444a3609c15 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/ImportService.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/ImportService.java @@ -311,7 +311,7 @@ public boolean canImportFromFile(String originalName) { /* * Get a collection of record from File, * The first match will be return. - * + * * @param file The file from which will read records * @param originalName The original file name or full path * @return a single record contains the metadatum @@ -319,28 +319,83 @@ public boolean canImportFromFile(String originalName) { */ public ImportRecord getRecord(File file, String originalName) throws FileMultipleOccurencesException, FileSourceException { - ImportRecord importRecords = null; - for (MetadataSource metadataSource : importSources.values()) { - try (InputStream fileInputStream = new FileInputStream(file)) { - if (metadataSource instanceof FileSource) { - FileSource fileSource = (FileSource)metadataSource; - if (fileSource.isValidSourceForFile(originalName)) { - importRecords = fileSource.getRecord(fileInputStream); - break; + try (InputStream fileInputStream = new FileInputStream(file)) { + FileSource fileSource = this.getFileSource(fileInputStream, originalName); + try { + if (fileSource.isValidSourceForFile(originalName)) { + return fileSource.getRecord(fileInputStream); + } + } catch (FileSourceException e) { + log.debug(fileSource.getImportSource() + " isn't a valid parser for file", e); + } + //catch statements is required because we could have supported format (i.e. XML) + //which fail on schema validation + } catch (FileMultipleOccurencesException e) { + log.debug("File contains multiple metadata, return with error"); + throw e; + } catch (IOException e1) { + throw new FileSourceException("File cannot be read, may be null"); + } + return null; + } + + /** + * Get a collection of record from File, + * + * @param file The file from which will read records + * @param originalName The original file name or full path + * @return records containing metdatum + * @throws FileMultipleOccurencesException if the import configured for the {@code file} + * doesn't allow multiple records import. + * @throws FileSourceException if the file cannot be read. + */ + public List getRecords(File file, String originalName) + throws FileMultipleOccurencesException, FileSourceException { + try (InputStream fileInputStream = new FileInputStream(file)) { + FileSource fileSource = this.getFileSource(fileInputStream, originalName); + try { + if (fileSource.isValidSourceForFile(originalName)) { + List records = fileSource.getRecords(fileInputStream); + if (!fileSource.canImportMultipleRecords() && records.size() > 1) { + throw new FileMultipleOccurencesException( + "Found " + records.size() + " entries in file ( " + + originalName + + " ) but import source ( " + + fileSource.getImportSource() + + " ) not allowed to import multiple records" + ); } + return records; } + } catch (FileSourceException e) { + log.debug(fileSource.getImportSource() + " isn't a valid parser for file", e); + } //catch statements is required because we could have supported format (i.e. XML) //which fail on schema validation - } catch (FileSourceException e) { - log.debug(metadataSource.getImportSource() + " isn't a valid parser for file"); - } catch (FileMultipleOccurencesException e) { - log.debug("File contains multiple metadata, return with error"); - throw e; - } catch (IOException e1) { - throw new FileSourceException("File cannot be read, may be null"); + } catch (IOException e1) { + throw new FileSourceException("File cannot be read, may be null"); + } + return null; + } + + protected FileSource getFileSource(File file, String originalName) throws FileSourceException { + try (InputStream fileInputStream = new FileInputStream(file)) { + return getFileSource(file, originalName); + } catch (IOException e1) { + throw new FileSourceException("File cannot be read, may be null"); + } + } + + protected FileSource getFileSource(InputStream fileInputStream, String originalName) { + for (MetadataSource metadataSource : importSources.values()) { + if (metadataSource instanceof FileSource) { + FileSource fileSource = (FileSource)metadataSource; + if (fileSource.isValidSourceForFile(originalName)) { + return fileSource; + } } } - return importRecords; + return null; } /** diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/components/AbstractPlainMetadataSource.java b/dspace-api/src/main/java/org/dspace/importer/external/service/components/AbstractPlainMetadataSource.java index 5d83b9a7cce4..b58f69b6665c 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/components/AbstractPlainMetadataSource.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/components/AbstractPlainMetadataSource.java @@ -41,7 +41,7 @@ public abstract class AbstractPlainMetadataSource /** * Set the file extensions supported by this metadata service - * + * * @param supportedExtensions the file extensions (xml,txt,...) supported by this service */ public void setSupportedExtensions(List supportedExtensions) { @@ -64,6 +64,9 @@ public List getSupportedExtensions() { @Override public List getRecords(InputStream is) throws FileSourceException { List datas = readData(is); + if (datas == null) { + return List.of(); + } List records = new ArrayList<>(); for (PlainMetadataSourceDto item : datas) { records.add(toRecord(item)); diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/components/FileSource.java b/dspace-api/src/main/java/org/dspace/importer/external/service/components/FileSource.java index 801f5474bb4e..fffd476a69ee 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/components/FileSource.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/components/FileSource.java @@ -52,7 +52,7 @@ public ImportRecord getRecord(InputStream inputStream) /** * This method is used to decide if the FileSource manage the file format - * + * * @param originalName the file file original name * @return true if the FileSource can parse the file, false otherwise */ @@ -67,4 +67,13 @@ public default boolean isValidSourceForFile(String originalName) { return false; } + /** + * This method is used to determine if we can import multiple records at once placed in the same source file. + * + * @return true if allowed to import multiple records in the same file, false otherwise + */ + public default boolean canImportMultipleRecords() { + return false; + } + } diff --git a/dspace-api/src/main/java/org/dspace/profile/ResearcherProfileServiceImpl.java b/dspace-api/src/main/java/org/dspace/profile/ResearcherProfileServiceImpl.java index cec440df6d45..32915d74c0cf 100644 --- a/dspace-api/src/main/java/org/dspace/profile/ResearcherProfileServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/profile/ResearcherProfileServiceImpl.java @@ -314,17 +314,20 @@ private Item createProfileItem(Context context, EPerson ePerson, Collection coll item = installItemService.installItem(context, workspaceItem); + context.uncacheEntity(workspaceItem); + if (isNewProfileNotVisibleByDefault()) { Group anonymous = groupService.findByName(context, ANONYMOUS); authorizeService.removeGroupPolicies(context, item, anonymous); } - authorizeService.addPolicy(context, item, READ, ePerson); + itemService.addResourcePolicy(context, item, READ, ePerson); if (isAdditionOfWritePolicyOnProfileEnabled()) { - authorizeService.addPolicy(context, item, WRITE, ePerson); + itemService.addResourcePolicy(context, item, WRITE, ePerson); } + return reloadItem(context, item); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/RegistrationDataConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/RegistrationDataConverter.java index 5b742366b582..3ec5bfbf533c 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/RegistrationDataConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/RegistrationDataConverter.java @@ -66,6 +66,9 @@ public RegistrationRest convert(RegistrationData registrationData, Projection pr EPerson ePerson = null; try { ePerson = accountService.getEPerson(context, registrationData.getToken()); + if (ePerson == null && registrationData.getRegistrationType().equals(RegistrationTypeEnum.ORCID)) { + ePerson = context.getCurrentUser(); + } } catch (SQLException | AuthorizeException e) { throw new RuntimeException(e); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java index 770087d0b54b..1f1582596277 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java @@ -317,9 +317,9 @@ public Iterable upload(Context context, HttpServletRequest re for (MultipartFile mpFile : uploadfiles) { File file = Utils.getFile(mpFile, "upload-loader", "filedataloader"); try { - ImportRecord record = importService.getRecord(file, mpFile.getOriginalFilename()); - if (record != null) { - records.add(record); + List recordsFound = importService.getRecords(file, mpFile.getOriginalFilename()); + if (recordsFound != null && !recordsFound.isEmpty()) { + records.addAll(recordsFound); break; } } catch (Exception e) { @@ -334,11 +334,15 @@ public Iterable upload(Context context, HttpServletRequest re } catch (Exception e) { log.error("Error importing metadata", e); } - WorkspaceItem source = submissionService. - createWorkspaceItem(context, getRequestService().getCurrentRequest()); - merge(context, records, source); - result = new ArrayList<>(); - result.add(source); + result = new ArrayList<>(records.size()); + for (ImportRecord importRecord : records) { + WorkspaceItem source = submissionService. + createWorkspaceItem(context, getRequestService().getCurrentRequest()); + + merge(context, importRecord, source); + + result.add(source); + } //perform upload of bitstream if there is exact one result and convert workspaceitem to entity rest if (!result.isEmpty()) { @@ -348,18 +352,17 @@ public Iterable upload(Context context, HttpServletRequest re //load bitstream into bundle ORIGINAL only if there is one result (approximately this is the // right behaviour for pdf file but not for other bibliographic format e.g. bibtex) if (result.size() == 1) { + ClassLoader loader = this.getClass().getClassLoader(); for (int i = 0; i < submissionConfig.getNumberOfSteps(); i++) { SubmissionStepConfig stepConfig = submissionConfig.getStep(i); - ClassLoader loader = this.getClass().getClassLoader(); - Class stepClass; try { - stepClass = loader.loadClass(stepConfig.getProcessingClassName()); - Object stepInstance = stepClass.newInstance(); + Class stepClass = loader.loadClass(stepConfig.getProcessingClassName()); + Object stepInstance = stepClass.getConstructor().newInstance(); if (UploadableStep.class.isAssignableFrom(stepClass)) { UploadableStep uploadableStep = (UploadableStep) stepInstance; for (MultipartFile mpFile : uploadfiles) { - ErrorRest err = uploadableStep.upload(context, - submissionService, stepConfig, wi, mpFile); + ErrorRest err = + uploadableStep.upload(context, submissionService, stepConfig, wi, mpFile); if (err != null) { errors.add(err); } @@ -449,7 +452,7 @@ private BaseObjectRest findItemRestById(Context context, String itemId) throw return authorizationRestUtil.getObject(context, objectId); } - private void merge(Context context, List records, WorkspaceItem item) throws SQLException { + private void merge(Context context, ImportRecord record, WorkspaceItem item) throws SQLException { for (MetadataValue metadataValue : itemService.getMetadata( item.getItem(), Item.ANY, Item.ANY, Item.ANY, Item.ANY)) { itemService.clearMetadata(context, item.getItem(), @@ -458,13 +461,11 @@ private void merge(Context context, List records, WorkspaceItem it metadataValue.getMetadataField().getQualifier(), metadataValue.getLanguage()); } - for (ImportRecord record : records) { - if (record != null && record.getValueList() != null) { - for (MetadatumDTO metadataValue : record.getValueList()) { - itemService.addMetadata(context, item.getItem(), metadataValue.getSchema(), - metadataValue.getElement(), metadataValue.getQualifier(), null, - metadataValue.getValue()); - } + if (record != null && record.getValueList() != null) { + for (MetadatumDTO metadataValue : record.getValueList()) { + itemService.addMetadata(context, item.getItem(), metadataValue.getSchema(), + metadataValue.getElement(), metadataValue.getQualifier(), null, + metadataValue.getValue()); } } } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java index c7725805687d..d9d2c0fcf708 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java @@ -60,9 +60,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.matchers.JsonPathMatchers; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; +import org.apache.commons.text.StringEscapeUtils; import org.dspace.app.rest.matcher.CollectionMatcher; import org.dspace.app.rest.matcher.ItemMatcher; import org.dspace.app.rest.matcher.MetadataMatcher; @@ -2027,27 +2027,109 @@ public void createSingleWorkspaceItemsFromSingleFileWithMultipleEntriesTest() th Collection col1 = CollectionBuilder.createCollection(context, child1) .withName("Collection 1") .withSubmitterGroup(eperson) + .withEntityType("Publication") + .withSubmissionDefinition("traditional") .build(); Collection col2 = CollectionBuilder.createCollection(context, child1) .withName("Collection 2") .withSubmitterGroup(eperson) + .withEntityType("Publication") + .withSubmissionDefinition("traditional") .build(); - InputStream bibtex = getClass().getResourceAsStream("bibtex-test-3-entries.bib"); - final MockMultipartFile bibtexFile = new MockMultipartFile("file", "bibtex-test-3-entries.bib", - "application/x-bibtex", - bibtex); + try (InputStream bibtex = getClass().getResourceAsStream("bibtex-test-3-entries.bib")) { + final MockMultipartFile bibtexFile = + new MockMultipartFile( + "file", "bibtex-test-3-entries.bib", + "application/x-bibtex", bibtex + ); - context.restoreAuthSystemState(); + context.restoreAuthSystemState(); - String authToken = getAuthToken(eperson.getEmail(), password); - // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1) - getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(bibtexFile)) - // create should return return a 422 because we don't allow/support bibliographic files - // that have multiple metadata records - .andExpect(status().is(422)); - bibtex.close(); + String authToken = getAuthToken(eperson.getEmail(), password); + // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1) + getClient(authToken) + .perform( + multipart("/api/submission/workspaceitems").file(bibtexFile) + ) + // bulk create should return 200, 201 (created) is better for single resource + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", + is("My Article") + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[0]._embedded.collection.id", + is(col1.getID().toString()) + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[1].sections.traditionalpageone['dc.title'][0].value", + is("My Article 2") + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[1]._embedded.collection.id", + is(col1.getID().toString()) + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[2].sections.traditionalpageone['dc.title'][0].value", + is("My Article 3") + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[2]._embedded.collection.id", + is(col1.getID().toString()) + ) + ) + .andExpect( + jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist()); + getClient(authToken) + .perform( + multipart("/api/submission/workspaceitems") + .file(bibtexFile) + .param("owningCollection", col2.getID().toString()) + ) + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", + is("My Article") + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[0]._embedded.collection.id", + is(col2.getID().toString()) + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[1].sections.traditionalpageone['dc.title'][0].value", + is("My Article 2") + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[1]._embedded.collection.id", + is(col2.getID().toString()) + ) + ) + .andExpect( + jsonPath( + "$._embedded.workspaceitems[2].sections.traditionalpageone['dc.title'][0].value", + is("My Article 3") + ) + ); + } } @Test diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/layout/CrisLayoutTabRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/layout/CrisLayoutTabRestRepositoryIT.java index 80ed84453088..c911253a6124 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/layout/CrisLayoutTabRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/layout/CrisLayoutTabRestRepositoryIT.java @@ -12,8 +12,10 @@ import static org.dspace.app.rest.matcher.CrisLayoutBoxMatcher.matchBox; import static org.dspace.app.rest.matcher.CrisLayoutTabMatcher.matchRest; import static org.dspace.app.rest.matcher.CrisLayoutTabMatcher.matchTab; +import static org.dspace.builder.RelationshipTypeBuilder.createRelationshipTypeBuilder; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; @@ -56,6 +58,7 @@ import org.dspace.builder.EntityTypeBuilder; import org.dspace.builder.GroupBuilder; import org.dspace.builder.ItemBuilder; +import org.dspace.builder.RelationshipBuilder; import org.dspace.content.Bundle; import org.dspace.content.Collection; import org.dspace.content.Community; @@ -63,9 +66,13 @@ import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityTypeService; import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.RelationshipService; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.layout.CrisLayoutBox; @@ -104,6 +111,12 @@ public class CrisLayoutTabRestRepositoryIT extends AbstractControllerIntegration @Autowired private CrisLayoutTabService crisLayoutTabService; + @Autowired + protected EntityTypeService entityTypeService; + + @Autowired + protected RelationshipService relationshipService; + private final String METADATASECURITY_URL = "http://localhost:8080/api/core/metadatafield/"; /** @@ -1730,6 +1743,196 @@ public void findByItemTabsWithCustomSecurityLayoutAnonynousTest() throws Excepti .andExpect(jsonPath("$._embedded.tabs[0].rows[1].cells[0].boxes", contains(matchBox(box2)))); } + @Test + public void findByItemTabsWithHiddenRelationshipsTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EntityType eType = EntityTypeBuilder.createEntityTypeBuilder(context, "Person").build(); + + EPerson userA = + EPersonBuilder.createEPerson(context) + .withNameInMetadata("Mecca", "Vincenzo") + .withEmail("vins@4science.com") + .withPassword(password) + .build(); + + Community community = + CommunityBuilder.createCommunity(context) + .withName("Test Community") + .withTitle("Title test community") + .build(); + + Collection col1 = + CollectionBuilder.createCollection(context, community) + .withName("Test Publications") + .build(); + + Collection people = + CollectionBuilder.createCollection(context, community) + .withName("People") + .withEntityType("Person") + .build(); + + Item firstPerson = + ItemBuilder.createItem(context, people) + .withTitle("4Science, Vins") + .build(); + + // RELATION.Person.researchoutputs + CrisLayoutBoxBuilder.createBuilder(context, eType, CrisLayoutBoxTypes.RELATION.name(), true, true) + .withShortname("box-shortname-one") + .build(); + + CrisLayoutBox box1 = + CrisLayoutBoxBuilder.createBuilder(context, eType, CrisLayoutBoxTypes.RELATION.name(), true, true) + .withShortname("researchoutputs") + .withHeader("Publications") + .withSecurity(LayoutSecurity.PUBLIC) + .withType(CrisLayoutBoxTypes.RELATION.name()) + .build(); + + + CrisLayoutBox box2 = + CrisLayoutBoxBuilder.createBuilder(context, eType, true, true) + .withShortname("box-shortname-two") + .withSecurity(LayoutSecurity.PUBLIC) + .build(); + + CrisLayoutFieldBuilder.createMetadataField(context, "dc.title", 0, 0) + .withLabel("LABEL TITLE") + .withRendering("RENDERIGN TITLE") + .withRowStyle("STYLE") + .withBox(box2) + .build(); + + CrisLayoutTab tab = + CrisLayoutTabBuilder.createTab(context, eType, 0) + .withShortName("details") + .withHeader("Profile") + .addBoxIntoNewRow(box2) + .withSecurity(LayoutSecurity.PUBLIC) + .build(); + + CrisLayoutTab tab1 = + CrisLayoutTabBuilder.createTab(context, eType, 0) + .withShortName("publications") + .withHeader("Publications") + .addBoxIntoNewRow(box1) + .withSecurity(LayoutSecurity.PUBLIC) + .build(); + + context.restoreAuthSystemState(); + + getClient().perform(get("/api/layout/tabs/search/findByItem") + .param("uuid", firstPerson.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", Matchers.is(1))) + .andExpect(jsonPath("$._embedded.tabs", contains(matchTab(tab)))) + .andExpect(jsonPath("$._embedded.tabs", not(contains(matchTab(tab1))))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", hasSize(1))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", contains(matchBox(box2)))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[1]").doesNotExist()); + + String tokenUserA = getAuthToken(userA.getEmail(), password); + getClient(tokenUserA).perform(get("/api/layout/tabs/search/findByItem") + .param("uuid", firstPerson.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", Matchers.is(1))) + .andExpect(jsonPath("$._embedded.tabs", contains(matchTab(tab)))) + .andExpect(jsonPath("$._embedded.tabs", not(contains(matchTab(tab1))))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", hasSize(1))) + .andExpect( + jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", contains(matchBox(box2))) + ) + .andExpect(jsonPath("$._embedded.tabs[0].rows[1]").doesNotExist()); + + context.turnOffAuthorisationSystem(); + + Item publication1 = + ItemBuilder.createItem(context, col1) + .withTitle("Title Of Item") + .withIssueDate("2015-06-25") + .withAuthor("4Science, Vins", firstPerson.getID().toString()) + .withEntityType("Publication") + .build(); + + context.restoreAuthSystemState(); + + getClient().perform(get("/api/layout/tabs/search/findByItem") + .param("uuid", firstPerson.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", Matchers.is(2))) + .andExpect(jsonPath("$._embedded.tabs", containsInAnyOrder(matchTab(tab), matchTab(tab1)))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", hasSize(1))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", contains(matchBox(box2)))) + .andExpect(jsonPath("$._embedded.tabs[1].rows[0].cells[0].boxes", hasSize(1))) + .andExpect(jsonPath("$._embedded.tabs[1].rows[0].cells[0].boxes", contains(matchBox(box1)))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[1]").doesNotExist()) + .andExpect(jsonPath("$._embedded.tabs[1].rows[1]").doesNotExist()); + + getClient(tokenUserA).perform(get("/api/layout/tabs/search/findByItem") + .param("uuid", firstPerson.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", Matchers.is(2))) + .andExpect(jsonPath("$._embedded.tabs", containsInAnyOrder(matchTab(tab), matchTab(tab1)))) + .andExpect( + jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", hasSize(1))) + .andExpect( + jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", contains(matchBox(box2))) + ) + .andExpect(jsonPath("$._embedded.tabs[1].rows[0].cells[0].boxes", hasSize(1))) + .andExpect( + jsonPath("$._embedded.tabs[1].rows[0].cells[0].boxes", contains(matchBox(box1))) + ) + .andExpect(jsonPath("$._embedded.tabs[0].rows[1]").doesNotExist()) + .andExpect(jsonPath("$._embedded.tabs[1].rows[1]").doesNotExist()); + + context.turnOffAuthorisationSystem(); + + RelationshipType hiddenResearchOutput = + createRelationshipTypeBuilder( + context, null, entityTypeService.findByEntityType(context, "Person"), "isResearchoutputsHiddenFor", + "notDisplayingResearchoutputs", 0, null, 0, null + ).build(); + + final Relationship publicationOneHiddenByFirstPerson = + RelationshipBuilder.createRelationshipBuilder( + context, publication1, firstPerson, hiddenResearchOutput + ).build(); + + context.restoreAuthSystemState(); + try { + getClient().perform(get("/api/layout/tabs/search/findByItem") + .param("uuid", firstPerson.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", Matchers.is(1))) + .andExpect(jsonPath("$._embedded.tabs", not(contains(matchTab(tab1))))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", hasSize(1))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", contains(matchBox(box2)))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[1]").doesNotExist()); + + getClient(tokenUserA).perform(get("/api/layout/tabs/search/findByItem") + .param("uuid", firstPerson.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", Matchers.is(1))) + .andExpect(jsonPath("$._embedded.tabs", not(contains(matchTab(tab1))))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", hasSize(1))) + .andExpect( + jsonPath("$._embedded.tabs[0].rows[0].cells[0].boxes", contains(matchBox(box2)))) + .andExpect(jsonPath("$._embedded.tabs[0].rows[1]").doesNotExist()); + + } finally { + RelationshipBuilder.deleteRelationship(publicationOneHiddenByFirstPerson.getID()); + } + + } + @Test public void findThumbnailUsingLayoutTabBoxConfiguration() throws Exception { context.turnOffAuthorisationSystem();