From 09ade7e912120f598f180ee99adb3922730c24f4 Mon Sep 17 00:00:00 2001 From: milanmajchrak <90026355+milanmajchrak@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:29:56 +0200 Subject: [PATCH] Customer UK - new release 3/June/2024 (#673) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ufal/downloading-restricted-bitstreams-not-working-properly (#457) * The admin could download restricted bitstreams. * The user cannot download bitstream if he/she is not signed in. * Cannot obtain context with user. * The user is already fetched from the context. * Added docs. * Do not use endpoint for downloading the single file because it already exists - remove it. * Fixed AuthorizationRestControllerIT tests. * ufal/be-cannot-download-and-preview-files-after-migration (#454) * Find bitstream format using mimetype not ID. * Updated tests according to fix. * ufal/update-canonical-prefix-to-hdl (#460) * Updated `handle.canonical.prefix` to hdl handle. * Integration test cannot have changed handle.canonical.prefix. * ufal/be-user-registration-missing (#463) * The user registration is added when the eperson is created by the ui. * try using newer checkout, same as upstream, since error is with git --------- Co-authored-by: MajoBerger <88670521+MajoBerger@users.noreply.github.com> * ufal/be-license-download-statistics (#462) * Add logging of downloading restricted bitstreams. * Log downloading of every bitstream not only restricted ones. * Added docs * Refactored logging. * ufal/be-shibboleth-headers-encoding (#464) * givenname and last name values are converted to UTF-8 encoding * Delete eperson in tests * using our dspace-dependencies because of https://github.com/dataquest-dev/DSpace/issues/466 * ufal/be-fix-email-parameters Fixed emails sending - added arguments and cfg properties that are sent in the email. (#470) * ufal/be-provenance-subbmitter-missing (#469) * #8585 Add submitter information to provenance metadata * Cherry picked fix from vanilla and added test to check if the Item provenance metadata is added --------- Co-authored-by: Adán Román Ruiz * ufal/be-get-user-ip-address (#468) * Created endpoint for fetching IP address with tests. * Made the code more understable * ufal/publisher-ok-fix (#473) * fixes ufal/clarin-dspace#1096 (#471) * Added publisher filter in the integration test check --------- Co-authored-by: Ondřej Košarko * ufal/zip-preview-configurable (#475) * Made previewing of the file configurable. * The default value of the previewing the file must be true in the integration tests. * ufal/fe-oversized-file-upload-message Exposed max file limit for upload from the cfg. (#477) * ufal/be-email-restricted-download * Fixed comments in the clarin emails (#484) * ufal/be-not-show-shib-welcome-page (#485) * Added cfg property to enable/disable showing of the page with attributes passed from the idp. * ufal/be-s3-customization (#481) * The bitstream data are stored in to local store after uploading to S3 * The bitstream is removed from the S3 and local assetstore * Store number is specific if all storages are synchronized. * Return store number in the BitstreamRest object * Find out which store is used - it could be synchronized stores number. * Constant is moved to the Bitstream class * Synchronization of storages is not allowed by default - set up it in the test environment. * Added docs * Removed constant from the Bitstream class - it wasn't consistent * Overriden BitstreamStorageServiceImpl by custom SyncBitstreamStorageServiceImpl * Removed ClarinS3BitStoreService.java to SyncS3BitStoreService * Added doc and refactoring. * ufal/be-s3-checker-sync (#486) * Fixed UserCheck - There was created a wrong select * Fixed ChecksumCheck - the session was closed but there were some requests do the database then * internal/load-version-from-file (#488) * Load version from the specific file and show content in the root endpoint. * Fixed checkstyle issue * DO not log anything if the VERSION file does not exist. Added VERSION file path into cfg property. * Append every line into final String. * ufal/be-s3-checksum-fix (#487) * Cherry picked fix S3 optimalization fixes from Vanilla * Cherry picked adding of pagination on cleanup * Updated Sync services according to S3 optimization fix * The checksum value is compared between S3 and local assetstore and the new result is inserted to the database. * Added docs and refactoring * The checksum values are exposed by REST API * Fixed failing tests --------- Co-authored-by: Tim Donohue Co-authored-by: Luca Giamminonni * internal/versioning (#491) * add version to docker * Allow shell because it is using double quotes in the command string. * removed cat and ls commands --------- Co-authored-by: MajoBerger * ufal/comment-ever-failing-test * Commented still failing tests (#490) * internal/verion-update-path (#492) * Updated `build.version.file.path` because the server cannot find `VERSION_D.txt` file * Added VERSION_D.txt info `.gitignore` * User ${dspace.dir} instead of absolute path * internal/be-upgrade-clarin-dspace-7.6 (#497) * Split docker image builds into separate jobs to allow them to run in parallel. * Ensure 'main' code is tagged as 'latest' in DockerHub * Fixes #8558 - set Solr UTC timezone Set the timezone of the Solr date formatter to UTC * remove obsolete code fragments * Add action to automatically create a port PR when specified (cherry picked from commit f6a898c3d13360286c416b2588ab0447d9e3d81b) * Run PR Port action as 'dspace-bot' to allow new PRs to trigger CI checks * Minor update to label_merge_conflicts to ignore any errors (seem random at this time) * Fix typo. Config must be a valid regex (cherry picked from commit 799528963e3c0391852ecbaf82ef21ec7d477342) * Bump h2 from 2.1.214 to 2.2.220 Bumps [h2](https://github.com/h2database/h2database) from 2.1.214 to 2.2.220. - [Release notes](https://github.com/h2database/h2database/releases) - [Commits](https://github.com/h2database/h2database/compare/version-2.1.214...version-2.2.220) --- updated-dependencies: - dependency-name: com.h2database:h2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Update FullTextContentStreams.java Fix NPE if bitstream is null * Update FullTextContentStreams.java Add additional NPE checks * Update ItemUtils.java Prevent npe if bitstream is null * dspace.cfg: remove old webui.itemlist properties These properties are no longer used in DSpace 7: webui.itemlist.widths webui.itemlist.*.widths webui.itemlist.tablewidth (cherry picked from commit 16c46c49797cf4a15b8ef51efdd365610bdf73ab) * dspace.cfg: remove old webui.browse.thumbnail.show property The webui.browse.thumbnail.show property is no longer used as of DSpace 7. Also remove subsequent references to adding thumbnails to item view columns since these are from legacy DSpace. (cherry picked from commit 213a546486073f09e73d91d014c489ed300bf59d) * dspace.cfg: remove old webui.itemlist.browse.* property The webui.itemlist.browse.* properties are no longer used in DSpace 7. (cherry picked from commit 35f72bc9d0c1a01aa0b9313216bbbe63e6960a81) * Fix #8963: Remove deletion constraint from Groomer * Enable entity type to submission form mapping by default (cherry picked from commit b71eee89c1e1dd7569e800e13eb8878548853ce6) * [DURACOM-179] replaced 'null' value with exception actual value in sendErrorResponse method calls having 'null' (cherry picked from commit aa35a47add5565a9302d276da2ceb22b8dbc320f) * DS-8935. webui.browse.link CrossLinks - Fix for multiple exact matches Fixes #8935 when multiple exact match "webui.browse.link" configuration entries are present that point to different indexes. Modified the code to return the index associated with the given metadata (which is used as the key in the hash map), instead of the key from the keySet (which may not actually be the metadata value being searched for). https://github.com/DSpace/DSpace/issues/8935 (cherry picked from commit b846c53baaeae1e19fbbafa3dc7ca724bcaf32c1) * #9006 fix referenced configuration file (cherry picked from commit 29a88d7e2dcfc36d2cd7991de3b84ef5f5623b63) * #9006 fix referenced configuration file (Test) (cherry picked from commit 309b0b355e4bffd6a1be3e6341dd6d17f99892c8) * Fix #8933: Only add the base statistic core if it hasn't already been added * Remove duplicate code * On failure log the name of the assetstore file and trace causes of exception. (cherry picked from commit 22974e982c99b7faa9d287ddc5bef4715f19849a) * Report Throwable's type too. (cherry picked from commit d6b612fc5cf84fe6b7226649451b7b927ded8997) * More description on OutOfMemoryError too. (cherry picked from commit bbe5df3f7dd4a33423fdf47702e23f3eb9ef821f) * Remove useless log.info (cherry picked from commit 1f3ad993cc4d10694112227245be3de1ec7b3762) * 103837: Refactor GA config to list bundles * README.md: Fix typo (cherry picked from commit ca8abddff1230e581501b482623966e64016d609) * Bump up versions of buildnumber-maven-plugin & build-helper-maven-plugin. add configuration for SCM failure (cherry picked from commit 78ea9e86df5e6737a4ce129120a6e1e6c74a371c) * 3331 - remove the --optimize feature of 'dspace stats-util' (cherry picked from commit 08c650921d7ce5210906db846ff29a053c2155a7) * fix MissingOptionException on help (cherry picked from commit 8ae5ffbf9b41fe2ad4e1146eceeff47e6ba985a0) * fix stylecheck (cherry picked from commit b1377ca1ef82d80f2ece9b48b8f1571e786c4525) * ingore unrecognized arguments on help (cherry picked from commit 82c9b6fc9baee9f4f5d8b4cc967b5d12b63cdd39) * add DSpaceSkipUnknownArgumentsParser as parser to ignore/skip unknown arguments in cli by help, fix not necessary ParseException in help (cherry picked from commit 86285d78aa0844b9811dcebdefa897ceeb944226) * remove not necessary else (cherry picked from commit 064e2caa37dfa283c3c08dee0e7321e36073bfa2) * Enable new skip merge commit feature * dspace-api: remove unnecessary trailing whitespace * 103818 ItemServiceImpl#inheritCollectionDefaultPolicies now clears item READ policies if new parent collection has a default READ policy * 103818 Add boolean parameter to ItemServiceImpl#inheritCollectionDefaultPolicies to decide whether to override item read policies * 103818 Add boolean parameters to ItemServiceImpl methodds to decide whether to override read policies * 103818 Extend ItemServiceTest#testMoveItemToCollectionWithMoreRestrictiveReadPolicy * 104878 Fix error in ItemServiceTest related to inheriting collection policies upon item move * 104878 Adjust ItemServiceTest to expect correct behavior of bundles when item is migrated * Fix failing IT in BulkAccessControlIT * 103837: Fix isContentBitstream() in GoogleAsyncEventListener * Rename test suites that are really integration testing. (cherry picked from commit f66ca33b0627c1b0789c9c3ce407463f5dc3356e) * Bump org.eclipse.jetty:jetty-xml Bumps [org.eclipse.jetty:jetty-xml](https://github.com/eclipse/jetty.project) from 9.4.51.v20230217 to 9.4.52.v20230823. - [Release notes](https://github.com/eclipse/jetty.project/releases) - [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.51.v20230217...jetty-9.4.52.v20230823) --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-xml dependency-type: direct:production ... Signed-off-by: dependabot[bot] (cherry picked from commit 2bcc0b38a9436b0abc4c54e419f0fa6ae194269c) * Add note that rebooting Tomcat required * Add websvc.opensearch.autolink and websvc.opensearch.shortname to exposed REST configuration properties (cherry picked from commit 80b35c9650ec2f40bea3b497b65ce77d0c97bfcf) * Add a "container friendly" log4j2 cfg and output compose dspace log to console (cherry picked from commit 9eefd56cd7013730ff43969b321d6cbee2a3ae64) * Fix ClassCastException (Collection cannot be cast to Item) in Handle identifier classes (cherry picked from commit 1271374d37a3f7d9cec270e54ec106895aa934bc) * Fix checkstyle. Correct grammar of comment while doing so. (cherry picked from commit ffa2683c632cfab59b0432c203434ac15a6eb85f) * Avoid double slashes in sitemap paths. (cherry picked from commit eae4463eaa5916bd9b20f4e4132398aceeba1f02) * Remove 'cross join' from count query. Updates "countHandlesByPrefix" to use a query similar to existing "findByPrefix" (cherry picked from commit 14223bd712ce91cf97096f2201924baea8456814) * fix logical bug when checking if field is controlled authority * remove optimize option from oai import * added authorization check for license bitstream in OAI import * OAI: add support to extract embargo from bitstreams and expose it in OAI metadata (cherry picked from commit db81d758a947a9bdbb63fea9e872bc9b52a377ff) * ItemUtils.java: added method doc (cherry picked from commit 51e60fbcf92ea731c4e355c9cf080d251ffbf68f) * ItemUtils.java: improved method to account for multiple embargo policies and select the longest embargo (cherry picked from commit 538be7f09ba790a4ab7099e7027e1e8f6a9c62ea) * Refactored access-status to include embargo date based on the DefaultAccessStatusHelper logic (look at primary or first bitstream) (cherry picked from commit 895926f021a355181faef47b5c41e78031700475) * Remove unused imports (cherry picked from commit 4bd2cfdf0f931aec7a05db42f255423fe806ea77) * Fix style issues (cherry picked from commit 724a4ffb0ed9ffefb2866930655767590b462bb5) * Fix style issues (cherry picked from commit 6e2c8a4ae0068d844d0fc796001c170c8849babf) * Add null check (cherry picked from commit 0de4c3945ed7f30d41841cda4bf01acf9ffc130f) * ItemUtils.java: refactored addEmbargoField (cherry picked from commit 291afa765d29836a67727fdd2f82ac0c9f9310c4) * uketd_dc.xsl: also expose access-status if embargo or restricted (cherry picked from commit 4b40872a6d5a3934c1f79c6babf439a21ce25f66) * DefaultAccessStatusHelper: fix logic to take shortest embargo (cherry picked from commit d17ef09082aa237cffdc928d9560667487c2c976) * Remove currently unused customisation of ItemUtils (cherry picked from commit 490a982e8055991a6b8cbacece22b924466e22df) * DefaultAccessStatusHelper: getEmbargoFromItem return null embargo if status than embargo (cherry picked from commit e05e73a112ce60bd0689ce68af442382712bd5fc) * Additional Item class cast fixes in handle providers DSOs were not properly checked if they were instanceof Item before attempting the cast in HandleIdentifierProvider and VersionedHandleIdentifierProviderWithCanonicalHandles * Remove Oracle script that accidentally made it in via #8800 (cherry picked from commit 5e04edf41e452cd383597680da9c3101211156b8) * 8968 - request-a-copy email: non ASCII characters are encoded as HTML character entity references (cherry picked from commit db36d5eeae3e76b61178c2c7ac4243bc2fc20a97) * unused import (cherry picked from commit bf6e042085140e305d43d61ddce564fbfe819c7f) * 8968 - added custom StringEscapper (cherry picked from commit 103c8ee75771d3d9e58e530b8855d07cc14598c2) * checkstyle (cherry picked from commit 2c2b3b18dc781054539add48ca74e4bf688c400c) * 8968 - implementated using HtmlUtils scaping (cherry picked from commit 090beedb6f692df29d1a61d4c2e6fde09d4b4c1d) * checkstiye (cherry picked from commit d12fbe2c340e18e42dba4380ee9976bccb4ca421) * Define _version_ * #8585 Add submitter information to provenance metadata (cherry picked from commit c15ac0eb4a3d39a0de47adbfa5260a6f3b396837) * 8585 - added provenance to metadata-import and itemImport (cherry picked from commit ea6307dcc68a75c935049a02022145691693cff4) * dspace-api: fix misaligned comment (cherry picked from commit 4fba787322803cc36ef267f0d6913b92c1eaeca4) * oai_openaire.xsl : change resourceTypeGeneral for thesis Thesis are "Literature" resource type (resourceTypeGeneral), not "other research product" ref: https://github.com/openaire/guidelines-literature-repositories/issues/43#issuecomment-1318262914 and https://api.openaire.eu/vocabularies/dnet:result_typologies/publication (cherry picked from commit 669ff343503539aa6fc8b23600989ab958a403b9) * Bump org.eclipse.jetty:jetty-http Bumps [org.eclipse.jetty:jetty-http](https://github.com/eclipse/jetty.project) from 9.4.52.v20230823 to 9.4.53.v20231009. - [Release notes](https://github.com/eclipse/jetty.project/releases) - [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.52.v20230823...jetty-9.4.53.v20231009) --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-http dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump org.json:json from 20230227 to 20231013 in /dspace-api Bumps [org.json:json](https://github.com/douglascrockford/JSON-java) from 20230227 to 20231013. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-type: direct:production ... Signed-off-by: dependabot[bot] (cherry picked from commit 11a08f1ac0a9b75bf3f2869d3760b2f0e229aefe) * Reading localized license file. * Reading localized license file. * Applying commit 6108c98d82f3cbf00e248f83535b06da4040ece4 * quote Pattern for thumbnail resolution constructed from bitstream filename (cherry picked from commit a1248074681a7bc4603176fb3e7d989b91edcbcd) * check null value of bitstream name before quoting name for regex (cherry picked from commit a9bcc0c223d0219f464d986d7b7c66b3c4cbc39c) * extract bitstream thumbnail name pattern into own function (cherry picked from commit c5466c2249c092f6638a7072b57c934d1d3581b5) * Make workflow curation tasks actually work. When curation runs, there was no "current user" and no claimed task, so the code broke when trying to find people to notify about curation failures. (cherry picked from commit a76af35a0cd4f0c0e8737c736578b17bcc349691) * Community request: fake EPerson from configuration. (cherry picked from commit bb9e88d1bb452d0865f4827134baf907e6d34044) * Correct some documentation. (cherry picked from commit be22790aad7f627e2ac027773e272b703986f589) * Handle missing role. (cherry picked from commit 2e62fa3fd1f264aac0bb4a12953b6385211e5656) * Fix "Site cannot be indexed" error by ignoring ADD/REMOVE events on Site object (cherry picked from commit ef7f02fe81bc570353c0bf6a43706c77909e30e3) * Add a null check when assigning ldap groups Prevent NullReferenceException by checking if the group list is null Fixes #8920 (cherry picked from commit bb6498ed5e4696201d3e45bd377faa407dca277f) * 9043 use Templates for compiled XSLT instead of Transformer - use Templates are thread-safe and NOT Transformer (cherry picked from commit 1160341cb2a2c163c8fddc04ddab46de9041e1b8) * Update to newly released XOAI 3.4.0 (cherry picked from commit 160ebbd791c0545db6516403da40cb191a2c8b99) * add test and fix (cherry picked from commit 48b0b71c6301b6eb46c387c47b71d0729cc2f889) * unset primary bitstream on bitstream service (cherry picked from commit 47ca74bc4220249b95de9b8e71186277c9ac31ca) * adding sql expression to fix deleted primary bitstreams from bundle (cherry picked from commit 8a531ad0c7e8fdf09fa9a3870024687e6708a9a1) * add bundle remove authorization (cherry picked from commit 3255e073fa110a3354f1265853bbf531c677f6ea) * adding missing bundle REMOVE authorization (cherry picked from commit 4a05600194fb9be7e19084f3a9106a0152fd0d80) * add missing head style check (cherry picked from commit caba4bbb96f56c103c4dd8ac9f9fa5863b40e04c) * fix style errors (cherry picked from commit 74605f159af5e53a3e890f578732a858cef12e51) * new testDeleteBitstreamAndUnsetPrimaryBitstreamID test for primary bitstream verification (cherry picked from commit e6d108a94e41e58d6d701f3ef0429fda438e6555) * new testDeleteBitstreamAndUnsetPrimaryBitstreamID test for primary bitstream verification (cherry picked from commit ad0d22a13a35a2167557efeb5ddea7a3a504424d) * new testDeleteBitstreamAndUnsetPrimaryBitstreamID remove unnecessary stubs (cherry picked from commit a3e506c7f452133e3cc973705d671dba61a469d6) * make comments more clear to understand (cherry picked from commit c0bbd9d91f894fbe26f8cf7c4f166da8ba1cefd3) * typo (cherry picked from commit 74cce86afcc163c52502892556679e6175fa1948) * Add basic pagination to /groups/[uuid]/epersons endpoint (cherry picked from commit 74c72354b405ed266b65cdd50b594d25bea0e87f) * Bug fix. Only use pageSize and offset if >0 (cherry picked from commit 15de2d0074b56f421b3bbb9f3955814497985aef) * Add missing pagination test for /groups/[uuid]/epersons (cherry picked from commit 457dd9ae441fa084ff7cc3eaf9213e5497a2b298) * Add pagination to /groups/[uuid]/subgroups endpoint, along with tests (cherry picked from commit e7c4b9eba2d8148e07543c3b6c61dde359018da2) * Add basic unit test for new EpersonService methods (cherry picked from commit c000e54116498030261d988f87a496beef7d21d1) * Minor unit test fix. Use isEqualCollection to compare list with Hibernate results (cherry picked from commit cdb68a6fdc925fcbb76f9265e64771497b3f78bc) * Add countAllMembers() with tests. Update tests to use try/catch (cherry picked from commit 58a15b72975940d48ae450e6b46557b4443f2978) * Replace several usages of allMembers() with count methods to avoid performance issues (cherry picked from commit 2c9165afb08126189ee3367347e7011f89227b7c) * Fix bug in logic for determining whether a workflow group will be left empty. Need to check *both* EPerson and subgroup counts. (cherry picked from commit 9832259aa06d9fe140407ed54c4687989e98f7b2) * Use join instead of subquery as join seems slightly faster. (cherry picked from commit 9c0bf08cf4c3ab7e941ebe1bae66cf2aea720697) * Address feedback. Initialize HashSet sizes to avoid resizing. Correct comment about indeterminante ordering. (cherry picked from commit f011a5a5dbcd2def47dde7830981cf282ca660aa) * Allow users with write permission to view hidden metadata (cherry picked from commit 65a17d4390aeab69c191fb75559646aec9dda512) * Test modification: allow users with write rights to see hidden metadata (cherry picked from commit df7f6e9f4082e5aef3392932f8a87177ac202655) * Add test to check that user with read rights can see hidden metadata (cherry picked from commit 03496c36d4d47138bcd51badf8daca720d4cc484) * Verify optional message is not missing or a literal "null" value (cherry picked from commit 534ee3a699937eedd11aa5cb54f97b081bcda621) * Change the database mode to READ_ONLY during the indexing by discovery consumer (IndexEventConsumer) (cherry picked from commit 94822b50af4098d990d63e27bb3906cfa9c0ec37) * Add functions to do a manual flush of the db session and call flush before change to READ_ONLY mode to be sure we index the current object (cherry picked from commit c33d3fa87d6c29533d379939bd23b29ff3d9b5c9) * Flush database changes after switching to READONLY mode (cherry picked from commit 00a65312ccb52481cd72653b4c5465b7d16c760e) * Add test to check retrieving of policies after changing mode to READ_ONLY (cherry picked from commit d19a9599b5f08a567c93d2e167e219673518fb78) * Change class name to ContextIT and correct a test (cherry picked from commit a5567992bbe456cd33c68f695a2364f507149e7a) * dspace/config: update spider agent list Update list of spider user agents from the COUNTER-Robots project. See: https://github.com/atmire/COUNTER-Robots (cherry picked from commit 7566a79d906b5050bef01d22c5f4b3e4ab6e4b58) * removed options to ping search engines when generating sitemaps (cherry picked from commit f8f88060408c30314cdcf38ba5bbac0f367ee3fd) * XmlWorkflowCuratorServiceImpl: add check to queue task if configured; Curation: remove obsolete code preventing curation running on workflow tasks as #3157 is now implemented * Return both user and operational LDAP attributes Explicitly request both user and operation attributes for LDAP group search as the default searching does not include operational attributes. This is required to fetch the memberOf attribute when checking LDAP group membership. Fixes #9151 (cherry picked from commit 56b7cbf4dbcc4a1ec201518f291c119470cc4e93) * [DURACOM-200] improvement of checker script (cherry picked from commit 5a7c7956cd4e8b47f6a6f53adbc646adeddb0f88) * 108055: isClosed method should use xml configuration (cherry picked from commit d800d800d5346ea9a526ba2a880fc93a6892da98) * [DURACOM-192] Authentication Method related special groups are put in claim set even if a different authentication method is used (cherry picked from commit 6504d749b91508096300e4545069a0554eb5934b) * [DURACOM-192] Added test (cherry picked from commit fa39251071156a6eeb1030000f50761663e128e2) * 107891: Cache administrator group (cherry picked from commit 1e82ca7998c45bd628cd84cefce9ae3f0a0ce046) * DURACOM-199 improved test to show bug related to restricted content (cherry picked from commit dac4df9c1a0b813d2b7578a17c79dd1e9f798a55) * DURACOM-199 fix sitemap generator for restricted content and improve performance (cherry picked from commit 6d9ca388dac3a632530eccbdeda955f7842aae84) * [Port dspace-7_x] Event consumer for submission config reloading when a collection changes (#9196) * initialization with refactoring (cherry picked from commit e93dc1cf4586f684bb441eb0341b4f14393abde5) * also consider SubmissionConfigReaderException (cherry picked from commit 8a04b8775088a82ded154e325a6cb0ce250f1a2e) * rename consumer file (cherry picked from commit f6c92a4c8b25fccc6920646f99e09dd967a2ccf2) * init submission service factory (cherry picked from commit fcc52390b98e3a92927d7a99d9fcf57579a8ed97) * set submissionconfig config settings by default (cherry picked from commit e343d515198950dae7ddb705fee5b34cc7ee0eec) * renaming SubmissionConfigReaderService (cherry picked from commit 9ea7c321c374a0058935efa33e1c2941d6aeb602) * support for SubmissionConfigService (cherry picked from commit 61389fb7876a0757eaac497737aa2cfcd4d4c55a) * fixing style errors and renaming submissionConfigService (cherry picked from commit 5f49491b53c2570fa12bf725a7324e7d7338fc9c) * fixing style errors and unused imports (cherry picked from commit 31d92519508f676659c2efb9e6b9a9089305016d) * set default submission event configs (cherry picked from commit 578198c588f5e7f0da6448f1b4497a041df7fddd) * adding force indexing action to Consumer (cherry picked from commit b91236434f38e8d3510aae816f6e2e871517fb70) * stylecheck fixes (cherry picked from commit 89e89c3d8a7ef8b77a8388cde9905c7fdc1b4bba) * undo event.dispatcher.noindex.consumers (cherry picked from commit ae9dc5f0058f8c7ceb4fb960fc3ca3343fac3763) --------- Co-authored-by: Paulo Graça * Add isNotMemberOf for groups, including unit and integration tests (cherry picked from commit 9d271b24b9721741a53142a690b86287efb738fe) * Implement searchNonMembers for EPersonService. Add tests to prove it works (and tests for search()). Requires minor bug fix to AbstractHibernateDSODAO to allow for additional OR/AND clauses to be appended. (cherry picked from commit f186dcf4ca17f56478ce27946acdc2c269d8bd50) * Add /epersons/search/isNotMemberOf endpoint to REST API along with integration tests (cherry picked from commit 5208a355d69c86dc7cb3ea372656c6959664fd9a) * Bug fix to EPersonDAOImpl. Correctly determine if excluded group needs to be preceded by AND or WHERE (cherry picked from commit e5e0eaa9999a96f499c131e02877d4280f7b5263) * Updated IIIF Controller IT to text bitstream and bundle exclusions (cherry picked from commit e92b4b7bfdc08efab9aee9b8f07506273ee2bfcb) * Simplified the process of fixing the tests after adding new sidebar facets/search filters and sort options to discover.xml (cherry picked from commit b40ad0dfc23040f335d6c6be0fcd0ae6e68a318f) * 107671: Expose the handle.canonical.prefix to the frontend (cherry picked from commit 6d86e65b720b5108e94b1df85e6038394c183214) * Remove line breaks from default.license because they are being rendered in the frontend (cherry picked from commit 56aae347c2a7012af912a8893142fc04809e7ff3) * [Port dspace-7_x] subscription email: do not send email if nothing has changed (#9204) * improved subscriptions email template (cherry picked from commit 6e7b32795930ea3c0758875c654e95b8602cf9b3) * do not send emails without content (cherry picked from commit 926b2421302587d69318f208b48e334cab57b204) * fixed coding style violations (cherry picked from commit fdacec08df8f930ff7c45745a20297a10eff3ad2) * removed unnecessary isEmpty check as suggested by reviewer (cherry picked from commit 30a837f85403332c31761880a0ed936996ba1b5a) * moved null check on indexableObjects in generateBodyMail (cherry picked from commit b43c340b182a62ddc51e3fd7e294101f6d355e90) * fixed unhandled IOException (cherry picked from commit 9b3f7b698c3efbff165fb727ac91609dbe569218) * fixed typo in bodyCommunities (cherry picked from commit ac3d02eb1ce83f9e1fee55f69f1c0fd2c0e03332) * do not use != to compare strings (cherry picked from commit e46018333508215fce7225b75a5af50d4d7beb59) * fixed improper handling of empty list (cherry picked from commit ac72aae44b5ce49ec1a8ddfa2b7986d0d580a8ac) --------- Co-authored-by: Sascha Szott * [maven-release-plugin] prepare release dspace-7.6.1 * Fixed checkstyle issues * Fixed compilation errors * Removed redundant service definitions in the `core-factory-services.xml` because unit tests was failing * Removed redundant bean in the `discovery.xml` * Removed redundant `latestVersion` from `schema.xml` * Fixed wrong resolved conflicts - the app cannot start running * Used ClarinVersionedHandleIdentifierProvider instead of Vanilla one in the `identifier-service.xml` * Fixed tests - the user has an authorization to remove bundle * Fixed failing test in the `MetadataExportSearchIT` it was trying to test dateIssued filter, but the CLARIN DSpace doesn't use that. * controlled.authority.dc.relation is changed in the configuration by CLARIN so the test VersioningWithRelationshipsIT is failing because of that. * Fixed wrong license validation class * Removed test which was accidentaly added durign resolving conflicts * The ACL tag restricted loading of some input field which was missing in the assert * The test cannot convert `Oct` from the xml to normal number because of Slovak default locale which doesn't know what `Oct` means in the date. I set up EN locale for the current test * Added clarin set up of search Facets into integration tests - because src/test/java/org/dspace/app/rest/DiscoveryScopeBasedRestControllerIT.java was failing * Added method `areSpecialGroupsApplicable` into ClarinShibAuthentication because after shib authentication the user wasn't assinged into special group because of some dspace new feature * Change DEFAULT_AMOUNT_FORMATS in the BitstreamFormatRestRepositoryIT.java because vanila has added a new format. * Ignored still failing RegistrationRestRepositoryIT test - it is ignored also in the 7.5 version * fix: Failure of org.dspace.app.rest.SitemapRestControllerIT when running locally * Ignore pubmedImportMetadataGetRecordsTest or allow ssl * Let the pubmedImportMetadataGetRecordsTests ignored * Fixed CurationIT - it failed on the Stream because Stream has null param. Null param was because of null handle on the Site object - the site handle was removed in the `ClarinHandleImportControllerIT.java#createHandleWithoutDSpaceObjectTest`. * Do not delete site handle in the HandleRestRepositoryIT * Updated scripts for fast building 7.6.1 * Moved flyway script for updating checksum_results into separate file * Added missing headers --------- Signed-off-by: dependabot[bot] Co-authored-by: Tim Donohue Co-authored-by: Sean Kalynuk Co-authored-by: Sascha Szott Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Agustina Martinez Co-authored-by: Alan Orth Co-authored-by: Martin Walk Co-authored-by: corrado lombardi Co-authored-by: David P. Steelman Co-authored-by: Christian Bethge <54576195+ChrisBethgster@users.noreply.github.com> Co-authored-by: max.nuding Co-authored-by: Max Nuding Co-authored-by: Mark H. Wood Co-authored-by: Nona Luypaert Co-authored-by: Christian Clauss Co-authored-by: Hrafn Malmquist Co-authored-by: aroman-arvo Co-authored-by: Christian Bethge Co-authored-by: Koen Pauwels Co-authored-by: Mark Cooper Co-authored-by: nwoodward Co-authored-by: Kim Shepherd Co-authored-by: Marie-Hélène Vézina Co-authored-by: damian Co-authored-by: Gantner, Florian Klaus Co-authored-by: wwuck Co-authored-by: Paulo Graça Co-authored-by: Toni Prieto Co-authored-by: mohamed eskander Co-authored-by: Jens Vannerum Co-authored-by: Luca Giamminonni Co-authored-by: Andrea Bollini Co-authored-by: DSpace Bot <68393067+dspace-bot@users.noreply.github.com> Co-authored-by: Michael Spalti Co-authored-by: Alexandre Vryghem Co-authored-by: Shankeerthan Kasilingam * The cas.init() method is called in the VocabularyRestRepositoryIT#setup() method * Update docker.yml (#502) dspace-dependencies job was missing * Update docker.yml (#503) Fixed dspace-dependencies error * Update docker.yml (#504) * Empty commit - run actions * use checkstyle before commit * remove fix duplicate dependency * remove discofeed related fetching from obsolete discojuice servers (#508) * remove discofeed related fetching from obsolete discojuice servers * check style, turned off in testing, turned of by default * fix failing test --------- Co-authored-by: jm * ufal/cannot-upload-big-file (#533) * Do not compute localChecksum because it takes too long for the big files. The checksum is computed using DigestInputStream object. Copy content into sync local assetstore using buffered copying. * Fixed checkstyle issue * Updated comment about creating required directories * ufal/license-agreement-wrong-behaviour (#534) * The all transactions are not updated in the user metadata after a new download.. * Return the user metadata depending on user registration, bitstream, mapping and the last translation. * Fixed checkstyle issues * Fixed failing integration tests - do not fetch user metadata for testing by ID where there are more tests which creates the user metadata * internal/discofeed-it (#535) * Disable SSL check for specific discofeed requests * Fixed checkstyle issues * Do not throw error in private constructor * Fixed failing IT - ssl check wasn't disabled * Ignore integration test which is trying to connect to our private network. * allow running from branch rework-actions for testing * ufal/s3-check-etag (#537) * Temp commit - upload a file by uploading 50MB parts * Added uploading the file by parts - for every part is computed checksum and compared with UploadPartResult's ETag. This feature could be enabled or disabled by cfg. * Undo S3BitStoreService changes * Fixed checkstyle issues * Prettify the code * Changed cfg property to be better understandable and file size is converted into constant. * ufal/allow-impersonating Allow impersonating by default (#539) * correct branches for main gh actions * Rework actions (#540) * run correct actions on correct repos * remove old docker job, separating it to several * reusable build yml from upstream * upstream docker.yml version * first test run * steppify docker.yml action to be able to add more steps * added python version to reusable build * fix incorrect usage of steps in gh action * corect the type in reusable wf * correct condition in python version script * corrected the branch * corrected image dockerhub owner * no linux/arm64 * comment out unused tasks; minor corrections * do not redepoy becuse jm said so * do not use codecov * disable deploy differently * extend possibilities for using version script (#542) * parametrized output of python version script * RUUUN * correct version placement * correct branches for run of gh action * Fix all mistakes in the /home page (#543) * Configured browsing by language * Updated tests following the browsing cfg * reusable run provides links to run and it's ID * first attempt at tag release action * also release images under github.sha * Improve version info, add release-tag action add run link to version info correct image for tests (remove dspace-dependencies from migrate to 7.5) add action to release on tagging * add necessary option to tag-action * Fixed all mistakes in the Item View page (#551) * Remove the xml info and bibtex tag from the citation refbox * Show handle and DOI in the Item View following the new cfg property * Made updating xml string more generic * Updated the method name for the getting text content from the bibtex xml. * Fixed all mistakes in the Search page (#549) * File size in the MetadataBitstreamWrapperRest changed to `long` type instead of String, the FE transfer all bytes into readable form. * Changed default sorting options * Added a new search configuration for the homepage, because searching by `dc.date.accesioned` must be removed because of clarin requirements, but the homepage uses searching by `dc.date.accesioned` * Configured searching by Item Type in the search page. * Updated community indexing - added _filter and _keyword because they are needed to work as facet and filter * Updated `Rights` and `Community` configuration. Changed to `text` type. * Allow Site usage reports for the Anonymous user * Fixed MetadataBitstreamRestRepositoryIT - the Matcher has a problem to compare long types. * Fixed DiscoveryScopeBasedRestControllerIT - the expected facets and Matchers did must be updated. * Fixed ClarinDiscoveryRestControllerIT - the expected facets and Matchers did must be updated. * Use `dc.contributor.other` metadata field for mapping the authors (#557) * Added `edm.xml` registry (#559) * Added `edm.xml` registry * Fixed cfg for `edm.xml` * Updated shibboleth cfg properties (firstname, lastname, netid, email) (#558) * Updated shibboleth cfg properties (firstname, lastname, netid, email) * Keep vanilla shib headers for the integration tests * during release, retag cli image as well * Recent submissions are loaded on the collection page. (#567) * Disabled showing `Accesioned sort option` by cfg (#568) * Disabled showing `Accesioned sort option` by cfg * Fixed when the `sort.options.filtered` property is empty * Turned off signposting (#571) * Turned off and tested on dev. * Allowed signposting for the integration tests * Show all values for the Subject facet in the search page. (#569) * Updated fast building app after config change. * Added a new search facet to return facet values with and without splitter. With - search page side bar, without - homepage. * Show values in search page and do not show them on Home page, added tests. * Fixed tests which were failing because of Solr indexing updates * Updated interpolation of Subject following the update from 7.6.1 (#620) * use true, for cmdi crosswalk (#629) * use true, for cmdi crosswalk * test fix * migrate DIM2DataCite v4.5 [Port dspace-7_x] Update of DataCite crosswalk to metadata schema 4.5 Co-authored-by: Tim Donohue * Updated `submission-forms.xml` following actual v5 `input-forms.xml` (#633) * Added missing inputs, defined a new complex inputs and copied vocabulary values without interpolation from v5 * Translated added vocabularies * Removed sequence number from the complex input field * Added `clariah-submission` * Added teaching materials form * Added czech translation of submission-forms.xml (#636) * Created submission-forms_cs.xml for the czech translation of the submission-forms.xml. And allowed cs locale in the config. * Added `webui.supported.locales = en` property into test cfg because IT expect only `en` locale. * Added a new log4j appender for logging file downloads into `file_download.log` file. (#634) * remove TUL references in code * deTULify * return required props * do not mess with lines * Synchronized spider config with ufal (#635) * Copied `ufal.ignore.txt` spider * Removed conflict IP address * Fixed IP with `/` instead of `.` * The IP address must be in the format `74.86.158.0/24` * The max file preview size is loaded from the cfg (#630) * The max file preview size is loaded from the cfg * Removed a condition to not preview files longer less 3 chars. And updated condition to check if the file is file or a folder. * Added email validation and input/output encodings are loaded from the cfg. * Revert "Added email validation and input/output encodings are loaded from the cfg." This reverts commit 9d40f009b261d6bea5f69b1458a1652889e0ad64. * load matomo url from cfg * forgotten remove comment * Reserve PID on the start of the submission. (#649) * Upload big file differencies (#647) * Update hint for big file upload * Do not delete big file after upload by default - changed cfg property. * Refactored checking if the file should be deleted after upload. * Remove big file metadata after every save metadata * Updated indexing of the hidden Item for the OAI-PMH (#650) * Updated indexing of the Item for the OAI-PMH: show the Item if it is hidden from the search. * Updated doc * Send Authorization request if the User is not allowed to see restricted Item (#646) * Shibboleth login - Added email validation (#644) * Added email validation and input/output encodings are loaded from the cfg. * Fixed checkstyle violation * Refactored condition which check empty character in the email. * Show Download all as ZIP button only when all conditions are met (#641) * Defined `local.files.count` and `local.files.size` and that values are added into metadata fields during updating of the Item. * Defined downloading zip cfg properties * Exposed download zip cfg properties * Removed commit which starts active session and because of that some tests are failing. * Removed VersioningWithRelationshipsTest.java because it is duplicate of VersioningWithRelationshipsIT and that is also removed from Vanilla * Update Item's file metadata in other place - not in the ItemServiceImpl#update because it is causing errors * Count files info only for the ORIGINAL bundle * Updated StatisticsRestRepositoryIT.java in the way that creating of some bitstreams are done in the setup when the Item is still persisted and not detached * Removed the function from the ItemServiceImpl#update method * fix problems displaying oai in various formats (#653) fixed wrong number of parameters expected in java code and wrong number of parameters sent in xsl file * Set up dtoken for every bitstream of the zip file. (#652) * Updated xoai.xml - changed filters, conditions, refactored (#631) * Updated xoia.xml following the actual xoai.xml in v5 * Empty commit to run actions * Fixed path to the ColComFilter in the xoai.xml * The bitstreams cannot be seen after the item is created (#657) * Update Item's metadata when the bitstream is updated. * Update Item's metadata about files after deleting the bitstream. * Update Item's metadata before the bundle is deleted or touched * Check if the bundle is not null before using it. * prevent empty argument errors (#655) Some xsl crosswalks call functions that expect parameters, but for various reasons, parameters are empty. That is now checked and logged. * Edit Item's license (#654) * Added authorization for the `Edit Item - License` menu option. * Created endpoint for updating license of the Item. * Added functionality only for detaching the license. * Changed DOI identifier to `dc.identifier.doi` (#661) * Complex input field issues (#651) * The complex input field value could be empty - removed condition that requires complex input data to not be empty. * Fixed issue when the `jsonValEvaluator` is null because of empty operation value. * Updated doc. * Mark inputs for funding as required. Added an exception when the openaire_id is not required. * Updated `submission-forms` complex input field to be not required for Integration tests. * Refactored and updated validation for complex input field * Fixed the importing of the Item - if the Item has pre-registered PID it should be unbound (#659) * local-typex differencies (#660) * Added dataProvider Facet * Replaced deprecated `sortOrder` with the new one. * `searchFacetDataProvider` should be in the searchFilters * Updated Integration test which checks the search filters * Ufal/add olac description (#662) Add olac description with lindat values * add elg format (#658) add elg format with appropriate functions * The Item should not be exposed by the OAI * Fix not exposing the Item by the OAI (#667) * dso has never been asigned * Use Factory for the Collection and Community service . * Use Handle Service instead of HandleResolver which calls HandleService * add extra appender for warns (#668) * Update Item's date metadata - do not remove dc.date.issued (#669) * Created method which updates properly the Item's date metadata. * Fixed checkstyle issues * The servlet request could be null. * Update the comment to make description more clear. * Fix encoding problems in refbox endpoint (#670) Use correct middle part in special Output Stream. * solr log modification (#671) solr log modification with explanation * Cherry picked and resolved conflicts. The submission-forms.xml and item-submission.xml are ignored. (#672) Co-authored-by: Ondřej Košarko --------- Signed-off-by: dependabot[bot] Co-authored-by: MajoBerger <88670521+MajoBerger@users.noreply.github.com> Co-authored-by: MajoBerger Co-authored-by: Adán Román Ruiz Co-authored-by: Ondřej Košarko Co-authored-by: Tim Donohue Co-authored-by: Luca Giamminonni Co-authored-by: Sean Kalynuk Co-authored-by: Sascha Szott Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Agustina Martinez Co-authored-by: Alan Orth Co-authored-by: Martin Walk Co-authored-by: corrado lombardi Co-authored-by: David P. Steelman Co-authored-by: Christian Bethge <54576195+ChrisBethgster@users.noreply.github.com> Co-authored-by: max.nuding Co-authored-by: Max Nuding Co-authored-by: Mark H. Wood Co-authored-by: Nona Luypaert Co-authored-by: Christian Clauss Co-authored-by: Hrafn Malmquist Co-authored-by: Christian Bethge Co-authored-by: Koen Pauwels Co-authored-by: Mark Cooper Co-authored-by: nwoodward Co-authored-by: Kim Shepherd Co-authored-by: Marie-Hélène Vézina Co-authored-by: damian Co-authored-by: Gantner, Florian Klaus Co-authored-by: wwuck Co-authored-by: Paulo Graça Co-authored-by: Toni Prieto Co-authored-by: mohamed eskander Co-authored-by: Jens Vannerum Co-authored-by: Andrea Bollini Co-authored-by: DSpace Bot <68393067+dspace-bot@users.noreply.github.com> Co-authored-by: Michael Spalti Co-authored-by: Alexandre Vryghem Co-authored-by: Shankeerthan Kasilingam Co-authored-by: jm Co-authored-by: Jozef Misutka <332350+vidiecan@users.noreply.github.com> --- .../app/itemimport/ItemImportServiceImpl.java | 5 + .../clarin/ClarinShibAuthentication.java | 22 +- .../dspace/content/BitstreamServiceImpl.java | 6 +- .../org/dspace/content/BundleServiceImpl.java | 7 +- .../main/java/org/dspace/content/Item.java | 3 +- .../content/clarin/ClarinItemServiceImpl.java | 144 + .../service/clarin/ClarinItemService.java | 43 + .../org/dspace/discovery/SolrServiceImpl.java | 28 + .../identifier/DOIIdentifierProvider.java | 2 +- .../test/data/dspaceFolder/config/local.cfg | 6 + .../dspaceFolder/config/submission-forms.xml | 14 +- .../dspace/app/util/GoogleMetadataTest.java | 1 - .../VersioningWithRelationshipsTest.java | 4203 ----------------- .../main/java/org/dspace/utils/LangUtil.java | 104 + .../java/org/dspace/utils/LicenseUtil.java | 4 +- .../main/java/org/dspace/xoai/app/XOAI.java | 8 +- .../org/dspace/xoai/filter/ColComFilter.java | 21 +- .../resources/DSpaceResourceResolver.java | 4 +- .../resources/functions/LogMissingFn.java | 25 +- .../functions/NodeListXslFunction.java | 19 +- .../resources/functions/NodeXslFunction.java | 13 +- .../resources/functions/ShortestIdFn.java | 26 + .../functions/StringXSLFunction.java | 16 +- .../app/rest/ClarinRefBoxController.java | 12 +- .../ClarinUserMetadataImportController.java | 4 +- .../app/rest/ItemAddBundleController.java | 76 + .../authorization/impl/CanManageLicense.java | 53 + .../DiscoverConfigurationConverter.java | 13 + .../app/rest/converter/ItemConverter.java | 30 +- .../ClarinItemImportController.java | 13 +- .../ClarinUserMetadataRestController.java | 175 +- .../repository/IdentifierRestRepository.java | 4 + .../MetadataBitstreamRestRepository.java | 46 +- .../WorkspaceItemRestRepository.java | 7 +- .../app/rest/submit/step/DescribeStep.java | 10 +- .../validation/CMDIFileBundleMaintainer.java | 2 +- .../step/validation/MetadataValidation.java | 92 +- .../config/spring/api/test-discovery.xml | 174 + .../rest/ClarinDiscoveryRestControllerIT.java | 125 +- .../rest/ClarinItemImportControllerIT.java | 15 +- .../app/rest/DiscoveryVersioningIT.java | 31 +- .../dspace/app/rest/ItemRestRepositoryIT.java | 94 +- .../app/rest/StatisticsRestRepositoryIT.java | 22 +- .../DiscoverConfigurationConverterTest.java | 4 + .../app/rest/matcher/SearchFilterMatcher.java | 20 + .../CMDIFileBundleMaintainerTest.java | 2 +- dspace/config/clarin-dspace.cfg | 29 +- .../crosswalks/oai/description-olac.xml | 16 + .../crosswalks/oai/metadataFormats/elg.xsl | 912 ++++ .../oai/metadataFormats/metasharev2.xsl | 16 +- dspace/config/crosswalks/oai/xoai.xml | 167 +- dspace/config/dspace.cfg | 8 +- dspace/config/emails/clarin_autoregistration | 2 +- dspace/config/emails/clarin_download_link | 2 +- dspace/config/item-submission.xml | 6 +- dspace/config/log4j2.xml | 37 + dspace/config/modules/identifiers.cfg | 4 +- dspace/config/modules/oai.cfg | 15 +- dspace/config/modules/rest.cfg | 4 +- dspace/config/modules/signposting.cfg | 2 +- dspace/config/registries/local-types.xml | 14 + dspace/config/spiders/ufal.ignore.txt | 51 + dspace/config/spring/api/core-services.xml | 3 +- dspace/config/spring/api/discovery.xml | 68 +- dspace/config/submission-forms_cs.xml | 2130 +++++++++ dspace/src/main/docker/dspace-solr/Dockerfile | 2 + scripts/envs/__basic.example.bat | 1 + scripts/fast-build/config-update.bat | 2 + scripts/fast-build/update-solr-configsets.bat | 5 + scripts/log4j2.solr.xml | 86 + 70 files changed, 4833 insertions(+), 4497 deletions(-) delete mode 100644 dspace-api/src/test/java/org/dspace/content/VersioningWithRelationshipsTest.java create mode 100644 dspace-oai/src/main/java/org/dspace/utils/LangUtil.java create mode 100644 dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/ShortestIdFn.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/CanManageLicense.java create mode 100644 dspace/config/crosswalks/oai/description-olac.xml create mode 100644 dspace/config/crosswalks/oai/metadataFormats/elg.xsl create mode 100644 dspace/config/spiders/ufal.ignore.txt create mode 100644 dspace/config/submission-forms_cs.xml create mode 100644 scripts/fast-build/update-solr-configsets.bat create mode 100644 scripts/log4j2.solr.xml diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 162e2b80a905..5eaeb326ffc4 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -100,6 +100,7 @@ import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.content.service.WorkspaceItemService; +import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.content.service.clarin.ClarinLicenseResourceMappingService; import org.dspace.content.service.clarin.ClarinLicenseService; import org.dspace.core.Constants; @@ -188,6 +189,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea protected ClarinLicenseService clarinLicenseService; @Autowired(required = true) protected ClarinLicenseResourceMappingService clarinLicenseResourceMappingService; + @Autowired(required = true) + protected ClarinItemService clarinItemService; protected String tempWorkDir; @@ -723,6 +726,8 @@ public void replaceItems(Context c, List mycollections, itemService.clearMetadata(c, newItem, "dc", "rights", "label", Item.ANY); itemService.addMetadata(c, newItem, "dc", "rights", "label", Item.ANY, license.getNonExtendedClarinLicenseLabel().getLabel()); + clarinItemService.updateItemFilesMetadata(c, newItem); + itemService.update(c, newItem); c.uncacheEntity(newItem); } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/clarin/ClarinShibAuthentication.java b/dspace-api/src/main/java/org/dspace/authenticate/clarin/ClarinShibAuthentication.java index 28fd67a71599..822543d08c80 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/clarin/ClarinShibAuthentication.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/clarin/ClarinShibAuthentication.java @@ -18,6 +18,7 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; +import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -578,7 +579,7 @@ protected EPerson findEPerson(Context context, HttpServletRequest request) throw // 2) Second, look for an email header. if (eperson == null && emailHeader != null) { - String email = findSingleAttribute(request, emailHeader); + String email = getEmailAcceptedOrNull(findSingleAttribute(request, emailHeader)); if (StringUtils.isEmpty(email) && Objects.nonNull(clarinVerificationToken)) { email = clarinVerificationToken.getEmail(); } @@ -694,7 +695,7 @@ protected EPerson registerNewEPerson(Context context, HttpServletRequest request // Header values String netid = Util.formatNetId(findSingleAttribute(request, netidHeader), org); - String email = findSingleAttribute(request, emailHeader); + String email = getEmailAcceptedOrNull(findSingleAttribute(request, emailHeader)); String fname = Headers.updateValueByCharset(findSingleAttribute(request, fnameHeader)); String lname = Headers.updateValueByCharset(findSingleAttribute(request, lnameHeader)); @@ -816,7 +817,7 @@ protected void updateEPerson(Context context, HttpServletRequest request, EPerso String lnameHeader = configurationService.getProperty("authentication-shibboleth.lastname-header"); String netid = Util.formatNetId(findSingleAttribute(request, netidHeader), shibheaders.get_idp()); - String email = findSingleAttribute(request, emailHeader); + String email = getEmailAcceptedOrNull(findSingleAttribute(request, emailHeader)); String fname = Headers.updateValueByCharset(findSingleAttribute(request, fnameHeader)); String lname = Headers.updateValueByCharset(findSingleAttribute(request, lnameHeader)); @@ -1171,7 +1172,12 @@ protected String findAttribute(HttpServletRequest request, String name) { if (!StringUtils.isEmpty(value) && reconvertAttributes) { try { - value = new String(value.getBytes("ISO-8859-1"), "UTF-8"); + String inputEncoding = configurationService.getProperty("shibboleth.name.conversion.inputEncoding", + "ISO-8859-1"); + String outputEncoding = configurationService.getProperty("shibboleth.name.conversion.outputEncoding", + "UTF-8"); + + value = new String(value.getBytes(inputEncoding), outputEncoding); } catch (UnsupportedEncodingException ex) { log.warn("Failed to reconvert shibboleth attribute (" + name + ").", ex); @@ -1324,5 +1330,13 @@ public boolean canChangePassword(Context context, EPerson ePerson, String curren public boolean areSpecialGroupsApplicable(Context context, HttpServletRequest request) { return true; } + + public String getEmailAcceptedOrNull(String email) { + // no whitespaces in mail + if (StringUtils.isEmpty(email) || Pattern.compile("\\s").matcher(email).find()) { + return null; + } + return email; + } } 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 5597d25f20bc..695d2840db8e 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java @@ -26,6 +26,7 @@ import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; import org.dspace.content.service.ItemService; +import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.content.service.clarin.ClarinLicenseResourceMappingService; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -66,6 +67,8 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp protected BitstreamStorageService bitstreamStorageService; @Autowired(required = true) protected ClarinLicenseResourceMappingService clarinLicenseResourceMappingService; + @Autowired(required = true) + protected ClarinItemService clarinItemService; protected BitstreamServiceImpl() { super(); @@ -275,6 +278,8 @@ public void delete(Context context, Bitstream bitstream) throws SQLException, Au // Remove bitstream itself bitstream.setDeleted(true); update(context, bitstream); + // Update Item's metadata about bitstreams + clarinItemService.updateItemFilesMetadata(context, bitstream); //Remove our bitstream from all our bundles final List bundles = bitstream.getBundles(); @@ -286,7 +291,6 @@ public void delete(Context context, Bitstream bitstream) throws SQLException, Au } bundle.removeBitstream(bitstream); } - //Remove all bundles from the bitstream object, clearing the connection in 2 ways bundles.clear(); diff --git a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java index 328dff747a94..23833efbe8fb 100644 --- a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java @@ -32,6 +32,7 @@ import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; import org.dspace.content.service.ItemService; +import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.content.service.clarin.ClarinLicenseResourceMappingService; import org.dspace.content.service.clarin.ClarinLicenseService; import org.dspace.core.Constants; @@ -70,6 +71,8 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement protected ClarinLicenseService clarinLicenseService; @Autowired(required = true) protected ClarinLicenseResourceMappingService clarinLicenseResourceMappingService; + @Autowired(required = true) + protected ClarinItemService clarinItemService; protected BundleServiceImpl() { super(); @@ -215,6 +218,7 @@ public void addBitstream(Context context, Bundle bundle, Bitstream bitstream) } bitstreamService.update(context, bitstream); + clarinItemService.updateItemFilesMetadata(context, owningItem, bundle); // Add clarin license to the bitstream and clarin license values to the item metadata clarinLicenseService.addClarinLicenseToBitstream(context, owningItem, bundle, bitstream); } @@ -238,6 +242,7 @@ public void removeBitstream(Context context, Bundle bundle, Bitstream bitstream) if (owningItem != null) { itemService.updateLastModified(context, owningItem); itemService.update(context, owningItem); + clarinItemService.updateItemFilesMetadata(context, owningItem, bundle); } // In the event that the bitstream to remove is actually @@ -453,7 +458,7 @@ public void setOrder(Context context, Bundle bundle, UUID[] bitstreamIds) throws if (owningItem != null) { itemService.updateLastModified(context, owningItem); itemService.update(context, owningItem); - + clarinItemService.updateItemFilesMetadata(context, owningItem, bundle); } } } diff --git a/dspace-api/src/main/java/org/dspace/content/Item.java b/dspace-api/src/main/java/org/dspace/content/Item.java index d36ed81e414d..034a2b6d213c 100644 --- a/dspace-api/src/main/java/org/dspace/content/Item.java +++ b/dspace-api/src/main/java/org/dspace/content/Item.java @@ -174,8 +174,7 @@ public boolean isDiscoverable() { public boolean isHidden() { String valueOfHidden = getItemService().getMetadataFirstValue(this, "local", "hidden", null, Item.ANY); - if (Objects.nonNull(valueOfHidden) && valueOfHidden.equalsIgnoreCase("hidden")) { - + if (Objects.nonNull(valueOfHidden) && valueOfHidden.equalsIgnoreCase("hidden")) { return true; } return false; diff --git a/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java index 08d5106491c4..50b1ff84dcc8 100644 --- a/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/clarin/ClarinItemServiceImpl.java @@ -8,19 +8,26 @@ package org.dspace.content.clarin; import java.sql.SQLException; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.UUID; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.apache.logging.log4j.Logger; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.MetadataField; +import org.dspace.content.MetadataValue; import org.dspace.content.dao.clarin.ClarinItemDAO; import org.dspace.content.service.CollectionService; +import org.dspace.content.service.ItemService; import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -35,12 +42,18 @@ public class ClarinItemServiceImpl implements ClarinItemService { private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ClarinItemServiceImpl.class); + private static final String DELIMETER = ","; + private static final String NO_YEAR = "0000"; + @Autowired ClarinItemDAO clarinItemDAO; @Autowired CollectionService collectionService; + @Autowired + ItemService itemService; + @Override public List findByBitstreamUUID(Context context, UUID bitstreamUUID) throws SQLException { return clarinItemDAO.findByBitstreamUUID(context, bitstreamUUID); @@ -125,4 +138,135 @@ public Community getOwningCommunity(Context context, UUID owningCollectionId) th } return null; } + + @Override + public void updateItemFilesMetadata(Context context, Item item) throws SQLException { + List originalBundles = itemService.getBundles(item, Constants.CONTENT_BUNDLE_NAME); + if (Objects.nonNull(originalBundles.get(0))) { + updateItemFilesMetadata(context, item, originalBundles.get(0)); + } else { + log.error("Cannot update item files metadata because the ORIGINAL bundle is null."); + } + } + + @Override + public void updateItemFilesMetadata(Context context, Item item, Bundle bundle) throws SQLException { + if (!Objects.equals(bundle.getName(), Constants.CONTENT_BUNDLE_NAME)) { + return; + } + + int totalNumberOfFiles = 0; + long totalSizeofFiles = 0; + + /* Add local.has.files metadata */ + boolean hasFiles = false; + List origs = itemService.getBundles(item, Constants.CONTENT_BUNDLE_NAME); + for (Bundle orig : origs) { + if (CollectionUtils.isNotEmpty(orig.getBitstreams())) { + hasFiles = true; + } + for (Bitstream bit : orig.getBitstreams()) { + totalNumberOfFiles ++; + totalSizeofFiles += bit.getSizeBytes(); + } + } + + itemService.clearMetadata(context, item, "local", "has", "files", Item.ANY); + itemService.clearMetadata(context, item, "local", "files", "count", Item.ANY); + itemService.clearMetadata(context, item, "local", "files", "size", Item.ANY); + if ( hasFiles ) { + itemService.addMetadata(context, item, "local", "has", "files", Item.ANY, "yes"); + } else { + itemService.addMetadata(context, item,"local", "has", "files", Item.ANY, "no"); + } + itemService.addMetadata(context, item,"local", "files", "count", Item.ANY, "" + totalNumberOfFiles); + itemService.addMetadata(context, item,"local", "files", "size", Item.ANY, "" + totalSizeofFiles); + } + + @Override + public void updateItemFilesMetadata(Context context, Bitstream bit) throws SQLException { + // Get the Item the bitstream is associated with + Item item = null; + Bundle bundle = null; + List origs = bit.getBundles(); + for (Bundle orig : origs) { + if (!Constants.CONTENT_BUNDLE_NAME.equals(orig.getName())) { + continue; + } + + List items = orig.getItems(); + if (CollectionUtils.isEmpty(items)) { + continue; + } + + item = items.get(0); + bundle = orig; + break; + } + + // It could be null when the bundle name is e.g. `LICENSE` + if (Objects.isNull(item) || Objects.isNull(bundle)) { + return; + } + this.updateItemFilesMetadata(context, item, bundle); + } + + @Override + public void updateItemDatesMetadata(Context context, Item item) throws SQLException { + if (Objects.isNull(context)) { + log.error("Cannot update item dates metadata because the context is null."); + return; + } + + List approximatedDates = + itemService.getMetadata(item, "local", "approximateDate", "issued", Item.ANY, false); + + if (CollectionUtils.isEmpty(approximatedDates) || StringUtils.isBlank(approximatedDates.get(0).getValue())) { + log.warn("Cannot update item dates metadata because the approximate date is empty."); + return; + } + + // Get the approximate date value from the metadata + String approximateDateValue = approximatedDates.get(0).getValue(); + + // Split the approximate date value by the delimeter and get the list of years. + List listOfYearValues = Arrays.asList(approximateDateValue.split(DELIMETER)); + // Trim the list of years - remove leading and trailing whitespaces + listOfYearValues.replaceAll(String::trim); + + try { + // Clear the current `dc.date.issued` metadata + itemService.clearMetadata(context, item, "dc", "date", "issued", Item.ANY); + + // Update the `dc.date.issued` metadata with a new value: `0000` or the last year from the sequence + if (CollectionUtils.isNotEmpty(listOfYearValues) && isListOfNumbers(listOfYearValues)) { + // Take the last year from the list of years and add it to the `dc.date.issued` metadata + itemService.addMetadata(context, item, "dc", "date", "issued", Item.ANY, + getLastNumber(listOfYearValues)); + } else { + // Add the `0000` value to the `dc.date.issued` metadata + itemService.addMetadata(context, item, "dc", "date", "issued", Item.ANY, NO_YEAR); + } + } catch (SQLException e) { + log.error("Cannot remove `dc.date.issued` metadata because: {}", e.getMessage()); + } + } + + public static boolean isListOfNumbers(List values) { + for (String value : values) { + if (!NumberUtils.isCreatable(value)) { + return false; + } + } + return true; + } + + private static String getLastNumber(List values) { + if (CollectionUtils.isEmpty(values)) { + return NO_YEAR; + } + return values.get(values.size() - 1); + } + + } diff --git a/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java b/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java index 1ea0643bc965..0559b10e1378 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinItemService.java @@ -11,6 +11,8 @@ import java.util.List; import java.util.UUID; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; @@ -59,4 +61,45 @@ public interface ClarinItemService { * @throws SQLException */ Community getOwningCommunity(Context context, UUID owningCollectionId) throws SQLException; + + /** + * Update item's metadata about its files (local.has.files, local.files.size, local.files.count). + * This method doesn't require Item's Bundle to be passed as a parameter. The ORIGINAL bundle is used by default. + * @param context DSpace context object + * @param item Update metadata for this Item + * @throws SQLException + */ + void updateItemFilesMetadata(Context context, Item item) throws SQLException; + + /** + * Update item's metadata about its files (local.has.files, local.files.size, local.files.count). + * @param context DSpace context object + * @param item Update metadata for this Item + * @param bundle Bundle to be used for the metadata update - it if is not the ORIGINAL bundle + * the method will be skipped. + * @throws SQLException + */ + void updateItemFilesMetadata(Context context, Item item, Bundle bundle) throws SQLException; + + /** + * Update item's metadata about its files (local.has.files, local.files.size, local.files.count). + * The Item and Bundle information is taken from the Bitstream object. + * @param context + * @param bit + * @throws SQLException + */ + void updateItemFilesMetadata(Context context, Bitstream bit) throws SQLException; + + /** + * Update item's metadata about its dates (dc.date.issued, local.approximateDate.issued). + * If the local.approximateDate.issued has any approximate value, e.g. 'cca 1938 - 1945' or 'approx. 1995' + * or similar, use 0000 + * If the local.approximateDate.issued has several values, e.g. 1993, 1918, 2021 use the last one: + * `dc.date.issued` = 2021 + * + * @param context DSpace context object + * @param item Update metadata for this Item + */ + void updateItemDatesMetadata(Context context, Item item) throws SQLException; + } 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 813787bff105..4930b9cee165 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java @@ -109,6 +109,13 @@ public class SolrServiceImpl implements SearchService, IndexingService { // facet by indexing "each word to end of value' partial value public static final String SOLR_FIELD_SUFFIX_FACET_PREFIXES = "_prefix"; + // Suffix of the solr field used to index the facet/filter so that the facet search can search all word in a + // facet. + private static final String SOLR_FACET_FIELD_ALL_VALUES_SUFFIX = "_filter"; + + // List of all facets which will return facet value with splitter. + private ArrayList allValuesFacetList = new ArrayList<>(); + @Autowired protected ContentServiceFactory contentServiceFactory; @Autowired @@ -1400,12 +1407,22 @@ protected String transformFacetField(DiscoverFacetField facetFieldConfig, String } } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) { if (removePostfix) { + // If the current field is configured to show all values instead of only the top level values + if (this.getFacetsToShowAllValues().contains( + StringUtils.substringBeforeLast(field, SOLR_FACET_FIELD_ALL_VALUES_SUFFIX))) { + return StringUtils.substringBeforeLast(field, SOLR_FACET_FIELD_ALL_VALUES_SUFFIX); + } return StringUtils.substringBeforeLast(field, "_tax_"); } else { + // If the current field is configured to show all values instead of only the top level values + if (this.getFacetsToShowAllValues().contains(field)) { + return field + SOLR_FACET_FIELD_ALL_VALUES_SUFFIX; + } //Only display top level filters ! return field + "_tax_0_filter"; } } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_AUTHORITY)) { + if (removePostfix) { return field.substring(0, field.lastIndexOf("_acid")); } else { @@ -1603,4 +1620,15 @@ public String calculateExtremeValue(Context context, String valueField, return null; } + /** + * Return or load the configuration property `discovery.solr.facets.allvalues` as a list. + */ + private ArrayList getFacetsToShowAllValues() { + if (CollectionUtils.isEmpty(allValuesFacetList)) { + String[] allValuesFacetArray = configurationService.getArrayProperty("discovery.solr.facets.allvalues"); + Collections.addAll(allValuesFacetList, allValuesFacetArray); + } + return allValuesFacetList; + } + } diff --git a/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java index b70eda960d35..e1a4d3e46b9a 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java @@ -73,7 +73,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider { // TODO: move these to MetadataSchema or some such? public static final String MD_SCHEMA = "dc"; public static final String DOI_ELEMENT = "identifier"; - public static final String DOI_QUALIFIER = "uri"; + public static final String DOI_QUALIFIER = "doi"; // The DOI is queued for registered with the service provider public static final Integer TO_BE_REGISTERED = 1; // The DOI is queued for reservation with the service provider diff --git a/dspace-api/src/test/data/dspaceFolder/config/local.cfg b/dspace-api/src/test/data/dspaceFolder/config/local.cfg index a842905c53ab..cc9ccb26bbb2 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/local.cfg +++ b/dspace-api/src/test/data/dspaceFolder/config/local.cfg @@ -301,3 +301,9 @@ file.preview.enabled = true ### Storage service ### sync.storage.service.enabled = false + +### Signposting configuration ### +signposting.enabled = true + +# Test configuration has only EN locale (submission-forms.xml) +webui.supported.locales = en \ No newline at end of file diff --git a/dspace-api/src/test/data/dspaceFolder/config/submission-forms.xml b/dspace-api/src/test/data/dspaceFolder/config/submission-forms.xml index cbd30695283a..81eecc680164 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/submission-forms.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/submission-forms.xml @@ -686,17 +686,17 @@ it, please enter the types and the actual numbers or codes. Uncomment the example row of the complex input type definition to see this input in the submission UI. --> - - - + + + - - - - + + + + diff --git a/dspace-api/src/test/java/org/dspace/app/util/GoogleMetadataTest.java b/dspace-api/src/test/java/org/dspace/app/util/GoogleMetadataTest.java index ee6723480e35..1bd8b19d18f5 100644 --- a/dspace-api/src/test/java/org/dspace/app/util/GoogleMetadataTest.java +++ b/dspace-api/src/test/java/org/dspace/app/util/GoogleMetadataTest.java @@ -94,7 +94,6 @@ public void init() { Item item = wi.getItem(); ContentServiceFactory.getInstance().getInstallItemService().installItem(context, wi, null); context.restoreAuthSystemState(); - context.commit(); it = item; bundleService = ContentServiceFactory.getInstance().getBundleService(); bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); diff --git a/dspace-api/src/test/java/org/dspace/content/VersioningWithRelationshipsTest.java b/dspace-api/src/test/java/org/dspace/content/VersioningWithRelationshipsTest.java deleted file mode 100644 index 88bde022f78a..000000000000 --- a/dspace-api/src/test/java/org/dspace/content/VersioningWithRelationshipsTest.java +++ /dev/null @@ -1,4203 +0,0 @@ -/** - * 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.content; - -import static org.dspace.content.Relationship.LatestVersionStatus.BOTH; -import static org.dspace.content.Relationship.LatestVersionStatus.LEFT_ONLY; -import static org.dspace.content.Relationship.LatestVersionStatus.RIGHT_ONLY; -import static org.dspace.util.RelationshipVersioningTestUtils.isRel; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.startsWith; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.function.FailableRunnable; -import org.apache.commons.lang3.function.FailableSupplier; -import org.apache.solr.client.solrj.SolrQuery; -import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.common.SolrDocument; -import org.apache.solr.common.SolrDocumentList; -import org.dspace.AbstractIntegrationTestWithDatabase; -import org.dspace.authorize.AuthorizeException; -import org.dspace.builder.CollectionBuilder; -import org.dspace.builder.CommunityBuilder; -import org.dspace.builder.EntityTypeBuilder; -import org.dspace.builder.ItemBuilder; -import org.dspace.builder.RelationshipBuilder; -import org.dspace.builder.RelationshipTypeBuilder; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.InstallItemService; -import org.dspace.content.service.ItemService; -import org.dspace.content.service.RelationshipService; -import org.dspace.content.service.WorkspaceItemService; -import org.dspace.content.virtual.Collected; -import org.dspace.content.virtual.VirtualMetadataConfiguration; -import org.dspace.content.virtual.VirtualMetadataPopulator; -import org.dspace.core.Constants; -import org.dspace.discovery.SolrSearchCore; -import org.dspace.kernel.ServiceManager; -import org.dspace.services.factory.DSpaceServicesFactory; -import org.dspace.versioning.Version; -import org.dspace.versioning.factory.VersionServiceFactory; -import org.dspace.versioning.service.VersioningService; -import org.hamcrest.Matcher; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.springframework.beans.factory.config.AutowireCapableBeanFactory; - -public class VersioningWithRelationshipsTest extends AbstractIntegrationTestWithDatabase { - - private final RelationshipService relationshipService = - ContentServiceFactory.getInstance().getRelationshipService(); - private final VersioningService versioningService = - VersionServiceFactory.getInstance().getVersionService(); - private final WorkspaceItemService workspaceItemService = - ContentServiceFactory.getInstance().getWorkspaceItemService(); - private final InstallItemService installItemService = - ContentServiceFactory.getInstance().getInstallItemService(); - private final ItemService itemService = - ContentServiceFactory.getInstance().getItemService(); - private final SolrSearchCore solrSearchCore = - DSpaceServicesFactory.getInstance().getServiceManager().getServicesByType(SolrSearchCore.class).get(0); - - protected Community community; - protected Collection collection; - protected EntityType publicationEntityType; - protected EntityType personEntityType; - protected EntityType projectEntityType; - protected EntityType orgUnitEntityType; - protected EntityType journalIssueEntityType; - protected EntityType journalVolumeEntityType; - protected RelationshipType isAuthorOfPublication; - protected RelationshipType isProjectOfPublication; - protected RelationshipType isOrgUnitOfPublication; - protected RelationshipType isMemberOfProject; - protected RelationshipType isMemberOfOrgUnit; - protected RelationshipType isIssueOfJournalVolume; - protected RelationshipType isProjectOfPerson; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - context.turnOffAuthorisationSystem(); - - community = CommunityBuilder.createCommunity(context) - .withName("community") - .build(); - - collection = CollectionBuilder.createCollection(context, community) - .withName("collection") - .build(); - - publicationEntityType = EntityTypeBuilder.createEntityTypeBuilder(context, "Publication") - .build(); - - personEntityType = EntityTypeBuilder.createEntityTypeBuilder(context, "Person") - .build(); - - projectEntityType = EntityTypeBuilder.createEntityTypeBuilder(context, "Project") - .build(); - - orgUnitEntityType = EntityTypeBuilder.createEntityTypeBuilder(context, "OrgUnit") - .build(); - - journalIssueEntityType = EntityTypeBuilder.createEntityTypeBuilder(context, "JournalIssue") - .build(); - - journalVolumeEntityType = EntityTypeBuilder.createEntityTypeBuilder(context, "JournalVolume") - .build(); - - isAuthorOfPublication = RelationshipTypeBuilder.createRelationshipTypeBuilder( - context, publicationEntityType, personEntityType, - "isAuthorOfPublication", "isPublicationOfAuthor", - null, null, null, null - ) - .withCopyToLeft(false) - .withCopyToRight(false) - .build(); - - isProjectOfPublication = RelationshipTypeBuilder.createRelationshipTypeBuilder( - context, publicationEntityType, projectEntityType, - "isProjectOfPublication", "isPublicationOfProject", - null, null, null, null - ) - .withCopyToLeft(false) - .withCopyToRight(false) - .build(); - - isOrgUnitOfPublication = RelationshipTypeBuilder.createRelationshipTypeBuilder( - context, publicationEntityType, orgUnitEntityType, - "isOrgUnitOfPublication", "isPublicationOfOrgUnit", - null, null, null, null - ) - .withCopyToLeft(false) - .withCopyToRight(false) - .build(); - - isMemberOfProject = RelationshipTypeBuilder.createRelationshipTypeBuilder( - context, projectEntityType, personEntityType, - "isMemberOfProject", "isProjectOfMember", - null, null, null, null - ) - .withCopyToLeft(false) - .withCopyToRight(false) - .build(); - - isMemberOfOrgUnit = RelationshipTypeBuilder.createRelationshipTypeBuilder( - context, orgUnitEntityType, personEntityType, - "isMemberOfOrgUnit", "isOrgUnitOfMember", - null, null, null, null - ) - .withCopyToLeft(false) - .withCopyToRight(false) - .build(); - - isIssueOfJournalVolume = RelationshipTypeBuilder.createRelationshipTypeBuilder( - context, journalVolumeEntityType, journalIssueEntityType, - "isIssueOfJournalVolume", "isJournalVolumeOfIssue", - null, null, 1, 1 - ) - .withCopyToLeft(false) - .withCopyToRight(false) - .build(); - - isProjectOfPerson = RelationshipTypeBuilder.createRelationshipTypeBuilder( - context, personEntityType, projectEntityType, - "isProjectOfPerson", "isPersonOfProject", - null, null, null, null - ) - .withCopyToLeft(false) - .withCopyToRight(false) - .build(); - } - - protected Relationship getRelationship( - Item leftItem, RelationshipType relationshipType, Item rightItem - ) throws Exception { - List rels = relationshipService.findByRelationshipType(context, relationshipType).stream() - .filter(rel -> leftItem.getID().equals(rel.getLeftItem().getID())) - .filter(rel -> rightItem.getID().equals(rel.getRightItem().getID())) - .collect(Collectors.toList()); - - if (rels.size() == 0) { - return null; - } - - if (rels.size() == 1) { - return rels.get(0); - } - - // NOTE: this shouldn't be possible because of database constraints - throw new IllegalStateException(); - } - - @Test - public void test_createNewVersionOfItemOnLeftSideOfRelationships() throws Exception { - /////////////////////////////////////////////// - // create a publication with 3 relationships // - /////////////////////////////////////////////// - - Item person1 = ItemBuilder.createItem(context, collection) - .withTitle("person 1") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .build(); - - Item project1 = ItemBuilder.createItem(context, collection) - .withTitle("project 1") - .withMetadata("dspace", "entity", "type", projectEntityType.getLabel()) - .build(); - - Item orgUnit1 = ItemBuilder.createItem(context, collection) - .withTitle("org unit 1") - .withMetadata("dspace", "entity", "type", orgUnitEntityType.getLabel()) - .build(); - - Item originalPublication = ItemBuilder.createItem(context, collection) - .withTitle("original publication") - .withMetadata("dspace", "entity", "type", publicationEntityType.getLabel()) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, person1, isAuthorOfPublication) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, project1, isProjectOfPublication) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, orgUnit1, isOrgUnitOfPublication) - .build(); - - ///////////////////////////////////////////////////////// - // verify that the relationships were properly created // - ///////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - ///////////////////////////////////////////// - // create a new version of the publication // - ///////////////////////////////////////////// - - Version newVersion = versioningService.createNewVersion(context, originalPublication); - Item newPublication = newVersion.getItem(); - assertNotSame(originalPublication, newPublication); - - /////////////////////////////////////////////////////////////////////// - // verify the relationships of all 5 items (excludeNonLatest = true) // - /////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - isRel(newPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0) - )) - ); - - //////////////////////////////////////////////////////////////////////// - // verify the relationships of all 5 items (excludeNonLatest = false) // - //////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(newPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(newPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - isRel(newPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0) - )) - ); - - //////////////////////////////////////// - // do item install on new publication // - //////////////////////////////////////// - - WorkspaceItem newPublicationWSI = workspaceItemService.findByItem(context, newPublication); - installItemService.installItem(context, newPublicationWSI); - context.dispatchEvents(); - - /////////////////////////////////////////////////////////////////////// - // verify the relationships of all 5 items (excludeNonLatest = true) // - /////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isProjectOfPublication, project1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(newPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - //////////////////////////////////////////////////////////////////////// - // verify the relationships of all 5 items (excludeNonLatest = false) // - //////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - isRel(newPublication, isAuthorOfPublication, person1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0), - isRel(newPublication, isProjectOfPublication, project1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(newPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - ////////////// - // clean up // - ////////////// - - // need to manually delete all relationships to avoid SQL constraint violation exception - List relationships = relationshipService.findAll(context); - for (Relationship relationship : relationships) { - relationshipService.delete(context, relationship); - } - } - - @Test - public void test_createNewVersionOfItemAndModifyRelationships() throws Exception { - /////////////////////////////////////////////// - // create a publication with 3 relationships // - /////////////////////////////////////////////// - - Item person1 = ItemBuilder.createItem(context, collection) - .withTitle("person 1") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .build(); - - Item project1 = ItemBuilder.createItem(context, collection) - .withTitle("project 1") - .withMetadata("dspace", "entity", "type", projectEntityType.getLabel()) - .build(); - - Item orgUnit1 = ItemBuilder.createItem(context, collection) - .withTitle("org unit 1") - .withMetadata("dspace", "entity", "type", orgUnitEntityType.getLabel()) - .build(); - - Item originalPublication = ItemBuilder.createItem(context, collection) - .withTitle("original publication") - .withMetadata("dspace", "entity", "type", publicationEntityType.getLabel()) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, person1, isAuthorOfPublication) - .build(); - - RelationshipBuilder - .createRelationshipBuilder(context, originalPublication, project1, isProjectOfPublication) - .build(); - - RelationshipBuilder - .createRelationshipBuilder(context, originalPublication, orgUnit1, isOrgUnitOfPublication) - .build(); - - ///////////////////////////////////////////////////////// - // verify that the relationships were properly created // - ///////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - ///////////////////////////////////////////// - // create a new version of the publication // - ///////////////////////////////////////////// - - Version newVersion = versioningService.createNewVersion(context, originalPublication); - Item newPublication = newVersion.getItem(); - assertNotSame(originalPublication, newPublication); - - ///////////////////////////////////////////// - // modify relationships on new publication // - ///////////////////////////////////////////// - - Item person2 = ItemBuilder.createItem(context, collection) - .withTitle("person 2") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .build(); - - Item orgUnit2 = ItemBuilder.createItem(context, collection) - .withTitle("org unit 2") - .withMetadata("dspace", "entity", "type", orgUnitEntityType.getLabel()) - .build(); - - // on new item, remove relationship with project 1 - List newProjectRels = relationshipService - .findByItemAndRelationshipType(context, newPublication, isProjectOfPublication); - assertEquals(1, newProjectRels.size()); - relationshipService.delete(context, newProjectRels.get(0)); - - // on new item remove relationship with org unit 1 - List newOrgUnitRels = relationshipService - .findByItemAndRelationshipType(context, newPublication, isOrgUnitOfPublication); - assertEquals(1, newOrgUnitRels.size()); - relationshipService.delete(context, newOrgUnitRels.get(0)); - - RelationshipBuilder.createRelationshipBuilder(context, newPublication, person2, isAuthorOfPublication) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, newPublication, orgUnit2, isOrgUnitOfPublication) - .build(); - - /////////////////////////////////////////////////////////////////////// - // verify the relationships of all 7 items (excludeNonLatest = true) // - /////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person2, -1, -1, false, true), - containsInAnyOrder(List.of( - // NOTE: BOTH because new relationship - isRel(newPublication, isAuthorOfPublication, person2, BOTH, 1, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit2, -1, -1, false, true), - containsInAnyOrder(List.of( - // NOTE: BOTH because new relationship - isRel(newPublication, isOrgUnitOfPublication, orgUnit2, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - // NOTE: BOTH because new relationship - isRel(newPublication, isAuthorOfPublication, person2, BOTH, 1, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit2, BOTH, 0, 0) - )) - ); - - //////////////////////////////////////////////////////////////////////// - // verify the relationships of all 7 items (excludeNonLatest = false) // - //////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(newPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person2, -1, -1, false, false), - containsInAnyOrder(List.of( - // NOTE: BOTH because new relationship - isRel(newPublication, isAuthorOfPublication, person2, BOTH, 1, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isProjectOfPublication, project1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit2, -1, -1, false, false), - containsInAnyOrder(List.of( - // NOTE: BOTH because new relationship - isRel(newPublication, isOrgUnitOfPublication, orgUnit2, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - // NOTE: BOTH because new relationship - isRel(newPublication, isAuthorOfPublication, person2, BOTH, 1, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit2, BOTH, 0, 0) - )) - ); - - //////////////////////////////////////// - // do item install on new publication // - //////////////////////////////////////// - - WorkspaceItem newPublicationWSI = workspaceItemService.findByItem(context, newPublication); - installItemService.installItem(context, newPublicationWSI); - context.dispatchEvents(); - - /////////////////////////////////////////////////////////////////////// - // verify the relationships of all 7 items (excludeNonLatest = true) // - /////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person2, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person2, BOTH, 1, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, true), - empty() - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, true), - empty() - ); - - assertThat( - relationshipService.findByItem(context, orgUnit2, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isOrgUnitOfPublication, orgUnit2, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(newPublication, isAuthorOfPublication, person2, BOTH, 1, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit2, BOTH, 0, 0) - )) - ); - - //////////////////////////////////////////////////////////////////////// - // verify the relationships of all 7 items (excludeNonLatest = false) // - //////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - isRel(originalPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0), - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isAuthorOfPublication, person1, RIGHT_ONLY, 0, 0), - isRel(newPublication, isAuthorOfPublication, person1, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, person2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person2, BOTH, 1, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isProjectOfPublication, project1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(originalPublication, isOrgUnitOfPublication, orgUnit1, RIGHT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(newPublication, isOrgUnitOfPublication, orgUnit2, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(newPublication, isAuthorOfPublication, person1, BOTH, 0, 0), - isRel(newPublication, isAuthorOfPublication, person2, BOTH, 1, 0), - isRel(newPublication, isOrgUnitOfPublication, orgUnit2, BOTH, 0, 0) - )) - ); - - ////////////// - // clean up // - ////////////// - - // need to manually delete all relationships to avoid SQL constraint violation exception - List relationships = relationshipService.findAll(context); - for (Relationship relationship : relationships) { - relationshipService.delete(context, relationship); - } - } - - @Test - public void test_createNewVersionOfItemOnRightSideOfRelationships() throws Exception { - ////////////////////////////////////////// - // create a person with 3 relationships // - ////////////////////////////////////////// - - Item publication1 = ItemBuilder.createItem(context, collection) - .withTitle("publication 1") - .withMetadata("dspace", "entity", "type", publicationEntityType.getLabel()) - .build(); - - Item project1 = ItemBuilder.createItem(context, collection) - .withTitle("project 1") - .withMetadata("dspace", "entity", "type", projectEntityType.getLabel()) - .build(); - - Item orgUnit1 = ItemBuilder.createItem(context, collection) - .withTitle("org unit 1") - .withMetadata("dspace", "entity", "type", orgUnitEntityType.getLabel()) - .build(); - - Item originalPerson = ItemBuilder.createItem(context, collection) - .withTitle("original person") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, publication1, originalPerson, isAuthorOfPublication) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, project1, originalPerson, isMemberOfProject) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, orgUnit1, originalPerson, isMemberOfOrgUnit) - .build(); - - ///////////////////////////////////////////////////////// - // verify that the relationships were properly created // - ///////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPerson, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, BOTH, 0, 0), - isRel(project1, isMemberOfProject, originalPerson, BOTH, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, publication1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(project1, isMemberOfProject, originalPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, BOTH, 0, 0) - )) - ); - - //////////////////////////////////////// - // create a new version of the person // - //////////////////////////////////////// - - Version newVersion = versioningService.createNewVersion(context, originalPerson); - Item newPerson = newVersion.getItem(); - assertNotSame(originalPerson, newPerson); - - /////////////////////////////////////////////////////////////////////// - // verify the relationships of all 5 items (excludeNonLatest = true) // - /////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPerson, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, BOTH, 0, 0), - isRel(project1, isMemberOfProject, originalPerson, BOTH, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, publication1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(project1, isMemberOfProject, originalPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPerson, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, newPerson, LEFT_ONLY, 0, 0), - isRel(project1, isMemberOfProject, newPerson, LEFT_ONLY, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, newPerson, LEFT_ONLY, 0, 0) - )) - ); - - //////////////////////////////////////////////////////////////////////// - // verify the relationships of all 5 items (excludeNonLatest = false) // - //////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPerson, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, BOTH, 0, 0), - isRel(project1, isMemberOfProject, originalPerson, BOTH, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, publication1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, BOTH, 0, 0), - isRel(publication1, isAuthorOfPublication, newPerson, LEFT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(project1, isMemberOfProject, originalPerson, BOTH, 0, 0), - isRel(project1, isMemberOfProject, newPerson, LEFT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, BOTH, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, newPerson, LEFT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPerson, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, newPerson, LEFT_ONLY, 0, 0), - isRel(project1, isMemberOfProject, newPerson, LEFT_ONLY, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, newPerson, LEFT_ONLY, 0, 0) - )) - ); - - /////////////////////////////////// - // do item install on new person // - /////////////////////////////////// - - WorkspaceItem newPersonWSI = workspaceItemService.findByItem(context, newPerson); - installItemService.installItem(context, newPersonWSI); - context.dispatchEvents(); - - /////////////////////////////////////////////////////////////////////// - // verify the relationships of all 5 items (excludeNonLatest = true) // - /////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPerson, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, LEFT_ONLY, 0, 0), - isRel(project1, isMemberOfProject, originalPerson, LEFT_ONLY, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, LEFT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, publication1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, newPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(project1, isMemberOfProject, newPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(orgUnit1, isMemberOfOrgUnit, newPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPerson, -1, -1, false, true), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, newPerson, BOTH, 0, 0), - isRel(project1, isMemberOfProject, newPerson, BOTH, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, newPerson, BOTH, 0, 0) - )) - ); - - //////////////////////////////////////////////////////////////////////// - // verify the relationships of all 5 items (excludeNonLatest = false) // - //////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPerson, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, LEFT_ONLY, 0, 0), - isRel(project1, isMemberOfProject, originalPerson, LEFT_ONLY, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, LEFT_ONLY, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, publication1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, originalPerson, LEFT_ONLY, 0, 0), - isRel(publication1, isAuthorOfPublication, newPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, project1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(project1, isMemberOfProject, originalPerson, LEFT_ONLY, 0, 0), - isRel(project1, isMemberOfProject, newPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, orgUnit1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(orgUnit1, isMemberOfOrgUnit, originalPerson, LEFT_ONLY, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, newPerson, BOTH, 0, 0) - )) - ); - - assertThat( - relationshipService.findByItem(context, newPerson, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1, isAuthorOfPublication, newPerson, BOTH, 0, 0), - isRel(project1, isMemberOfProject, newPerson, BOTH, 0, 0), - isRel(orgUnit1, isMemberOfOrgUnit, newPerson, BOTH, 0, 0) - )) - ); - - ////////////// - // clean up // - ////////////// - - // need to manually delete all relationships to avoid SQL constraint violation exception - List relationships = relationshipService.findAll(context); - for (Relationship relationship : relationships) { - relationshipService.delete(context, relationship); - } - } - - @Test - public void test_createNewVersionOfItemAndVerifyMetadataOrder() throws Exception { - ///////////////////////////////////////// - // create a publication with 6 authors // - ///////////////////////////////////////// - - Item originalPublication = ItemBuilder.createItem(context, collection) - .withTitle("original publication") - .withMetadata("dspace", "entity", "type", publicationEntityType.getLabel()) - .build(); - - // author 1 (plain metadata) - itemService.addMetadata(context, originalPublication, "dc", "contributor", "author", null, "author 1 (plain)"); - - // author 2 (virtual) - Item author2 = ItemBuilder.createItem(context, collection) - .withTitle("author 2 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .withPersonIdentifierFirstName("2 (item)") - .withPersonIdentifierLastName("author") - .build(); - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, author2, isAuthorOfPublication) - .build(); - - // author 3 (virtual) - Item author3 = ItemBuilder.createItem(context, collection) - .withTitle("author 3 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .withPersonIdentifierFirstName("3 (item)") - .withPersonIdentifierLastName("author") - .build(); - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, author3, isAuthorOfPublication) - .build(); - - // author 4 (virtual) - Item author4 = ItemBuilder.createItem(context, collection) - .withTitle("author 4 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .withPersonIdentifierFirstName("4 (item)") - .withPersonIdentifierLastName("author") - .build(); - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, author4, isAuthorOfPublication) - .build(); - - // author 5 (virtual) - Item author5 = ItemBuilder.createItem(context, collection) - .withTitle("author 5 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .withPersonIdentifierFirstName("5 (item)") - .withPersonIdentifierLastName("author") - .build(); - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, author5, isAuthorOfPublication) - .build(); - - // author 6 (plain metadata) - itemService.addMetadata(context, originalPublication, "dc", "contributor", "author", null, "author 6 (plain)"); - - // author 7 (virtual) - Item author7 = ItemBuilder.createItem(context, collection) - .withTitle("author 7 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .withPersonIdentifierFirstName("7 (item)") - .withPersonIdentifierLastName("author") - .build(); - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, author7, isAuthorOfPublication) - .build(); - - // author 8 (plain metadata) - itemService.addMetadata(context, originalPublication, "dc", "contributor", "author", null, "author 8 (plain)"); - - // author 9 (virtual) - Item author9 = ItemBuilder.createItem(context, collection) - .withTitle("author 9 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .withPersonIdentifierFirstName("9 (item)") - .withPersonIdentifierLastName("author") - .build(); - RelationshipBuilder.createRelationshipBuilder(context, originalPublication, author9, isAuthorOfPublication) - .build(); - - //////////////////////////////// - // test dc.contributor.author // - //////////////////////////////// - - List oldMdvs = itemService.getMetadata( - originalPublication, "dc", "contributor", "author", Item.ANY - ); - assertEquals(9, oldMdvs.size()); - - assertFalse(oldMdvs.get(0) instanceof RelationshipMetadataValue); - assertEquals("author 1 (plain)", oldMdvs.get(0).getValue()); - assertEquals(0, oldMdvs.get(0).getPlace()); - - assertTrue(oldMdvs.get(1) instanceof RelationshipMetadataValue); - assertEquals("author, 2 (item)", oldMdvs.get(1).getValue()); - assertEquals(1, oldMdvs.get(1).getPlace()); - - assertTrue(oldMdvs.get(2) instanceof RelationshipMetadataValue); - assertEquals("author, 3 (item)", oldMdvs.get(2).getValue()); - assertEquals(2, oldMdvs.get(2).getPlace()); - - assertTrue(oldMdvs.get(3) instanceof RelationshipMetadataValue); - assertEquals("author, 4 (item)", oldMdvs.get(3).getValue()); - assertEquals(3, oldMdvs.get(3).getPlace()); - - assertTrue(oldMdvs.get(4) instanceof RelationshipMetadataValue); - assertEquals("author, 5 (item)", oldMdvs.get(4).getValue()); - assertEquals(4, oldMdvs.get(4).getPlace()); - - assertFalse(oldMdvs.get(5) instanceof RelationshipMetadataValue); - assertEquals("author 6 (plain)", oldMdvs.get(5).getValue()); - assertEquals(5, oldMdvs.get(5).getPlace()); - - assertTrue(oldMdvs.get(6) instanceof RelationshipMetadataValue); - assertEquals("author, 7 (item)", oldMdvs.get(6).getValue()); - assertEquals(6, oldMdvs.get(6).getPlace()); - - assertFalse(oldMdvs.get(7) instanceof RelationshipMetadataValue); - assertEquals("author 8 (plain)", oldMdvs.get(7).getValue()); - assertEquals(7, oldMdvs.get(7).getPlace()); - - assertTrue(oldMdvs.get(8) instanceof RelationshipMetadataValue); - assertEquals("author, 9 (item)", oldMdvs.get(8).getValue()); - assertEquals(8, oldMdvs.get(8).getPlace()); - - ///////////////////////////////////////////// - // test relationship isAuthorOfPublication // - ///////////////////////////////////////////// - - List oldRelationships = relationshipService.findByItem(context, originalPublication); - assertEquals(6, oldRelationships.size()); - - assertEquals(originalPublication, oldRelationships.get(0).getLeftItem()); - assertEquals(isAuthorOfPublication, oldRelationships.get(0).getRelationshipType()); - assertEquals(author2, oldRelationships.get(0).getRightItem()); - assertEquals(1, oldRelationships.get(0).getLeftPlace()); - assertEquals(0, oldRelationships.get(0).getRightPlace()); - - assertEquals(originalPublication, oldRelationships.get(1).getLeftItem()); - assertEquals(isAuthorOfPublication, oldRelationships.get(1).getRelationshipType()); - assertEquals(author3, oldRelationships.get(1).getRightItem()); - assertEquals(2, oldRelationships.get(1).getLeftPlace()); - assertEquals(0, oldRelationships.get(1).getRightPlace()); - - assertEquals(originalPublication, oldRelationships.get(2).getLeftItem()); - assertEquals(isAuthorOfPublication, oldRelationships.get(2).getRelationshipType()); - assertEquals(author4, oldRelationships.get(2).getRightItem()); - assertEquals(3, oldRelationships.get(2).getLeftPlace()); - assertEquals(0, oldRelationships.get(2).getRightPlace()); - - assertEquals(originalPublication, oldRelationships.get(3).getLeftItem()); - assertEquals(isAuthorOfPublication, oldRelationships.get(3).getRelationshipType()); - assertEquals(author5, oldRelationships.get(3).getRightItem()); - assertEquals(4, oldRelationships.get(3).getLeftPlace()); - assertEquals(0, oldRelationships.get(3).getRightPlace()); - - assertEquals(originalPublication, oldRelationships.get(4).getLeftItem()); - assertEquals(isAuthorOfPublication, oldRelationships.get(4).getRelationshipType()); - assertEquals(author7, oldRelationships.get(4).getRightItem()); - assertEquals(6, oldRelationships.get(4).getLeftPlace()); - assertEquals(0, oldRelationships.get(4).getRightPlace()); - - assertEquals(originalPublication, oldRelationships.get(5).getLeftItem()); - assertEquals(isAuthorOfPublication, oldRelationships.get(5).getRelationshipType()); - assertEquals(author9, oldRelationships.get(5).getRightItem()); - assertEquals(8, oldRelationships.get(5).getLeftPlace()); - assertEquals(0, oldRelationships.get(5).getRightPlace()); - - /////////////////////////////////////// - // create new version of publication // - /////////////////////////////////////// - - Version newVersion = versioningService.createNewVersion(context, originalPublication); - Item newPublication = newVersion.getItem(); - assertNotSame(originalPublication, newPublication); - - //////////////////////////////// - // test dc.contributor.author // - //////////////////////////////// - - List newMdvs = itemService.getMetadata( - newPublication, "dc", "contributor", "author", Item.ANY - ); - assertEquals(9, newMdvs.size()); - - assertFalse(newMdvs.get(0) instanceof RelationshipMetadataValue); - assertEquals("author 1 (plain)", newMdvs.get(0).getValue()); - assertEquals(0, newMdvs.get(0).getPlace()); - - assertTrue(newMdvs.get(1) instanceof RelationshipMetadataValue); - assertEquals("author, 2 (item)", newMdvs.get(1).getValue()); - assertEquals(1, newMdvs.get(1).getPlace()); - - assertTrue(newMdvs.get(2) instanceof RelationshipMetadataValue); - assertEquals("author, 3 (item)", newMdvs.get(2).getValue()); - assertEquals(2, newMdvs.get(2).getPlace()); - - assertTrue(newMdvs.get(3) instanceof RelationshipMetadataValue); - assertEquals("author, 4 (item)", newMdvs.get(3).getValue()); - assertEquals(3, newMdvs.get(3).getPlace()); - - assertTrue(newMdvs.get(4) instanceof RelationshipMetadataValue); - assertEquals("author, 5 (item)", newMdvs.get(4).getValue()); - assertEquals(4, newMdvs.get(4).getPlace()); - - assertFalse(newMdvs.get(5) instanceof RelationshipMetadataValue); - assertEquals("author 6 (plain)", newMdvs.get(5).getValue()); - assertEquals(5, newMdvs.get(5).getPlace()); - - assertTrue(newMdvs.get(6) instanceof RelationshipMetadataValue); - assertEquals("author, 7 (item)", newMdvs.get(6).getValue()); - assertEquals(6, newMdvs.get(6).getPlace()); - - assertFalse(newMdvs.get(7) instanceof RelationshipMetadataValue); - assertEquals("author 8 (plain)", newMdvs.get(7).getValue()); - assertEquals(7, newMdvs.get(7).getPlace()); - - assertTrue(newMdvs.get(8) instanceof RelationshipMetadataValue); - assertEquals("author, 9 (item)", newMdvs.get(8).getValue()); - assertEquals(8, newMdvs.get(8).getPlace()); - - ///////////////////////////////////////////// - // test relationship isAuthorOfPublication // - ///////////////////////////////////////////// - - List newRelationships = relationshipService.findByItem(context, newPublication); - assertEquals(6, newRelationships.size()); - - assertEquals(newPublication, newRelationships.get(0).getLeftItem()); - assertEquals(isAuthorOfPublication, newRelationships.get(0).getRelationshipType()); - assertEquals(author2, newRelationships.get(0).getRightItem()); - assertEquals(1, newRelationships.get(0).getLeftPlace()); - assertEquals(0, newRelationships.get(0).getRightPlace()); - - assertEquals(newPublication, newRelationships.get(1).getLeftItem()); - assertEquals(isAuthorOfPublication, newRelationships.get(1).getRelationshipType()); - assertEquals(author3, newRelationships.get(1).getRightItem()); - assertEquals(2, newRelationships.get(1).getLeftPlace()); - assertEquals(0, newRelationships.get(1).getRightPlace()); - - assertEquals(newPublication, newRelationships.get(2).getLeftItem()); - assertEquals(isAuthorOfPublication, newRelationships.get(2).getRelationshipType()); - assertEquals(author4, newRelationships.get(2).getRightItem()); - assertEquals(3, newRelationships.get(2).getLeftPlace()); - assertEquals(0, newRelationships.get(2).getRightPlace()); - - assertEquals(newPublication, newRelationships.get(3).getLeftItem()); - assertEquals(isAuthorOfPublication, newRelationships.get(3).getRelationshipType()); - assertEquals(author5, newRelationships.get(3).getRightItem()); - assertEquals(4, newRelationships.get(3).getLeftPlace()); - assertEquals(0, newRelationships.get(3).getRightPlace()); - - assertEquals(newPublication, newRelationships.get(4).getLeftItem()); - assertEquals(isAuthorOfPublication, newRelationships.get(4).getRelationshipType()); - assertEquals(author7, newRelationships.get(4).getRightItem()); - assertEquals(6, newRelationships.get(4).getLeftPlace()); - assertEquals(0, newRelationships.get(4).getRightPlace()); - - assertEquals(newPublication, newRelationships.get(5).getLeftItem()); - assertEquals(isAuthorOfPublication, newRelationships.get(5).getRelationshipType()); - assertEquals(author9, newRelationships.get(5).getRightItem()); - assertEquals(8, newRelationships.get(5).getLeftPlace()); - assertEquals(0, newRelationships.get(5).getRightPlace()); - - ////////////// - // clean up // - ////////////// - - // need to manually delete all relationships to avoid SQL constraint violation exception - List relationships = relationshipService.findAll(context); - for (Relationship relationship : relationships) { - relationshipService.delete(context, relationship); - } - } - - /** - * This test will - * - create a publication with 10 projects - * - Remove, move, add projects - * - Verify the order remains correct - * @throws Exception - */ - @Test - public void test_createNewVersionOfItemWithAddRemoveMove() throws Exception { - /////////////////////////////////////////// - // create a publication with 10 projects // - /////////////////////////////////////////// - - Item originalPublication = ItemBuilder.createItem(context, collection) - .withTitle("original publication") - .withMetadata("dspace", "entity", "type", publicationEntityType.getLabel()) - .build(); - - List projects = new ArrayList<>(); - - for (int i = 0; i < 10; i++) { - Item project = ItemBuilder.createItem(context, collection) - .withTitle("project " + i) - .withMetadata("dspace", "entity", "type", projectEntityType.getLabel()) - .build(); - projects.add(project); - - RelationshipBuilder - .createRelationshipBuilder(context, originalPublication, project, isProjectOfPublication) - .build(); - } - - AtomicInteger counterOriginalPublication = new AtomicInteger(); - List> listOriginalPublication = projects.stream().map( - project -> isRel(originalPublication, isProjectOfPublication, project, BOTH, - counterOriginalPublication.getAndIncrement(), 0) - ).collect(Collectors.toCollection(ArrayList::new)); - - ///////////////////////////////////////////////////////////////////// - // verify the relationships of all items (excludeNonLatest = true) // - ///////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, true), - containsInAnyOrder(listOriginalPublication) - ); - - ////////////////////////////////////////////////////////////////////// - // verify the relationships of all items (excludeNonLatest = false) // - ////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, false), - containsInAnyOrder(listOriginalPublication) - ); - - ///////////////////////////////////////////// - // create a new version of the publication // - ///////////////////////////////////////////// - - Version newVersion = versioningService.createNewVersion(context, originalPublication); - Item newPublication = newVersion.getItem(); - assertNotSame(originalPublication, newPublication); - - verifyProjectsMatch(originalPublication, projects, newPublication, projects, false);// - - ///////////////////////////////////////////// - // modify relationships on new publication // - ///////////////////////////////////////////// - - List newProjects = new ArrayList<>(projects); - assertEquals(newProjects.size(), 10); - - removeProject(newPublication, 5, newProjects); - - assertEquals(projects.size(), 10); - assertEquals(newProjects.size(), 9); - verifyProjectsMatch(originalPublication, projects, newPublication, newProjects, false); - - Item project6 = newProjects.get(6); - moveProject(newPublication, 6, 2, newProjects); - assertEquals(newProjects.size(), 9); - assertEquals(newProjects.get(2), project6); - assertNotEquals(projects.get(2), project6); - verifyProjectsMatch(originalPublication, projects, newPublication, newProjects, false); - - Item project1 = newProjects.get(1); - moveProject(newPublication, 1, 5, newProjects); - assertEquals(newProjects.size(), 9); - assertEquals(newProjects.get(5), project1); - assertNotEquals(projects.get(5), project1); - verifyProjectsMatch(originalPublication, projects, newPublication, newProjects, false); - - Item project = ItemBuilder.createItem(context, collection) - .withTitle("project 10") - .withMetadata("dspace", "entity", "type", projectEntityType.getLabel()) - .build(); - newProjects.add(4, project); - - RelationshipBuilder - .createRelationshipBuilder(context, newPublication, project, isProjectOfPublication, 4, -1) - .build(); - - verifyProjectsMatch(originalPublication, projects, newPublication, newProjects, false); - - //////////////////////////////////////// - // do item install on new publication // - //////////////////////////////////////// - - WorkspaceItem newPublicationWSI = workspaceItemService.findByItem(context, newPublication); - installItemService.installItem(context, newPublicationWSI); - context.dispatchEvents(); - - verifyProjectsMatch(originalPublication, projects, newPublication, newProjects, true); - - ////////////// - // clean up // - ////////////// - - // need to manually delete all relationships to avoid SQL constraint violation exception - List relationships = relationshipService.findAll(context); - for (Relationship relationship : relationships) { - relationshipService.delete(context, relationship); - } - } - - protected void removeProject(Item newPublication, int place, List newProjects) - throws SQLException, AuthorizeException { - List projectRels = relationshipService - .findByItemAndRelationshipType(context, newProjects.get(place), isProjectOfPublication, -1, -1, false) - .stream() - .filter( - relationship -> relationship.getLeftItem().equals(newPublication) - ) - .collect(Collectors.toCollection(ArrayList::new)); - assertEquals(1, projectRels.size()); - relationshipService.delete(context, projectRels.get(0)); - newProjects.remove(newProjects.get(place)); - } - - protected void moveProject(Item newPublication, int oldPlace, int newPlace, List newProjects) - throws SQLException, AuthorizeException { - Item project = newProjects.get(oldPlace); - List projectRels = relationshipService - .findByItemAndRelationshipType(context, project, isProjectOfPublication, -1, -1, false) - .stream() - .filter( - relationship -> relationship.getLeftItem().equals(newPublication) - ) - .collect(Collectors.toCollection(ArrayList::new)); - assertEquals(1, projectRels.size()); - relationshipService.move(context, projectRels.get(0), newPlace, null); - newProjects.remove(project); - newProjects.add(newPlace, project); - } - - protected void verifyProjectsMatch(Item originalPublication, List originalProjects, - Item newPublication, List newProjects, boolean newPublicationArchived) - throws SQLException { - - ///////////////////////////////////////////////////////// - // verify that the relationships were properly created // - ///////////////////////////////////////////////////////// - - AtomicInteger counterOriginalPublication = new AtomicInteger(); - List> listOriginalPublication = originalProjects.stream().map( - project -> isRel(originalPublication, isProjectOfPublication, project, - newPublicationArchived ? RIGHT_ONLY : BOTH, - counterOriginalPublication.getAndIncrement(), 0) - ).collect(Collectors.toCollection(ArrayList::new)); - - AtomicInteger counterNewPublication = new AtomicInteger(); - List> listNewPublication = newProjects.stream().map( - project -> isRel(newPublication, isProjectOfPublication, project, - newPublicationArchived || !originalProjects.contains(project) ? - BOTH : RIGHT_ONLY, - counterNewPublication.getAndIncrement(), 0) - ).collect(Collectors.toCollection(ArrayList::new)); - - ///////////////////////////////////////////////////////////////////// - // verify the relationships of all items (excludeNonLatest = true) // - ///////////////////////////////////////////////////////////////////// - - assertEquals( - relationshipService.countByItem(context, originalPublication, false, true), - originalProjects.size() - ); - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, true), - containsInAnyOrder(listOriginalPublication) - ); - - assertEquals( - relationshipService.countByItem(context, newPublication, false, true), - newProjects.size() - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, true), - containsInAnyOrder(listNewPublication) - ); - - ////////////////////////////////////////////////////////////////////// - // verify the relationships of all items (excludeNonLatest = false) // - ////////////////////////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, originalPublication, -1, -1, false, false), - containsInAnyOrder(listOriginalPublication) - ); - - assertThat( - relationshipService.findByItem(context, newPublication, -1, -1, false, false), - containsInAnyOrder(listNewPublication) - ); - } - - /** - * NOTE: If Spring bean classes would be created with the new keyword, nothing would be autowired. - */ - protected T createBean(Class beanClass) throws Exception { - AutowireCapableBeanFactory factory = DSpaceServicesFactory.getInstance().getServiceManager() - .getApplicationContext().getAutowireCapableBeanFactory(); - - T bean = beanClass.getDeclaredConstructor().newInstance(); - - factory.autowireBean(bean); - - return bean; - } - - /** - * Run the given callback with a virtual metadata config that's different from virtual-metadata.xml, - * and clean up after the callback has terminated. - * @param configModifier lambda that generates the temporary virtual metadata config. - * @param callback the callback that will be executed with the temporary virtual metadata config. - */ - protected void runWithVirtualMetadataConfig( - FailableSupplier>, Exception> configModifier, - FailableRunnable callback - ) throws Exception { - VirtualMetadataPopulator virtualMetadataPopulator = DSpaceServicesFactory.getInstance() - .getServiceManager().getServicesByType(VirtualMetadataPopulator.class).get(0); - - // keep reference to old config - Map> oldConfig = virtualMetadataPopulator.getMap(); - - try { - // set new config - Map> newConfig = configModifier.get(); - virtualMetadataPopulator.setMap(newConfig); - - // run the callback - callback.run(); - } finally { - // reset handlers - virtualMetadataPopulator.setMap(oldConfig); - } - } - - @Test - public void test_placeRecalculationAfterDelete() throws Exception { - // NOTE: this test uses relationship isIssueOfJournalVolume, because it adds virtual metadata - // on both sides of the relationship - - ///////////////////////////////////////// - // properly configure virtual metadata // - ///////////////////////////////////////// - - ServiceManager serviceManager = DSpaceServicesFactory.getInstance().getServiceManager(); - - // virtual metadata field publicationissue.issueNumber needs to be used in place calculations - Collected issueVmd = serviceManager.getServiceByName("journalIssue_number", Collected.class); - assertNotNull(issueVmd); - boolean ogIssueVmdUseForPlace = issueVmd.getUseForPlace(); - issueVmd.setUseForPlace(true); - - ////////////////// - // create items // - ////////////////// - - // journal volume 1.1 - Item v1_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal volume 1") - .withMetadata("dspace", "entity", "type", journalVolumeEntityType.getLabel()) - .withMetadata("publicationvolume", "volumeNumber", null, "volume nr 3 (rel)") - .build(); - - // journal issue 1.1 - Item i1_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 1") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 1 (rel)") - .build(); - - // journal issue 3.1 - Item i3_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 3") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 3 (rel)") - .build(); - - // journal issue 5.1 - Item i5_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 5") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 5 (rel)") - .build(); - - ////////////////////////////////////////////// - // create relationships and metadata values // - ////////////////////////////////////////////// - - // relationship - volume 1 & issue 1 - RelationshipBuilder.createRelationshipBuilder(context, v1_1, i1_1, isIssueOfJournalVolume).build(); - - // metadata - volume 1 & issue 2 - itemService.addMetadata(context, v1_1, "publicationissue", "issueNumber", null, null, "issue nr 2 (plain)"); - - // relationship - volume 1 & issue 3 - RelationshipBuilder.createRelationshipBuilder(context, v1_1, i3_1, isIssueOfJournalVolume).build(); - - // metadata - volume 1 & issue 4 - itemService.addMetadata(context, v1_1, "publicationissue", "issueNumber", null, null, "issue nr 4 (plain)"); - - // relationship - volume 1 & issue 5 - RelationshipBuilder.createRelationshipBuilder(context, v1_1, i5_1, isIssueOfJournalVolume).build(); - - // metadata - volume 1 & issue 6 - itemService.addMetadata(context, v1_1, "publicationissue", "issueNumber", null, null, "issue nr 6 (plain)"); - - // SUMMARY - // - // volume 3 - // - pos 0: issue 1 (rel) - // - pos 1: issue 2 (plain) - // - pos 2: issue 3 (rel) - // - pos 3: issue 4 (plain) - // - pos 4: issue 5 (rel) - // - pos 5: issue 6 (plain) - - ///////////////////////////////// - // initial - verify volume 3.1 // - ///////////////////////////////// - - List mdvs1 = itemService.getMetadata( - v1_1, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(6, mdvs1.size()); - - assertTrue(mdvs1.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs1.get(0).getValue()); - assertEquals(0, mdvs1.get(0).getPlace()); - - assertFalse(mdvs1.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (plain)", mdvs1.get(1).getValue()); - assertEquals(1, mdvs1.get(1).getPlace()); - - assertTrue(mdvs1.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs1.get(2).getValue()); - assertEquals(2, mdvs1.get(2).getPlace()); - - assertFalse(mdvs1.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (plain)", mdvs1.get(3).getValue()); - assertEquals(3, mdvs1.get(3).getPlace()); - - assertTrue(mdvs1.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs1.get(4).getValue()); - assertEquals(4, mdvs1.get(4).getPlace()); - - assertFalse(mdvs1.get(5) instanceof RelationshipMetadataValue); - assertEquals("issue nr 6 (plain)", mdvs1.get(5).getValue()); - assertEquals(5, mdvs1.get(5).getPlace()); - - ///////////////////////////////////// - // create new version - volume 1.2 // - ///////////////////////////////////// - - Item v1_2 = versioningService.createNewVersion(context, v1_1).getItem(); - installItemService.installItem(context, workspaceItemService.findByItem(context, v1_2)); - context.commit(); - - //////////////////////////////////// - // create new version - issue 3.2 // - //////////////////////////////////// - - Item i3_2 = versioningService.createNewVersion(context, i3_1).getItem(); - installItemService.installItem(context, workspaceItemService.findByItem(context, i3_2)); - context.commit(); - - //////////////////////////////////////////////// - // after version creation - verify volume 1.1 // - //////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_1, isIssueOfJournalVolume, i1_1, RIGHT_ONLY, 0, 0), - isRel(v1_1, isIssueOfJournalVolume, i3_1, RIGHT_ONLY, 2, 0), - isRel(v1_1, isIssueOfJournalVolume, i5_1, RIGHT_ONLY, 4, 0) - )) - ); - - List mdvs4 = itemService.getMetadata( - v1_1, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(6, mdvs4.size()); - - assertTrue(mdvs4.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs4.get(0).getValue()); - assertEquals(0, mdvs4.get(0).getPlace()); - - assertFalse(mdvs4.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (plain)", mdvs4.get(1).getValue()); - assertEquals(1, mdvs4.get(1).getPlace()); - - assertTrue(mdvs4.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs4.get(2).getValue()); - assertEquals(2, mdvs4.get(2).getPlace()); - - assertFalse(mdvs4.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (plain)", mdvs4.get(3).getValue()); - assertEquals(3, mdvs4.get(3).getPlace()); - - assertTrue(mdvs4.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs4.get(4).getValue()); - assertEquals(4, mdvs4.get(4).getPlace()); - - assertFalse(mdvs4.get(5) instanceof RelationshipMetadataValue); - assertEquals("issue nr 6 (plain)", mdvs4.get(5).getValue()); - assertEquals(5, mdvs4.get(5).getPlace()); - - //////////////////////////////////////////////// - // after version creation - verify volume 1.2 // - //////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_2, isIssueOfJournalVolume, i1_1, BOTH, 0, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_1, LEFT_ONLY, 2, 0), - isRel(v1_2, isIssueOfJournalVolume, i5_1, BOTH, 4, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_2, BOTH, 2, 0) - )) - ); - - List mdvs7 = itemService.getMetadata( - v1_2, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(6, mdvs7.size()); - - assertTrue(mdvs7.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs7.get(0).getValue()); - assertEquals(0, mdvs7.get(0).getPlace()); - - assertFalse(mdvs7.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (plain)", mdvs7.get(1).getValue()); - assertEquals(1, mdvs7.get(1).getPlace()); - - assertTrue(mdvs7.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs7.get(2).getValue()); - assertEquals(2, mdvs7.get(2).getPlace()); - - assertFalse(mdvs7.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (plain)", mdvs7.get(3).getValue()); - assertEquals(3, mdvs7.get(3).getPlace()); - - assertTrue(mdvs7.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs7.get(4).getValue()); - assertEquals(4, mdvs7.get(4).getPlace()); - - assertFalse(mdvs7.get(5) instanceof RelationshipMetadataValue); - assertEquals("issue nr 6 (plain)", mdvs7.get(5).getValue()); - assertEquals(5, mdvs7.get(5).getPlace()); - - /////////////////////////////////////////////////////////// - // remove relationship - volume 1.2 & issue 3.2 // - // since an issue needs a relationship, delete the issue // - /////////////////////////////////////////////////////////// - - Relationship rel1 = getRelationship(v1_2, isIssueOfJournalVolume, i3_2); - assertNotNull(rel1); - - itemService.delete(context, context.reloadEntity(i3_2)); - - context.commit(); - - //////////////////////////////////// - // after remove 1 - cache busting // - //////////////////////////////////// - - v1_2.setMetadataModified(); - v1_2 = context.reloadEntity(v1_2); - - //////////////////////////////////////// - // after remove 1 - verify volume 3.1 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_1, isIssueOfJournalVolume, i1_1, RIGHT_ONLY, 0, 0), - isRel(v1_1, isIssueOfJournalVolume, i3_1, RIGHT_ONLY, 2, 0), - isRel(v1_1, isIssueOfJournalVolume, i5_1, RIGHT_ONLY, 4, 0) - )) - ); - - List mdvs9 = itemService.getMetadata( - v1_1, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(6, mdvs9.size()); - - assertTrue(mdvs9.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs9.get(0).getValue()); - assertEquals(0, mdvs9.get(0).getPlace()); - - assertFalse(mdvs9.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (plain)", mdvs9.get(1).getValue()); - assertEquals(1, mdvs9.get(1).getPlace()); - - assertTrue(mdvs9.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs9.get(2).getValue()); - assertEquals(2, mdvs9.get(2).getPlace()); - - assertFalse(mdvs9.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (plain)", mdvs9.get(3).getValue()); - assertEquals(3, mdvs9.get(3).getPlace()); - - assertTrue(mdvs9.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs9.get(4).getValue()); - assertEquals(4, mdvs9.get(4).getPlace()); - - assertFalse(mdvs9.get(5) instanceof RelationshipMetadataValue); - assertEquals("issue nr 6 (plain)", mdvs9.get(5).getValue()); - assertEquals(5, mdvs9.get(5).getPlace()); - - //////////////////////////////////////// - // after remove 1 - verify volume 1.2 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_2, isIssueOfJournalVolume, i1_1, BOTH, 0, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_1, LEFT_ONLY, 2, 0), - // NOTE: left place was reduced by one - isRel(v1_2, isIssueOfJournalVolume, i5_1, BOTH, 3, 0) - )) - ); - - List mdvs12 = itemService.getMetadata( - v1_2, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(5, mdvs12.size()); - - assertTrue(mdvs12.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs12.get(0).getValue()); - assertEquals(0, mdvs12.get(0).getPlace()); - - assertFalse(mdvs12.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (plain)", mdvs12.get(1).getValue()); - assertEquals(1, mdvs12.get(1).getPlace()); - - assertFalse(mdvs12.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (plain)", mdvs12.get(2).getValue()); - assertEquals(2, mdvs12.get(2).getPlace()); - - assertTrue(mdvs12.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs12.get(3).getValue()); - assertEquals(3, mdvs12.get(3).getPlace()); - - assertFalse(mdvs12.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 6 (plain)", mdvs12.get(4).getValue()); - assertEquals(4, mdvs12.get(4).getPlace()); - - //////////////////////////////////////// - // remove metadata value - volume 1.2 // - //////////////////////////////////////// - - MetadataValue removeMdv1 = mdvs12.get(2); - - // let's make sure we have the metadata value that we intended to remove - assertFalse(removeMdv1 instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (plain)", removeMdv1.getValue()); - assertEquals(2, removeMdv1.getPlace()); - assertEquals(v1_2, removeMdv1.getDSpaceObject()); - - itemService.removeMetadataValues(context, v1_2, List.of(removeMdv1)); - // NOTE: after removal, update is required to do place recalculation, among other things - itemService.update(context, v1_2); - context.commit(); - - //////////////////////////////////////// - // after remove 2 - verify volume 1.1 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_1, isIssueOfJournalVolume, i1_1, RIGHT_ONLY, 0, 0), - isRel(v1_1, isIssueOfJournalVolume, i3_1, RIGHT_ONLY, 2, 0), - isRel(v1_1, isIssueOfJournalVolume, i5_1, RIGHT_ONLY, 4, 0) - )) - ); - - List mdvs14 = itemService.getMetadata( - v1_1, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(6, mdvs14.size()); - - assertTrue(mdvs14.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs14.get(0).getValue()); - assertEquals(0, mdvs14.get(0).getPlace()); - - assertFalse(mdvs14.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (plain)", mdvs14.get(1).getValue()); - assertEquals(1, mdvs14.get(1).getPlace()); - - assertTrue(mdvs14.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs14.get(2).getValue()); - assertEquals(2, mdvs14.get(2).getPlace()); - - assertFalse(mdvs14.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (plain)", mdvs14.get(3).getValue()); - assertEquals(3, mdvs14.get(3).getPlace()); - - assertTrue(mdvs14.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs14.get(4).getValue()); - assertEquals(4, mdvs14.get(4).getPlace()); - - assertFalse(mdvs14.get(5) instanceof RelationshipMetadataValue); - assertEquals("issue nr 6 (plain)", mdvs14.get(5).getValue()); - assertEquals(5, mdvs14.get(5).getPlace()); - - //////////////////////////////////////// - // after remove 2 - verify volume 1.2 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_2, isIssueOfJournalVolume, i1_1, BOTH, 0, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_1, LEFT_ONLY, 2, 0), - // NOTE: left place was reduced by one (from 3 to 2) - isRel(v1_2, isIssueOfJournalVolume, i5_1, BOTH, 2, 0) - )) - ); - - List mdvs17 = itemService.getMetadata( - v1_2, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(4, mdvs17.size()); - - assertTrue(mdvs17.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs17.get(0).getValue()); - assertEquals(0, mdvs17.get(0).getPlace()); - - assertFalse(mdvs17.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (plain)", mdvs17.get(1).getValue()); - assertEquals(1, mdvs17.get(1).getPlace()); - - assertTrue(mdvs17.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs17.get(2).getValue()); - assertEquals(2, mdvs17.get(2).getPlace()); - - assertFalse(mdvs17.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 6 (plain)", mdvs17.get(3).getValue()); - assertEquals(3, mdvs17.get(3).getPlace()); - - ///////////////////////////////////////////// - // delete volume first for min cardinality // - ///////////////////////////////////////////// - - itemService.delete(context, context.reloadEntity(v1_1)); - itemService.delete(context, context.reloadEntity(v1_2)); - - ///////////////////////////// - // clean up config changes // - ///////////////////////////// - - issueVmd.setUseForPlace(ogIssueVmdUseForPlace); - } - - @Test - public void test_placeRecalculationAfterDelete_complex() throws Exception { - runWithVirtualMetadataConfig( - () -> { - // config summary: - // on the Project items, metadata field dc.contributor.author will appear with the Authors' titles - // on the Person items, metadata field dc.relation will appear with the Projects' titles - - Collected dcRelation = createBean(Collected.class); - dcRelation.setFields(List.of("dc.title")); - dcRelation.setUseForPlace(true); - - Collected dcContributorAuthor = createBean(Collected.class); - dcContributorAuthor.setFields(List.of("dc.title")); - dcContributorAuthor.setUseForPlace(true); - - return Map.of( - "isProjectOfPerson", new HashMap<>(Map.of( - "dc.relation", dcRelation - )), - "isPersonOfProject", new HashMap<>(Map.of( - "dc.contributor.author", dcContributorAuthor - )) - ); - }, - () -> { - ////////////////// - // create items // - ////////////////// - - // person 1.1 - Item pe1_1 = ItemBuilder.createItem(context, collection) - .withTitle("person 1 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .build(); - - // person 3.1 - Item pe3_1 = ItemBuilder.createItem(context, collection) - .withTitle("person 3 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .build(); - - // person 5.1 - Item pe5_1 = ItemBuilder.createItem(context, collection) - .withTitle("person 5 (item)") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .build(); - - // project 1.1 - Item pr1_1 = ItemBuilder.createItem(context, collection) - .withTitle("project 1 (item)") - .withMetadata("dspace", "entity", "type", projectEntityType.getLabel()) - .build(); - - // project 3.1 - Item pr3_1 = ItemBuilder.createItem(context, collection) - .withTitle("project 3 (item)") - .withMetadata("dspace", "entity", "type", projectEntityType.getLabel()) - .build(); - - // project 5.1 - Item pr5_1 = ItemBuilder.createItem(context, collection) - .withTitle("project 5 (item)") - .withMetadata("dspace", "entity", "type", projectEntityType.getLabel()) - .build(); - - ////////////////////////////////////////////// - // create relationships and metadata values // - ////////////////////////////////////////////// - - // relationship - person 3 & project 1 - RelationshipBuilder.createRelationshipBuilder(context, pe3_1, pr1_1, isProjectOfPerson) - .build(); - - // metadata - person 3 & project 2 - itemService.addMetadata(context, pe3_1, "dc", "relation", null, null, "project 2 (mdv)", "20000", 300); - - // relationship - person 1 & project 3 - RelationshipBuilder.createRelationshipBuilder(context, pe1_1, pr3_1, isProjectOfPerson) - .build(); - - // metadata - person 2 & project 3 - itemService.addMetadata(context, pr3_1, "dc", "contributor", "author", null, "person 2 (mdv)"); - - // relationship - person 3 & project 3 - RelationshipBuilder.createRelationshipBuilder(context, pe3_1, pr3_1, isProjectOfPerson) - .build(); - - // metadata - person 4 & project 3 - itemService.addMetadata(context, pr3_1, "dc", "contributor", "author", null, "person 4 (mdv)"); - - // relationship - person 5 & project 3 - RelationshipBuilder.createRelationshipBuilder(context, pe5_1, pr3_1, isProjectOfPerson) - .build(); - - // metadata - person 6 & project 3 - itemService.addMetadata(context, pr3_1, "dc", "contributor", "author", null, "person 6 (mdv)"); - - // metadata - person 7 & project 5 - itemService.addMetadata(context, pr5_1, "dc", "contributor", "author", null, "person 7 (mdv)"); - - // relationship - person 5 & project 5 - RelationshipBuilder.createRelationshipBuilder(context, pe5_1, pr5_1, isProjectOfPerson) - .build(); - - // metadata - person 3 & project 4 - itemService.addMetadata(context, pe3_1, "dc", "relation", null, null, "project 4 (mdv)", "20000", 300); - - // relationship - person 3 & project 5 - RelationshipBuilder.createRelationshipBuilder(context, pe3_1, pr5_1, isProjectOfPerson) - .build(); - - // metadata - person 3 & project 6 - itemService.addMetadata(context, pe3_1, "dc", "relation", null, null, "project 6 (mdv)", "20000", 300); - - // SUMMARY - // - // person 3 - // - pos 0: project 1 (item) - // - pos 1: project 2 (mdv) - // - pos 2: project 3 (item) [A] - // - pos 3: project 4 (mdv) - // - pos 4: project 5 (item) [B] - // - pos 5: project 6 (mdv) - // - // project 3 - // - pos 0: person 1 (item) - // - pos 1: person 2 (mdv) - // - pos 2: person 3 (item) [A] - // - pos 3: person 4 (mdv) - // - pos 4: person 5 (item) - // - pos 5: person 6 (mdv) - // - // project 5 - // - pos 0: person 7 (mdv) - // - pos 1: person 5 (item) - // - pos 2: person 3 (item) [B] - - ///////////////////////////////// - // initial - verify person 3.1 // - ///////////////////////////////// - - List mdvs1 = itemService.getMetadata( - pe3_1, "dc", "relation", null, Item.ANY - ); - assertEquals(6, mdvs1.size()); - - assertTrue(mdvs1.get(0) instanceof RelationshipMetadataValue); - assertEquals("project 1 (item)", mdvs1.get(0).getValue()); - assertEquals(0, mdvs1.get(0).getPlace()); - - assertFalse(mdvs1.get(1) instanceof RelationshipMetadataValue); - assertEquals("project 2 (mdv)", mdvs1.get(1).getValue()); - assertEquals(1, mdvs1.get(1).getPlace()); - - assertTrue(mdvs1.get(2) instanceof RelationshipMetadataValue); - assertEquals("project 3 (item)", mdvs1.get(2).getValue()); - assertEquals(2, mdvs1.get(2).getPlace()); - - assertFalse(mdvs1.get(3) instanceof RelationshipMetadataValue); - assertEquals("project 4 (mdv)", mdvs1.get(3).getValue()); - assertEquals(3, mdvs1.get(3).getPlace()); - - assertTrue(mdvs1.get(4) instanceof RelationshipMetadataValue); - assertEquals("project 5 (item)", mdvs1.get(4).getValue()); - assertEquals(4, mdvs1.get(4).getPlace()); - - assertFalse(mdvs1.get(5) instanceof RelationshipMetadataValue); - assertEquals("project 6 (mdv)", mdvs1.get(5).getValue()); - assertEquals(5, mdvs1.get(5).getPlace()); - - ////////////////////////////////// - // initial - verify project 3.1 // - ////////////////////////////////// - - List mdvs2 = itemService.getMetadata( - pr3_1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(6, mdvs2.size()); - - assertTrue(mdvs2.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 1 (item)", mdvs2.get(0).getValue()); - assertEquals(0, mdvs2.get(0).getPlace()); - - assertFalse(mdvs2.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 2 (mdv)", mdvs2.get(1).getValue()); - assertEquals(1, mdvs2.get(1).getPlace()); - - assertTrue(mdvs2.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs2.get(2).getValue()); - assertEquals(2, mdvs2.get(2).getPlace()); - - assertFalse(mdvs2.get(3) instanceof RelationshipMetadataValue); - assertEquals("person 4 (mdv)", mdvs2.get(3).getValue()); - assertEquals(3, mdvs2.get(3).getPlace()); - - assertTrue(mdvs2.get(4) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs2.get(4).getValue()); - assertEquals(4, mdvs2.get(4).getPlace()); - - assertFalse(mdvs2.get(5) instanceof RelationshipMetadataValue); - assertEquals("person 6 (mdv)", mdvs2.get(5).getValue()); - assertEquals(5, mdvs2.get(5).getPlace()); - - ////////////////////////////////// - // initial - verify project 5.1 // - ////////////////////////////////// - - List mdvs3 = itemService.getMetadata( - pr5_1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(3, mdvs3.size()); - - assertFalse(mdvs3.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 7 (mdv)", mdvs3.get(0).getValue()); - assertEquals(0, mdvs3.get(0).getPlace()); - - assertTrue(mdvs3.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs3.get(1).getValue()); - assertEquals(1, mdvs3.get(1).getPlace()); - - assertTrue(mdvs3.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs3.get(2).getValue()); - assertEquals(2, mdvs3.get(2).getPlace()); - - ///////////////////////////////////// - // create new version - person 3.2 // - ///////////////////////////////////// - - Item pe3_2 = versioningService.createNewVersion(context, pe3_1).getItem(); - installItemService.installItem(context, workspaceItemService.findByItem(context, pe3_2)); - context.commit(); - - ////////////////////////////////////// - // create new version - project 3.2 // - ////////////////////////////////////// - - Item pr3_2 = versioningService.createNewVersion(context, pr3_1).getItem(); - installItemService.installItem(context, workspaceItemService.findByItem(context, pr3_2)); - context.commit(); - - //////////////////////////////////////////////// - // after version creation - verify person 3.1 // - //////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pe3_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe3_1, isProjectOfPerson, pr1_1, RIGHT_ONLY, 0, 0), - isRel(pe3_1, isProjectOfPerson, pr3_1, RIGHT_ONLY, 2, 2), - isRel(pe3_1, isProjectOfPerson, pr5_1, RIGHT_ONLY, 4, 2) - )) - ); - - List mdvs4 = itemService.getMetadata( - pe3_1, "dc", "relation", null, Item.ANY - ); - assertEquals(6, mdvs4.size()); - - assertTrue(mdvs4.get(0) instanceof RelationshipMetadataValue); - assertEquals("project 1 (item)", mdvs4.get(0).getValue()); - assertEquals(0, mdvs4.get(0).getPlace()); - - assertFalse(mdvs4.get(1) instanceof RelationshipMetadataValue); - assertEquals("project 2 (mdv)", mdvs4.get(1).getValue()); - assertEquals(1, mdvs4.get(1).getPlace()); - - assertTrue(mdvs4.get(2) instanceof RelationshipMetadataValue); - assertEquals("project 3 (item)", mdvs4.get(2).getValue()); - assertEquals(2, mdvs4.get(2).getPlace()); - - assertFalse(mdvs4.get(3) instanceof RelationshipMetadataValue); - assertEquals("project 4 (mdv)", mdvs4.get(3).getValue()); - assertEquals(3, mdvs4.get(3).getPlace()); - - assertTrue(mdvs4.get(4) instanceof RelationshipMetadataValue); - assertEquals("project 5 (item)", mdvs4.get(4).getValue()); - assertEquals(4, mdvs4.get(4).getPlace()); - - assertFalse(mdvs4.get(5) instanceof RelationshipMetadataValue); - assertEquals("project 6 (mdv)", mdvs4.get(5).getValue()); - assertEquals(5, mdvs4.get(5).getPlace()); - - ///////////////////////////////////////////////// - // after version creation - verify project 3.1 // - ///////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr3_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe1_1, isProjectOfPerson, pr3_1, LEFT_ONLY, 0, 0), - isRel(pe3_1, isProjectOfPerson, pr3_1, RIGHT_ONLY, 2, 2), - isRel(pe5_1, isProjectOfPerson, pr3_1, LEFT_ONLY, 0, 4), - isRel(pe3_2, isProjectOfPerson, pr3_1, LEFT_ONLY, 2, 2) - )) - ); - - List mdvs5 = itemService.getMetadata( - pr3_1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(6, mdvs5.size()); - - assertTrue(mdvs5.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 1 (item)", mdvs5.get(0).getValue()); - assertEquals(0, mdvs5.get(0).getPlace()); - - assertFalse(mdvs5.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 2 (mdv)", mdvs5.get(1).getValue()); - assertEquals(1, mdvs5.get(1).getPlace()); - - assertTrue(mdvs5.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs5.get(2).getValue()); - assertEquals(2, mdvs5.get(2).getPlace()); - - assertFalse(mdvs5.get(3) instanceof RelationshipMetadataValue); - assertEquals("person 4 (mdv)", mdvs5.get(3).getValue()); - assertEquals(3, mdvs5.get(3).getPlace()); - - assertTrue(mdvs5.get(4) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs5.get(4).getValue()); - assertEquals(4, mdvs5.get(4).getPlace()); - - assertFalse(mdvs5.get(5) instanceof RelationshipMetadataValue); - assertEquals("person 6 (mdv)", mdvs5.get(5).getValue()); - assertEquals(5, mdvs5.get(5).getPlace()); - - ///////////////////////////////////////////////// - // after version creation - verify project 5.1 // - ///////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr5_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe5_1, isProjectOfPerson, pr5_1, BOTH, 1, 1), - isRel(pe3_1, isProjectOfPerson, pr5_1, RIGHT_ONLY, 4, 2), - isRel(pe3_2, isProjectOfPerson, pr5_1, BOTH, 4, 2) - )) - ); - - List mdvs6 = itemService.getMetadata( - pr5_1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(3, mdvs6.size()); - - assertFalse(mdvs6.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 7 (mdv)", mdvs6.get(0).getValue()); - assertEquals(0, mdvs6.get(0).getPlace()); - - assertTrue(mdvs6.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs6.get(1).getValue()); - assertEquals(1, mdvs6.get(1).getPlace()); - - assertTrue(mdvs6.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs6.get(2).getValue()); - assertEquals(2, mdvs6.get(2).getPlace()); - - //////////////////////////////////////////////// - // after version creation - verify volume 3.2 // - //////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pe3_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe3_2, isProjectOfPerson, pr1_1, BOTH, 0, 0), - isRel(pe3_2, isProjectOfPerson, pr3_1, LEFT_ONLY, 2, 2), - isRel(pe3_2, isProjectOfPerson, pr3_2, BOTH, 2, 2), - isRel(pe3_2, isProjectOfPerson, pr5_1, BOTH, 4, 2) - )) - ); - - List mdvs7 = itemService.getMetadata( - pe3_2, "dc", "relation", null, Item.ANY - ); - assertEquals(6, mdvs7.size()); - - assertTrue(mdvs7.get(0) instanceof RelationshipMetadataValue); - assertEquals("project 1 (item)", mdvs7.get(0).getValue()); - assertEquals(0, mdvs7.get(0).getPlace()); - - assertFalse(mdvs7.get(1) instanceof RelationshipMetadataValue); - assertEquals("project 2 (mdv)", mdvs7.get(1).getValue()); - assertEquals(1, mdvs7.get(1).getPlace()); - - assertTrue(mdvs7.get(2) instanceof RelationshipMetadataValue); - assertEquals("project 3 (item)", mdvs7.get(2).getValue()); - assertEquals(2, mdvs7.get(2).getPlace()); - - assertFalse(mdvs7.get(3) instanceof RelationshipMetadataValue); - assertEquals("project 4 (mdv)", mdvs7.get(3).getValue()); - assertEquals(3, mdvs7.get(3).getPlace()); - - assertTrue(mdvs7.get(4) instanceof RelationshipMetadataValue); - assertEquals("project 5 (item)", mdvs7.get(4).getValue()); - assertEquals(4, mdvs7.get(4).getPlace()); - - assertFalse(mdvs7.get(5) instanceof RelationshipMetadataValue); - assertEquals("project 6 (mdv)", mdvs7.get(5).getValue()); - assertEquals(5, mdvs7.get(5).getPlace()); - - ///////////////////////////////////////////////// - // after version creation - verify project 3.2 // - ///////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr3_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe1_1, isProjectOfPerson, pr3_2, BOTH, 0, 0), - isRel(pe5_1, isProjectOfPerson, pr3_2, BOTH, 0, 4), - isRel(pe3_2, isProjectOfPerson, pr3_2, BOTH, 2, 2) - )) - ); - - List mdvs8 = itemService.getMetadata( - pr3_2, "dc", "contributor", "author", Item.ANY - ); - assertEquals(6, mdvs8.size()); - - assertTrue(mdvs8.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 1 (item)", mdvs8.get(0).getValue()); - assertEquals(0, mdvs8.get(0).getPlace()); - - assertFalse(mdvs8.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 2 (mdv)", mdvs8.get(1).getValue()); - assertEquals(1, mdvs8.get(1).getPlace()); - - assertTrue(mdvs8.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs8.get(2).getValue()); - assertEquals(2, mdvs8.get(2).getPlace()); - - assertFalse(mdvs8.get(3) instanceof RelationshipMetadataValue); - assertEquals("person 4 (mdv)", mdvs8.get(3).getValue()); - assertEquals(3, mdvs8.get(3).getPlace()); - - assertTrue(mdvs8.get(4) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs8.get(4).getValue()); - assertEquals(4, mdvs8.get(4).getPlace()); - - assertFalse(mdvs8.get(5) instanceof RelationshipMetadataValue); - assertEquals("person 6 (mdv)", mdvs8.get(5).getValue()); - assertEquals(5, mdvs8.get(5).getPlace()); - - //////////////////////////////////////////////////// - // remove relationship - person 3.2 & project 3.2 // - //////////////////////////////////////////////////// - - Relationship rel1 = getRelationship(pe3_2, isProjectOfPerson, pr3_2); - assertNotNull(rel1); - - relationshipService.delete(context, rel1, false, false); - context.commit(); - - //////////////////////////////////// - // after remove 1 - cache busting // - //////////////////////////////////// - - pe3_2.setMetadataModified(); - pe3_2 = context.reloadEntity(pe3_2); - - pr3_2.setMetadataModified(); - pr3_2 = context.reloadEntity(pr3_2); - - //////////////////////////////////////// - // after remove 1 - verify person 3.1 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pe3_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe3_1, isProjectOfPerson, pr1_1, RIGHT_ONLY, 0, 0), - isRel(pe3_1, isProjectOfPerson, pr3_1, RIGHT_ONLY, 2, 2), - isRel(pe3_1, isProjectOfPerson, pr5_1, RIGHT_ONLY, 4, 2) - )) - ); - - List mdvs9 = itemService.getMetadata( - pe3_1, "dc", "relation", null, Item.ANY - ); - assertEquals(6, mdvs9.size()); - - assertTrue(mdvs9.get(0) instanceof RelationshipMetadataValue); - assertEquals("project 1 (item)", mdvs9.get(0).getValue()); - assertEquals(0, mdvs9.get(0).getPlace()); - - assertFalse(mdvs9.get(1) instanceof RelationshipMetadataValue); - assertEquals("project 2 (mdv)", mdvs9.get(1).getValue()); - assertEquals(1, mdvs9.get(1).getPlace()); - - assertTrue(mdvs9.get(2) instanceof RelationshipMetadataValue); - assertEquals("project 3 (item)", mdvs9.get(2).getValue()); - assertEquals(2, mdvs9.get(2).getPlace()); - - assertFalse(mdvs9.get(3) instanceof RelationshipMetadataValue); - assertEquals("project 4 (mdv)", mdvs9.get(3).getValue()); - assertEquals(3, mdvs9.get(3).getPlace()); - - assertTrue(mdvs9.get(4) instanceof RelationshipMetadataValue); - assertEquals("project 5 (item)", mdvs9.get(4).getValue()); - assertEquals(4, mdvs9.get(4).getPlace()); - - assertFalse(mdvs9.get(5) instanceof RelationshipMetadataValue); - assertEquals("project 6 (mdv)", mdvs9.get(5).getValue()); - assertEquals(5, mdvs9.get(5).getPlace()); - - ///////////////////////////////////////// - // after remove 1 - verify project 3.1 // - ///////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr3_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe1_1, isProjectOfPerson, pr3_1, LEFT_ONLY, 0, 0), - isRel(pe3_1, isProjectOfPerson, pr3_1, RIGHT_ONLY, 2, 2), - isRel(pe3_2, isProjectOfPerson, pr3_1, LEFT_ONLY, 2, 2), - isRel(pe5_1, isProjectOfPerson, pr3_1, LEFT_ONLY, 0, 4) - )) - ); - - List mdvs10 = itemService.getMetadata( - pr3_1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(6, mdvs10.size()); - - assertTrue(mdvs10.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 1 (item)", mdvs10.get(0).getValue()); - assertEquals(0, mdvs10.get(0).getPlace()); - - assertFalse(mdvs10.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 2 (mdv)", mdvs10.get(1).getValue()); - assertEquals(1, mdvs10.get(1).getPlace()); - - assertTrue(mdvs10.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs10.get(2).getValue()); - assertEquals(2, mdvs10.get(2).getPlace()); - - assertFalse(mdvs10.get(3) instanceof RelationshipMetadataValue); - assertEquals("person 4 (mdv)", mdvs10.get(3).getValue()); - assertEquals(3, mdvs10.get(3).getPlace()); - - assertTrue(mdvs10.get(4) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs10.get(4).getValue()); - assertEquals(4, mdvs10.get(4).getPlace()); - - assertFalse(mdvs10.get(5) instanceof RelationshipMetadataValue); - assertEquals("person 6 (mdv)", mdvs10.get(5).getValue()); - assertEquals(5, mdvs10.get(5).getPlace()); - - ///////////////////////////////////////// - // after remove 1 - verify project 5.1 // - ///////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr5_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe5_1, isProjectOfPerson, pr5_1, BOTH, 1, 1), - isRel(pe3_1, isProjectOfPerson, pr5_1, RIGHT_ONLY, 4, 2), - // NOTE: left place was reduced by one - isRel(pe3_2, isProjectOfPerson, pr5_1, BOTH, 3, 2) - )) - ); - - List mdvs11 = itemService.getMetadata( - pr5_1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(3, mdvs11.size()); - - assertFalse(mdvs11.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 7 (mdv)", mdvs11.get(0).getValue()); - assertEquals(0, mdvs11.get(0).getPlace()); - - assertTrue(mdvs11.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs11.get(1).getValue()); - assertEquals(1, mdvs11.get(1).getPlace()); - - assertTrue(mdvs11.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs11.get(2).getValue()); - assertEquals(2, mdvs11.get(2).getPlace()); - - //////////////////////////////////////// - // after remove 1 - verify person 3.2 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pe3_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe3_2, isProjectOfPerson, pr1_1, BOTH, 0, 0), - isRel(pe3_2, isProjectOfPerson, pr3_1, LEFT_ONLY, 2, 2), - // NOTE: left place was reduced by one (from 4 to 3) - isRel(pe3_2, isProjectOfPerson, pr5_1, BOTH, 3, 2) - )) - ); - - List mdvs12 = itemService.getMetadata( - pe3_2, "dc", "relation", null, Item.ANY - ); - assertEquals(5, mdvs12.size()); - - assertTrue(mdvs12.get(0) instanceof RelationshipMetadataValue); - assertEquals("project 1 (item)", mdvs12.get(0).getValue()); - assertEquals(0, mdvs12.get(0).getPlace()); - - assertFalse(mdvs12.get(1) instanceof RelationshipMetadataValue); - assertEquals("project 2 (mdv)", mdvs12.get(1).getValue()); - assertEquals(1, mdvs12.get(1).getPlace()); - - assertFalse(mdvs12.get(2) instanceof RelationshipMetadataValue); - assertEquals("project 4 (mdv)", mdvs12.get(2).getValue()); - assertEquals(2, mdvs12.get(2).getPlace()); - - assertTrue(mdvs12.get(3) instanceof RelationshipMetadataValue); - assertEquals("project 5 (item)", mdvs12.get(3).getValue()); - assertEquals(3, mdvs12.get(3).getPlace()); - - assertFalse(mdvs12.get(4) instanceof RelationshipMetadataValue); - assertEquals("project 6 (mdv)", mdvs12.get(4).getValue()); - assertEquals(4, mdvs12.get(4).getPlace()); - - ///////////////////////////////////////// - // after remove 1 - verify project 3.2 // - ///////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr3_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe1_1, isProjectOfPerson, pr3_2, BOTH, 0, 0), - // NOTE: right place was reduced by one (from 4 to 3) - isRel(pe5_1, isProjectOfPerson, pr3_2, BOTH, 0, 3) - )) - ); - - List mdvs13 = itemService.getMetadata( - pr3_2, "dc", "contributor", "author", Item.ANY - ); - assertEquals(5, mdvs13.size()); - - assertTrue(mdvs13.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 1 (item)", mdvs13.get(0).getValue()); - assertEquals(0, mdvs13.get(0).getPlace()); - - assertFalse(mdvs13.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 2 (mdv)", mdvs13.get(1).getValue()); - assertEquals(1, mdvs13.get(1).getPlace()); - - assertFalse(mdvs13.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 4 (mdv)", mdvs13.get(2).getValue()); - assertEquals(2, mdvs13.get(2).getPlace()); - - assertTrue(mdvs13.get(3) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs13.get(3).getValue()); - assertEquals(3, mdvs13.get(3).getPlace()); - - assertFalse(mdvs13.get(4) instanceof RelationshipMetadataValue); - assertEquals("person 6 (mdv)", mdvs13.get(4).getValue()); - assertEquals(4, mdvs13.get(4).getPlace()); - - //////////////////////////////////////// - // remove metadata value - person 3.2 // - //////////////////////////////////////// - - MetadataValue removeMdv1 = mdvs12.get(2); - - // let's make sure we have the metadata value that we intended to remove - assertFalse(removeMdv1 instanceof RelationshipMetadataValue); - assertEquals("project 4 (mdv)", removeMdv1.getValue()); - assertEquals(2, removeMdv1.getPlace()); - assertEquals(pe3_2, removeMdv1.getDSpaceObject()); - - itemService.removeMetadataValues(context, pe3_2, List.of(removeMdv1)); - itemService.update(context, pe3_2); - context.commit(); - - //////////////////////////////////////// - // after remove 2 - verify person 3.1 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pe3_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe3_1, isProjectOfPerson, pr1_1, RIGHT_ONLY, 0, 0), - isRel(pe3_1, isProjectOfPerson, pr3_1, RIGHT_ONLY, 2, 2), - isRel(pe3_1, isProjectOfPerson, pr5_1, RIGHT_ONLY, 4, 2) - )) - ); - - List mdvs14 = itemService.getMetadata( - pe3_1, "dc", "relation", null, Item.ANY - ); - assertEquals(6, mdvs14.size()); - - assertTrue(mdvs14.get(0) instanceof RelationshipMetadataValue); - assertEquals("project 1 (item)", mdvs14.get(0).getValue()); - assertEquals(0, mdvs14.get(0).getPlace()); - - assertFalse(mdvs14.get(1) instanceof RelationshipMetadataValue); - assertEquals("project 2 (mdv)", mdvs14.get(1).getValue()); - assertEquals(1, mdvs14.get(1).getPlace()); - - assertTrue(mdvs14.get(2) instanceof RelationshipMetadataValue); - assertEquals("project 3 (item)", mdvs14.get(2).getValue()); - assertEquals(2, mdvs14.get(2).getPlace()); - - assertFalse(mdvs14.get(3) instanceof RelationshipMetadataValue); - assertEquals("project 4 (mdv)", mdvs14.get(3).getValue()); - assertEquals(3, mdvs14.get(3).getPlace()); - - assertTrue(mdvs14.get(4) instanceof RelationshipMetadataValue); - assertEquals("project 5 (item)", mdvs14.get(4).getValue()); - assertEquals(4, mdvs14.get(4).getPlace()); - - assertFalse(mdvs14.get(5) instanceof RelationshipMetadataValue); - assertEquals("project 6 (mdv)", mdvs14.get(5).getValue()); - assertEquals(5, mdvs14.get(5).getPlace()); - - ///////////////////////////////////////// - // after remove 2 - verify project 3.1 // - ///////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr3_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe1_1, isProjectOfPerson, pr3_1, LEFT_ONLY, 0, 0), - isRel(pe3_1, isProjectOfPerson, pr3_1, RIGHT_ONLY, 2, 2), - isRel(pe3_2, isProjectOfPerson, pr3_1, LEFT_ONLY, 2, 2), - isRel(pe5_1, isProjectOfPerson, pr3_1, LEFT_ONLY, 0, 4) - )) - ); - - List mdvs15 = itemService.getMetadata( - pr3_1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(6, mdvs15.size()); - - assertTrue(mdvs15.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 1 (item)", mdvs15.get(0).getValue()); - assertEquals(0, mdvs15.get(0).getPlace()); - - assertFalse(mdvs15.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 2 (mdv)", mdvs15.get(1).getValue()); - assertEquals(1, mdvs15.get(1).getPlace()); - - assertTrue(mdvs15.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs15.get(2).getValue()); - assertEquals(2, mdvs15.get(2).getPlace()); - - assertFalse(mdvs15.get(3) instanceof RelationshipMetadataValue); - assertEquals("person 4 (mdv)", mdvs15.get(3).getValue()); - assertEquals(3, mdvs15.get(3).getPlace()); - - assertTrue(mdvs15.get(4) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs15.get(4).getValue()); - assertEquals(4, mdvs15.get(4).getPlace()); - - assertFalse(mdvs15.get(5) instanceof RelationshipMetadataValue); - assertEquals("person 6 (mdv)", mdvs15.get(5).getValue()); - assertEquals(5, mdvs15.get(5).getPlace()); - - ///////////////////////////////////////// - // after remove 2 - verify project 5.1 // - ///////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr5_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe5_1, isProjectOfPerson, pr5_1, BOTH, 1, 1), - isRel(pe3_1, isProjectOfPerson, pr5_1, RIGHT_ONLY, 4, 2), - // NOTE: left place was reduced by one - isRel(pe3_2, isProjectOfPerson, pr5_1, BOTH, 2, 2) - )) - ); - - List mdvs16 = itemService.getMetadata( - pr5_1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(3, mdvs16.size()); - - assertFalse(mdvs16.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 7 (mdv)", mdvs16.get(0).getValue()); - assertEquals(0, mdvs16.get(0).getPlace()); - - assertTrue(mdvs16.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs16.get(1).getValue()); - assertEquals(1, mdvs16.get(1).getPlace()); - - assertTrue(mdvs16.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 3 (item)", mdvs16.get(2).getValue()); - assertEquals(2, mdvs16.get(2).getPlace()); - - //////////////////////////////////////// - // after remove 2 - verify person 3.2 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pe3_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe3_2, isProjectOfPerson, pr1_1, BOTH, 0, 0), - isRel(pe3_2, isProjectOfPerson, pr3_1, LEFT_ONLY, 2, 2), - // NOTE: left place was reduced by one (from 3 to 2) - isRel(pe3_2, isProjectOfPerson, pr5_1, BOTH, 2, 2) - )) - ); - - List mdvs17 = itemService.getMetadata( - pe3_2, "dc", "relation", null, Item.ANY - ); - assertEquals(4, mdvs17.size()); - - assertTrue(mdvs17.get(0) instanceof RelationshipMetadataValue); - assertEquals("project 1 (item)", mdvs17.get(0).getValue()); - assertEquals(0, mdvs17.get(0).getPlace()); - - assertFalse(mdvs17.get(1) instanceof RelationshipMetadataValue); - assertEquals("project 2 (mdv)", mdvs17.get(1).getValue()); - assertEquals(1, mdvs17.get(1).getPlace()); - - assertTrue(mdvs17.get(2) instanceof RelationshipMetadataValue); - assertEquals("project 5 (item)", mdvs17.get(2).getValue()); - assertEquals(2, mdvs17.get(2).getPlace()); - - assertFalse(mdvs17.get(3) instanceof RelationshipMetadataValue); - assertEquals("project 6 (mdv)", mdvs17.get(3).getValue()); - assertEquals(3, mdvs17.get(3).getPlace()); - - ///////////////////////////////////////// - // after remove 2 - verify project 3.2 // - ///////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, pr3_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(pe1_1, isProjectOfPerson, pr3_2, BOTH, 0, 0), - isRel(pe5_1, isProjectOfPerson, pr3_2, BOTH, 0, 3) - )) - ); - - List mdvs18 = itemService.getMetadata( - pr3_2, "dc", "contributor", "author", Item.ANY - ); - assertEquals(5, mdvs18.size()); - - assertTrue(mdvs18.get(0) instanceof RelationshipMetadataValue); - assertEquals("person 1 (item)", mdvs18.get(0).getValue()); - assertEquals(0, mdvs18.get(0).getPlace()); - - assertFalse(mdvs18.get(1) instanceof RelationshipMetadataValue); - assertEquals("person 2 (mdv)", mdvs18.get(1).getValue()); - assertEquals(1, mdvs18.get(1).getPlace()); - - assertFalse(mdvs18.get(2) instanceof RelationshipMetadataValue); - assertEquals("person 4 (mdv)", mdvs18.get(2).getValue()); - assertEquals(2, mdvs18.get(2).getPlace()); - - assertTrue(mdvs18.get(3) instanceof RelationshipMetadataValue); - assertEquals("person 5 (item)", mdvs18.get(3).getValue()); - assertEquals(3, mdvs18.get(3).getPlace()); - - assertFalse(mdvs18.get(4) instanceof RelationshipMetadataValue); - assertEquals("person 6 (mdv)", mdvs18.get(4).getValue()); - assertEquals(4, mdvs18.get(4).getPlace()); - } - ); - } - - @Test - public void test_placeRecalculationNoUseForPlace() throws Exception { - // NOTE: this test uses relationship isIssueOfJournalVolume, because it adds virtual metadata - // on both sides of the relationship - - ////////////////// - // create items // - ////////////////// - - // journal volume 1.1 - Item v1_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal volume 1") - .withMetadata("dspace", "entity", "type", journalVolumeEntityType.getLabel()) - .withMetadata("publicationvolume", "volumeNumber", null, "volume nr 1 (rel)") - .build(); - - // journal issue 1.1 - Item i1_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 1") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 1 (rel)") - .build(); - - // journal issue 2.1 - Item i2_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 2") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 2 (rel)") - .build(); - - // journal issue 3.1 - Item i3_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 3") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 3 (rel)") - .build(); - - // journal issue 4.1 - Item i4_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 4") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 4 (rel)") - .build(); - - // journal issue 5.1 - Item i5_1 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 5") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 5 (rel)") - .build(); - - ////////////////////////////////////////////// - // create relationships and metadata values // - ////////////////////////////////////////////// - - // relationship - volume 1 & issue 1 - RelationshipBuilder.createRelationshipBuilder(context, v1_1, i1_1, isIssueOfJournalVolume) - .build(); - - // relationship - volume 1 & issue 2 - RelationshipBuilder.createRelationshipBuilder(context, v1_1, i2_1, isIssueOfJournalVolume) - .build(); - - // relationship - volume 1 & issue 3 - RelationshipBuilder.createRelationshipBuilder(context, v1_1, i3_1, isIssueOfJournalVolume) - .build(); - - // relationship - volume 1 & issue 4 - RelationshipBuilder.createRelationshipBuilder(context, v1_1, i4_1, isIssueOfJournalVolume) - .build(); - - // relationship - volume 1 & issue 5 - RelationshipBuilder.createRelationshipBuilder(context, v1_1, i5_1, isIssueOfJournalVolume) - .build(); - - ///////////////////////////////// - // initial - verify volume 3.1 // - ///////////////////////////////// - - List mdvs1 = itemService.getMetadata( - v1_1, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(5, mdvs1.size()); - - assertTrue(mdvs1.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs1.get(0).getValue()); - assertEquals(0, mdvs1.get(0).getPlace()); - - assertTrue(mdvs1.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (rel)", mdvs1.get(1).getValue()); - assertEquals(1, mdvs1.get(1).getPlace()); - - assertTrue(mdvs1.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs1.get(2).getValue()); - assertEquals(2, mdvs1.get(2).getPlace()); - - assertTrue(mdvs1.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (rel)", mdvs1.get(3).getValue()); - assertEquals(3, mdvs1.get(3).getPlace()); - - assertTrue(mdvs1.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs1.get(4).getValue()); - assertEquals(4, mdvs1.get(4).getPlace()); - - ///////////////////////////////////// - // create new version - volume 1.2 // - ///////////////////////////////////// - - Item v1_2 = versioningService.createNewVersion(context, v1_1).getItem(); - installItemService.installItem(context, workspaceItemService.findByItem(context, v1_2)); - context.commit(); - - //////////////////////////////////// - // create new version - issue 3.2 // - //////////////////////////////////// - - Item i3_2 = versioningService.createNewVersion(context, i3_1).getItem(); - installItemService.installItem(context, workspaceItemService.findByItem(context, i3_2)); - context.commit(); - - //////////////////////////////////////////////// - // after version creation - verify volume 3.1 // - //////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_1, isIssueOfJournalVolume, i1_1, RIGHT_ONLY, 0, 0), - isRel(v1_1, isIssueOfJournalVolume, i2_1, RIGHT_ONLY, 1, 0), - isRel(v1_1, isIssueOfJournalVolume, i3_1, RIGHT_ONLY, 2, 0), - isRel(v1_1, isIssueOfJournalVolume, i4_1, RIGHT_ONLY, 3, 0), - isRel(v1_1, isIssueOfJournalVolume, i5_1, RIGHT_ONLY, 4, 0) - )) - ); - - List mdvs4 = itemService.getMetadata( - v1_1, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(5, mdvs4.size()); - - assertTrue(mdvs4.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs4.get(0).getValue()); - assertEquals(0, mdvs4.get(0).getPlace()); - - assertTrue(mdvs4.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (rel)", mdvs4.get(1).getValue()); - assertEquals(1, mdvs4.get(1).getPlace()); - - assertTrue(mdvs4.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs4.get(2).getValue()); - assertEquals(2, mdvs4.get(2).getPlace()); - - assertTrue(mdvs4.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (rel)", mdvs4.get(3).getValue()); - assertEquals(3, mdvs4.get(3).getPlace()); - - assertTrue(mdvs4.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs4.get(4).getValue()); - assertEquals(4, mdvs4.get(4).getPlace()); - - //////////////////////////////////////////////// - // after version creation - verify volume 1.2 // - //////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_2, isIssueOfJournalVolume, i1_1, BOTH, 0, 0), - isRel(v1_2, isIssueOfJournalVolume, i2_1, BOTH, 1, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_1, LEFT_ONLY, 2, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_2, BOTH, 2, 0), - isRel(v1_2, isIssueOfJournalVolume, i4_1, BOTH, 3, 0), - isRel(v1_2, isIssueOfJournalVolume, i5_1, BOTH, 4, 0) - )) - ); - - List mdvs7 = itemService.getMetadata( - v1_2, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(5, mdvs7.size()); - - assertTrue(mdvs7.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs7.get(0).getValue()); - assertEquals(0, mdvs7.get(0).getPlace()); - - assertTrue(mdvs7.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (rel)", mdvs7.get(1).getValue()); - assertEquals(1, mdvs7.get(1).getPlace()); - - assertTrue(mdvs7.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs7.get(2).getValue()); - assertEquals(2, mdvs7.get(2).getPlace()); - - assertTrue(mdvs7.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (rel)", mdvs7.get(3).getValue()); - assertEquals(3, mdvs7.get(3).getPlace()); - - assertTrue(mdvs7.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs7.get(4).getValue()); - assertEquals(4, mdvs7.get(4).getPlace()); - - /////////////////////////////////////////////////////////// - // remove relationship - volume 1.2 & issue 3.2 // - // since an issue needs a relationship, delete the issue // - /////////////////////////////////////////////////////////// - - Relationship rel1 = getRelationship(v1_2, isIssueOfJournalVolume, i3_2); - assertNotNull(rel1); - - itemService.delete(context, context.reloadEntity(i3_2)); - - context.commit(); - - //////////////////////////////////// - // after remove 1 - cache busting // - //////////////////////////////////// - - v1_2.setMetadataModified(); - v1_2 = context.reloadEntity(v1_2); - - i3_2.setMetadataModified(); - i3_2 = context.reloadEntity(i3_2); - - //////////////////////////////////////// - // after remove 1 - verify volume 3.1 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_1, isIssueOfJournalVolume, i1_1, RIGHT_ONLY, 0, 0), - isRel(v1_1, isIssueOfJournalVolume, i2_1, RIGHT_ONLY, 1, 0), - isRel(v1_1, isIssueOfJournalVolume, i3_1, RIGHT_ONLY, 2, 0), - isRel(v1_1, isIssueOfJournalVolume, i4_1, RIGHT_ONLY, 3, 0), - isRel(v1_1, isIssueOfJournalVolume, i5_1, RIGHT_ONLY, 4, 0) - )) - ); - - List mdvs9 = itemService.getMetadata( - v1_1, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(5, mdvs9.size()); - - assertTrue(mdvs9.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs9.get(0).getValue()); - assertEquals(0, mdvs9.get(0).getPlace()); - - assertTrue(mdvs9.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (rel)", mdvs9.get(1).getValue()); - assertEquals(1, mdvs9.get(1).getPlace()); - - assertTrue(mdvs9.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs9.get(2).getValue()); - assertEquals(2, mdvs9.get(2).getPlace()); - - assertTrue(mdvs9.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (rel)", mdvs9.get(3).getValue()); - assertEquals(3, mdvs9.get(3).getPlace()); - - assertTrue(mdvs9.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs9.get(4).getValue()); - assertEquals(4, mdvs9.get(4).getPlace()); - - //////////////////////////////////////// - // after remove 1 - verify volume 3.2 // - //////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_2, isIssueOfJournalVolume, i1_1, BOTH, 0, 0), - isRel(v1_2, isIssueOfJournalVolume, i2_1, BOTH, 1, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_1, LEFT_ONLY, 2, 0), - // NOTE: left place was reduced by one - isRel(v1_2, isIssueOfJournalVolume, i4_1, BOTH, 2, 0), - isRel(v1_2, isIssueOfJournalVolume, i5_1, BOTH, 3, 0) - )) - ); - - List mdvs12 = itemService.getMetadata( - v1_2, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(4, mdvs12.size()); - - assertTrue(mdvs12.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs12.get(0).getValue()); - assertEquals(0, mdvs12.get(0).getPlace()); - - assertTrue(mdvs12.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (rel)", mdvs12.get(1).getValue()); - assertEquals(1, mdvs12.get(1).getPlace()); - - assertTrue(mdvs12.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (rel)", mdvs12.get(2).getValue()); - assertEquals(2, mdvs12.get(2).getPlace()); - - assertTrue(mdvs12.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs12.get(3).getValue()); - assertEquals(3, mdvs12.get(3).getPlace()); - - //////////////////////////////////// - // create new version - issue 3.3 // - //////////////////////////////////// - - // journal issue 3.3 - Item i3_3 = ItemBuilder.createItem(context, collection) - .withTitle("journal issue 3") - .withMetadata("dspace", "entity", "type", journalIssueEntityType.getLabel()) - .withMetadata("publicationissue", "issueNumber", null, "issue nr 3 (rel)") - .build(); - - /////////////////////////////////////////////// - // add relationship - volume 1.2 & issue 3.3 // - /////////////////////////////////////////////// - - RelationshipBuilder.createRelationshipBuilder(context, v1_2, i3_3, isIssueOfJournalVolume, 2, -1) - .build(); - - context.commit(); - - //////////////////////////////////////////// - // after add relationship - cache busting // - //////////////////////////////////////////// - - v1_2.setMetadataModified(); - v1_2 = context.reloadEntity(v1_2); - - i3_3.setMetadataModified(); - i3_3 = context.reloadEntity(i3_3); - - //////////////////////////////////////////////// - // after add relationship - verify volume 1.1 // - //////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_1, isIssueOfJournalVolume, i1_1, RIGHT_ONLY, 0, 0), - isRel(v1_1, isIssueOfJournalVolume, i2_1, RIGHT_ONLY, 1, 0), - isRel(v1_1, isIssueOfJournalVolume, i3_1, RIGHT_ONLY, 2, 0), - isRel(v1_1, isIssueOfJournalVolume, i4_1, RIGHT_ONLY, 3, 0), - isRel(v1_1, isIssueOfJournalVolume, i5_1, RIGHT_ONLY, 4, 0) - )) - ); - - List mdvs14 = itemService.getMetadata( - v1_1, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(5, mdvs14.size()); - - assertTrue(mdvs14.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs14.get(0).getValue()); - assertEquals(0, mdvs14.get(0).getPlace()); - - assertTrue(mdvs14.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (rel)", mdvs14.get(1).getValue()); - assertEquals(1, mdvs14.get(1).getPlace()); - - assertTrue(mdvs14.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs14.get(2).getValue()); - assertEquals(2, mdvs14.get(2).getPlace()); - - assertTrue(mdvs14.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (rel)", mdvs14.get(3).getValue()); - assertEquals(3, mdvs14.get(3).getPlace()); - - assertTrue(mdvs14.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs14.get(4).getValue()); - assertEquals(4, mdvs14.get(4).getPlace()); - - //////////////////////////////////////////////// - // after add relationship - verify volume 1.2 // - //////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, v1_2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(v1_2, isIssueOfJournalVolume, i1_1, BOTH, 0, 0), - isRel(v1_2, isIssueOfJournalVolume, i2_1, BOTH, 1, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_1, LEFT_ONLY, 2, 0), - isRel(v1_2, isIssueOfJournalVolume, i3_3, BOTH, 2, 0), - isRel(v1_2, isIssueOfJournalVolume, i4_1, BOTH, 3, 0), - isRel(v1_2, isIssueOfJournalVolume, i5_1, BOTH, 4, 0) - )) - ); - - assertEquals( - 6, - relationshipService.countByItem(context, v1_2, false, false) - ); - - List mdvs17 = itemService.getMetadata( - v1_2, "publicationissue", "issueNumber", null, Item.ANY - ); - assertEquals(5, mdvs17.size()); - - assertTrue(mdvs17.get(0) instanceof RelationshipMetadataValue); - assertEquals("issue nr 1 (rel)", mdvs17.get(0).getValue()); - assertEquals(0, mdvs17.get(0).getPlace()); - - assertTrue(mdvs17.get(1) instanceof RelationshipMetadataValue); - assertEquals("issue nr 2 (rel)", mdvs17.get(1).getValue()); - assertEquals(1, mdvs17.get(1).getPlace()); - - assertTrue(mdvs7.get(2) instanceof RelationshipMetadataValue); - assertEquals("issue nr 3 (rel)", mdvs7.get(2).getValue()); - assertEquals(2, mdvs7.get(2).getPlace()); - - assertTrue(mdvs17.get(3) instanceof RelationshipMetadataValue); - assertEquals("issue nr 4 (rel)", mdvs17.get(3).getValue()); - assertEquals(3, mdvs17.get(3).getPlace()); - - assertTrue(mdvs17.get(4) instanceof RelationshipMetadataValue); - assertEquals("issue nr 5 (rel)", mdvs17.get(4).getValue()); - assertEquals(4, mdvs17.get(4).getPlace()); - - ///////////////////////////////////////////// - // delete volume first for min cardinality // - ///////////////////////////////////////////// - - itemService.delete(context, context.reloadEntity(v1_1)); - itemService.delete(context, context.reloadEntity(v1_2)); - } - - protected void verifySolrField(Item item, String fieldName, List expectedValues) throws Exception { - QueryResponse result = solrSearchCore.getSolr().query(new SolrQuery(String.format( - "search.resourcetype:\"Item\" AND search.resourceid:\"%s\"", item.getID() - ))); - - SolrDocumentList docs = result.getResults(); - Assert.assertEquals(1, docs.size()); - SolrDocument doc = docs.get(0); - - java.util.Collection actualValues = doc.getFieldValues(fieldName); - - if (expectedValues == null) { - assertNull(actualValues); - } else { - assertThat(actualValues, containsInAnyOrder(expectedValues.toArray())); - } - } - - /** - * Setup: - * - two people are linked to one publication - * - create a new version of the publication - * - create a new version of person 1 - * - create a new version of person 2 - * - * Goals: - * - check that the metadata (plain text and from relationships) of the items have the correct value and place, - * as new versions of the items get created and edited - * - verify that changes to newer versions and relationships don't affect older versions and relationships - * - verify that the (versions of) items are properly indexed in the Solr search core - */ - @Test - public void test_virtualMetadataPreserved() throws Exception { - ////////////////////////////////////////////// - // create a publication and link two people // - ////////////////////////////////////////////// - - Item publication1V1 = ItemBuilder.createItem(context, collection) - .withTitle("publication 1V1") - .withMetadata("dspace", "entity", "type", publicationEntityType.getLabel()) - .build(); - - Item person1V1 = ItemBuilder.createItem(context, collection) - .withTitle("person 1V1") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .withPersonIdentifierFirstName("Donald") - .withPersonIdentifierLastName("Smith") - .build(); - - Item person2V1 = ItemBuilder.createItem(context, collection) - .withTitle("person 2V1") - .withMetadata("dspace", "entity", "type", personEntityType.getLabel()) - .withPersonIdentifierFirstName("Jane") - .withPersonIdentifierLastName("Doe") - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, publication1V1, person1V1, isAuthorOfPublication) - .build(); - - RelationshipBuilder.createRelationshipBuilder(context, publication1V1, person2V1, isAuthorOfPublication) - .withRightwardValue("Doe, J.") - .build(); - - /////////////////////////////////////////////// - // test dc.contributor.author of publication // - /////////////////////////////////////////////// - - List mdvs1 = itemService.getMetadata( - publication1V1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs1.size()); - - assertTrue(mdvs1.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, Donald", mdvs1.get(0).getValue()); - assertEquals(0, mdvs1.get(0).getPlace()); - - assertTrue(mdvs1.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, J.", mdvs1.get(1).getValue()); - assertEquals(1, mdvs1.get(1).getPlace()); - - verifySolrField(publication1V1, "dc.contributor.author", List.of( - "Smith, Donald", "Doe, J." - )); - - //////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of publication // - //////////////////////////////////////////////////////// - - List mdvsR1 = itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR1.size()); - - assertTrue(mdvsR1.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V1.getID().toString(), mdvsR1.get(0).getValue()); - assertEquals(0, mdvsR1.get(0).getPlace()); - - assertTrue(mdvsR1.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V1.getID().toString(), mdvsR1.get(1).getValue()); - assertEquals(1, mdvsR1.get(1).getPlace()); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication", List.of( - person1V1.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of publication // - /////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder( - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person2V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ) - ) - ); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication.latestForDiscovery", List.of( - person1V1.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////// - // create a new version of publication 1 and archive // - /////////////////////////////////////////////////////// - - Item publication1V2 = versioningService.createNewVersion(context, publication1V1).getItem(); - installItemService.installItem(context, workspaceItemService.findByItem(context, publication1V2)); - context.dispatchEvents(); - - //////////////////////////////////// - // create new version of person 1 // - //////////////////////////////////// - - Item person1V2 = versioningService.createNewVersion(context, person1V1).getItem(); - // update "Smith, Donald" to "Smith, D." - itemService.replaceMetadata( - context, person1V2, "person", "givenName", null, null, "D.", - null, -1, 0 - ); - itemService.update(context, person1V2); - context.dispatchEvents(); - - /////////////////// - // cache busting // - /////////////////// - - publication1V1.setMetadataModified(); - publication1V1 = context.reloadEntity(publication1V1); - - publication1V2.setMetadataModified(); - publication1V2 = context.reloadEntity(publication1V2); - - /////////////////////////////////////////////////// - // test dc.contributor.author of old publication // - /////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, publication1V1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1V1, isAuthorOfPublication, person1V1, RIGHT_ONLY, 0, 0), - isRel(publication1V1, isAuthorOfPublication, person2V1, RIGHT_ONLY, null, "Doe, J.", 1, 0) - )) - ); - - List mdvs2 = itemService.getMetadata( - publication1V1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs2.size()); - - assertTrue(mdvs2.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, Donald", mdvs2.get(0).getValue()); - assertEquals(0, mdvs2.get(0).getPlace()); - - assertTrue(mdvs2.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, J.", mdvs2.get(1).getValue()); - assertEquals(1, mdvs2.get(1).getPlace()); - - verifySolrField(publication1V1, "dc.contributor.author", List.of( - "Smith, Donald", "Doe, J." - )); - - //////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of old publication // - //////////////////////////////////////////////////////////// - - List mdvsR2 = itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR2.size()); - - assertTrue(mdvsR2.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V1.getID().toString(), mdvsR2.get(0).getValue()); - assertEquals(0, mdvsR2.get(0).getPlace()); - - assertTrue(mdvsR2.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V1.getID().toString(), mdvsR2.get(1).getValue()); - assertEquals(1, mdvsR2.get(1).getPlace()); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication", List.of( - person1V1.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of old publication // - /////////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder() - ); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication.latestForDiscovery", null); - - /////////////////////////////////////////////////// - // test dc.contributor.author of new publication // - /////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, publication1V2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1V2, isAuthorOfPublication, person1V1, BOTH, 0, 0), - isRel(publication1V2, isAuthorOfPublication, person1V2, LEFT_ONLY, 0, 0), - isRel(publication1V2, isAuthorOfPublication, person2V1, BOTH, null, "Doe, J.", 1, 0) - )) - ); - - List mdvs3 = itemService.getMetadata( - publication1V2, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs3.size()); - - assertTrue(mdvs3.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, Donald", mdvs3.get(0).getValue()); - assertEquals(0, mdvs3.get(0).getPlace()); - - assertTrue(mdvs3.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, J.", mdvs3.get(1).getValue()); - assertEquals(1, mdvs3.get(1).getPlace()); - - verifySolrField(publication1V2, "dc.contributor.author", List.of( - "Smith, Donald", "Doe, J." - )); - - //////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of new publication // - //////////////////////////////////////////////////////////// - - List mdvsR3 = itemService.getMetadata( - publication1V2, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR3.size()); - - assertTrue(mdvsR3.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V1.getID().toString(), mdvsR3.get(0).getValue()); - assertEquals(0, mdvsR3.get(0).getPlace()); - - assertTrue(mdvsR3.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V1.getID().toString(), mdvsR3.get(1).getValue()); - assertEquals(1, mdvsR3.get(1).getPlace()); - - verifySolrField(publication1V2, "relation.isAuthorOfPublication", List.of( - person1V1.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of new publication // - /////////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V2, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder( - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V2.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person2V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ) - ) - ); - - verifySolrField(publication1V2, "relation.isAuthorOfPublication.latestForDiscovery", List.of( - person1V1.getID().toString(), person1V2.getID().toString(), person2V1.getID().toString() - )); - - ///////////////////////////////////// - // archive new version of person 1 // - ///////////////////////////////////// - - installItemService.installItem(context, workspaceItemService.findByItem(context, person1V2)); - context.dispatchEvents(); - - /////////////////// - // cache busting // - /////////////////// - - publication1V1.setMetadataModified(); - publication1V1 = context.reloadEntity(publication1V1); - - publication1V2.setMetadataModified(); - publication1V2 = context.reloadEntity(publication1V2); - - /////////////////////////////////////////////////// - // test dc.contributor.author of old publication // - /////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, publication1V1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1V1, isAuthorOfPublication, person1V1, RIGHT_ONLY, 0, 0), - isRel(publication1V1, isAuthorOfPublication, person2V1, RIGHT_ONLY, null, "Doe, J.", 1, 0) - )) - ); - - List mdvs4 = itemService.getMetadata( - publication1V1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs4.size()); - - assertTrue(mdvs4.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, Donald", mdvs4.get(0).getValue()); - assertEquals(0, mdvs4.get(0).getPlace()); - - assertTrue(mdvs4.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, J.", mdvs4.get(1).getValue()); - assertEquals(1, mdvs4.get(1).getPlace()); - - verifySolrField(publication1V1, "dc.contributor.author", List.of( - "Smith, Donald", "Doe, J." - )); - - //////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of publication // - //////////////////////////////////////////////////////// - - List mdvsR4 = itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR4.size()); - - assertTrue(mdvsR4.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V1.getID().toString(), mdvsR4.get(0).getValue()); - assertEquals(0, mdvsR4.get(0).getPlace()); - - assertTrue(mdvsR4.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V1.getID().toString(), mdvsR4.get(1).getValue()); - assertEquals(1, mdvsR4.get(1).getPlace()); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication", List.of( - person1V1.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of publication // - /////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder() - ); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication.latestForDiscovery", null); - - /////////////////////////////////////////////////// - // test dc.contributor.author of new publication // - /////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, publication1V2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1V2, isAuthorOfPublication, person1V1, LEFT_ONLY, 0, 0), - isRel(publication1V2, isAuthorOfPublication, person1V2, BOTH, 0, 0), - isRel(publication1V2, isAuthorOfPublication, person2V1, BOTH, null, "Doe, J.", 1, 0) - )) - ); - - List mdvs5 = itemService.getMetadata( - publication1V2, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs5.size()); - - assertTrue(mdvs5.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, D.", mdvs5.get(0).getValue()); - assertEquals(0, mdvs5.get(0).getPlace()); - - assertTrue(mdvs5.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, J.", mdvs5.get(1).getValue()); - assertEquals(1, mdvs5.get(1).getPlace()); - - verifySolrField(publication1V2, "dc.contributor.author", List.of( - "Smith, D.", "Doe, J." - )); - - //////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of new publication // - //////////////////////////////////////////////////////////// - - List mdvsR5 = itemService.getMetadata( - publication1V2, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR5.size()); - - assertTrue(mdvsR5.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V2.getID().toString(), mdvsR5.get(0).getValue()); - assertEquals(0, mdvsR5.get(0).getPlace()); - - assertTrue(mdvsR5.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V1.getID().toString(), mdvsR5.get(1).getValue()); - assertEquals(1, mdvsR5.get(1).getPlace()); - - verifySolrField(publication1V2, "relation.isAuthorOfPublication", List.of( - person1V2.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of new publication // - /////////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V2, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder( - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V2.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person2V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ) - ) - ); - - verifySolrField(publication1V2, "relation.isAuthorOfPublication.latestForDiscovery", List.of( - person1V1.getID().toString(), person1V2.getID().toString(), person2V1.getID().toString() - )); - - //////////////////////////////////// - // create new version of person 2 // - //////////////////////////////////// - - Item person2V2 = versioningService.createNewVersion(context, person2V1).getItem(); - Relationship rel1 = getRelationship(publication1V2, isAuthorOfPublication, person2V2); - assertNotNull(rel1); - rel1.setRightwardValue("Doe, Jane Jr"); - relationshipService.update(context, rel1); - context.dispatchEvents(); - - /////////////////// - // cache busting // - /////////////////// - - publication1V1.setMetadataModified(); - publication1V1 = context.reloadEntity(publication1V1); - - publication1V2.setMetadataModified(); - publication1V2 = context.reloadEntity(publication1V2); - - /////////////////////////////////////////////////// - // test dc.contributor.author of old publication // - /////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, publication1V1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1V1, isAuthorOfPublication, person1V1, RIGHT_ONLY, 0, 0), - isRel(publication1V1, isAuthorOfPublication, person2V1, RIGHT_ONLY, null, "Doe, J.", 1, 0) - )) - ); - - List mdvs6 = itemService.getMetadata( - publication1V1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs6.size()); - - assertTrue(mdvs6.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, Donald", mdvs6.get(0).getValue()); - assertEquals(0, mdvs6.get(0).getPlace()); - - assertTrue(mdvs6.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, J.", mdvs6.get(1).getValue()); - assertEquals(1, mdvs6.get(1).getPlace()); - - verifySolrField(publication1V1, "dc.contributor.author", List.of( - "Smith, Donald", "Doe, J." - )); - - //////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of old publication // - //////////////////////////////////////////////////////////// - - List mdvsR6 = itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR6.size()); - - assertTrue(mdvsR6.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V1.getID().toString(), mdvsR6.get(0).getValue()); - assertEquals(0, mdvsR6.get(0).getPlace()); - - assertTrue(mdvsR6.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V1.getID().toString(), mdvsR6.get(1).getValue()); - assertEquals(1, mdvsR6.get(1).getPlace()); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication", List.of( - person1V1.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of old publication // - /////////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder() - ); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication.latestForDiscovery", null); - - /////////////////////////////////////////////////// - // test dc.contributor.author of new publication // - /////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, publication1V2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1V2, isAuthorOfPublication, person1V1, LEFT_ONLY, 0, 0), - isRel(publication1V2, isAuthorOfPublication, person1V2, BOTH, 0, 0), - isRel(publication1V2, isAuthorOfPublication, person2V1, BOTH, null, "Doe, J.", 1, 0), - isRel(publication1V2, isAuthorOfPublication, person2V2, LEFT_ONLY, null, "Doe, Jane Jr", 1, 0) - )) - ); - - List mdvs7 = itemService.getMetadata( - publication1V2, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs7.size()); - - assertTrue(mdvs7.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, D.", mdvs7.get(0).getValue()); - assertEquals(0, mdvs7.get(0).getPlace()); - - assertTrue(mdvs7.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, J.", mdvs7.get(1).getValue()); - assertEquals(1, mdvs7.get(1).getPlace()); - - verifySolrField(publication1V2, "dc.contributor.author", List.of( - "Smith, D.", "Doe, J." - )); - - //////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of new publication // - //////////////////////////////////////////////////////////// - - List mdvsR7 = itemService.getMetadata( - publication1V2, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR7.size()); - - assertTrue(mdvsR7.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V2.getID().toString(), mdvsR7.get(0).getValue()); - assertEquals(0, mdvsR7.get(0).getPlace()); - - assertTrue(mdvsR7.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V1.getID().toString(), mdvsR7.get(1).getValue()); - assertEquals(1, mdvsR7.get(1).getPlace()); - - verifySolrField(publication1V2, "relation.isAuthorOfPublication", List.of( - person1V2.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of new publication // - /////////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V2, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder( - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V2.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person2V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person2V2.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ) - ) - ); - - verifySolrField(publication1V2, "relation.isAuthorOfPublication.latestForDiscovery", List.of( - person1V1.getID().toString(), person1V2.getID().toString(), - person2V1.getID().toString(), person2V2.getID().toString() - )); - - ///////////////////////////////////// - // archive new version of person 2 // - ///////////////////////////////////// - - installItemService.installItem(context, workspaceItemService.findByItem(context, person2V2)); - context.dispatchEvents(); - - /////////////////// - // cache busting // - /////////////////// - - publication1V1.setMetadataModified(); - publication1V1 = context.reloadEntity(publication1V1); - - publication1V2.setMetadataModified(); - publication1V2 = context.reloadEntity(publication1V2); - - /////////////////////////////////////////////////// - // test dc.contributor.author of old publication // - /////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, publication1V1, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1V1, isAuthorOfPublication, person1V1, RIGHT_ONLY, 0, 0), - isRel(publication1V1, isAuthorOfPublication, person2V1, RIGHT_ONLY, null, "Doe, J.", 1, 0) - )) - ); - - List mdvs8 = itemService.getMetadata( - publication1V1, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs8.size()); - - assertTrue(mdvs8.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, Donald", mdvs8.get(0).getValue()); - assertEquals(0, mdvs8.get(0).getPlace()); - - assertTrue(mdvs8.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, J.", mdvs8.get(1).getValue()); - assertEquals(1, mdvs8.get(1).getPlace()); - - verifySolrField(publication1V1, "dc.contributor.author", List.of( - "Smith, Donald", "Doe, J." - )); - - //////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of old publication // - //////////////////////////////////////////////////////////// - - List mdvsR8 = itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR8.size()); - - assertTrue(mdvsR8.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V1.getID().toString(), mdvsR8.get(0).getValue()); - assertEquals(0, mdvsR8.get(0).getPlace()); - - assertTrue(mdvsR8.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V1.getID().toString(), mdvsR8.get(1).getValue()); - assertEquals(1, mdvsR8.get(1).getPlace()); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication", List.of( - person1V1.getID().toString(), person2V1.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of old publication // - /////////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V1, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder() - ); - - verifySolrField(publication1V1, "relation.isAuthorOfPublication.latestForDiscovery", null); - - /////////////////////////////////////////////////// - // test dc.contributor.author of new publication // - /////////////////////////////////////////////////// - - assertThat( - relationshipService.findByItem(context, publication1V2, -1, -1, false, false), - containsInAnyOrder(List.of( - isRel(publication1V2, isAuthorOfPublication, person1V1, LEFT_ONLY, 0, 0), - isRel(publication1V2, isAuthorOfPublication, person1V2, BOTH, 0, 0), - isRel(publication1V2, isAuthorOfPublication, person2V1, LEFT_ONLY, null, "Doe, J.", 1, 0), - isRel(publication1V2, isAuthorOfPublication, person2V2, BOTH, null, "Doe, Jane Jr", 1, 0) - )) - ); - - List mdvs9 = itemService.getMetadata( - publication1V2, "dc", "contributor", "author", Item.ANY - ); - assertEquals(2, mdvs9.size()); - - assertTrue(mdvs9.get(0) instanceof RelationshipMetadataValue); - assertEquals("Smith, D.", mdvs9.get(0).getValue()); - assertEquals(0, mdvs9.get(0).getPlace()); - - assertTrue(mdvs9.get(1) instanceof RelationshipMetadataValue); - assertEquals("Doe, Jane Jr", mdvs9.get(1).getValue()); - assertEquals(1, mdvs9.get(1).getPlace()); - - verifySolrField(publication1V2, "dc.contributor.author", List.of( - "Smith, D.", "Doe, Jane Jr" - )); - - //////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication of new publication // - //////////////////////////////////////////////////////////// - - List mdvsR9 = itemService.getMetadata( - publication1V2, "relation", "isAuthorOfPublication", null, Item.ANY - ); - assertEquals(2, mdvsR9.size()); - - assertTrue(mdvsR9.get(0) instanceof RelationshipMetadataValue); - assertEquals(person1V2.getID().toString(), mdvsR9.get(0).getValue()); - assertEquals(0, mdvsR9.get(0).getPlace()); - - assertTrue(mdvsR9.get(1) instanceof RelationshipMetadataValue); - assertEquals(person2V2.getID().toString(), mdvsR9.get(1).getValue()); - assertEquals(1, mdvsR9.get(1).getPlace()); - - verifySolrField(publication1V2, "relation.isAuthorOfPublication", List.of( - person1V2.getID().toString(), person2V2.getID().toString() - )); - - /////////////////////////////////////////////////////////////////////////////// - // test relation.isAuthorOfPublication.latestForDiscovery of new publication // - /////////////////////////////////////////////////////////////////////////////// - - assertThat( - itemService.getMetadata( - publication1V2, "relation", "isAuthorOfPublication", "latestForDiscovery", Item.ANY - ), - containsInAnyOrder( - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person1V2.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person2V1.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ), - allOf( - instanceOf(RelationshipMetadataValue.class), - hasProperty("value", is(person2V2.getID().toString())), - hasProperty("place", is(-1)), - hasProperty("authority", startsWith(Constants.VIRTUAL_AUTHORITY_PREFIX)) - ) - ) - ); - - verifySolrField(publication1V2, "relation.isAuthorOfPublication.latestForDiscovery", List.of( - person1V1.getID().toString(), person1V2.getID().toString(), - person2V1.getID().toString(), person2V2.getID().toString() - )); - } - -} diff --git a/dspace-oai/src/main/java/org/dspace/utils/LangUtil.java b/dspace-oai/src/main/java/org/dspace/utils/LangUtil.java new file mode 100644 index 000000000000..9fda94dbbd95 --- /dev/null +++ b/dspace-oai/src/main/java/org/dspace/utils/LangUtil.java @@ -0,0 +1,104 @@ +/** + * 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/ + */ + +/* Created for LINDAT/CLARIAH-CZ (UFAL) */ +package org.dspace.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; + +/** + * Class is copied from the LINDAT/CLARIAH-CZ (This class is taken from UFAL-clarin. + * ...) and modified by + * + * @author Marian Berger (dspace at dataquest.sk) + */ +public class LangUtil { + + private LangUtil() {} + private static org.apache.log4j.Logger log = org.apache.log4j.Logger + .getLogger(LangUtil.class); + + static final HashMap idToLang; + + static { + idToLang = new HashMap<>(); + final InputStream langCodesInputStream = LangUtil.class.getClassLoader() + .getResourceAsStream("iso-639-3.tab"); + if (langCodesInputStream != null) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(langCodesInputStream, + StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + Lang lang = new Lang(line); + idToLang.put(lang.getId(), lang); + if (lang.getPart2B() != null) { + idToLang.put(lang.getPart2B(), lang); + } + } + } catch (IOException e) { + log.error(e); + } + } + } + + public static String getShortestId(String id) { + Lang lang = idToLang.get(id); + if (lang != null) { + if (lang.getPart1() != null) { + return lang.getPart1(); + } else { + return lang.getId(); + } + } + return id; + } + + public static void main(String[] args) { + System.out.println(getShortestId("eng")); + System.out.println(getShortestId("deu")); + System.out.println(getShortestId("ger")); + System.out.println(getShortestId("wtf")); + } + + private static class Lang { + private final String id; + private final String part2B; + //private final String part2T; + private final String part1; + /*private final String scope; + private final String languageType; + private final String refName; + private final String comment;*/ + + public Lang(String line) { + String[] parts = line.split("\t", 8); + id = parts[0]; + part2B = parts[1].isEmpty() ? null : parts[1]; + //part2T = parts[2]; + part1 = parts[3].isEmpty() ? null : parts[3]; + } + + public String getId() { + return id; + } + + public String getPart1() { + return part1; + } + + public String getPart2B() { + return part2B; + } + } +} \ No newline at end of file diff --git a/dspace-oai/src/main/java/org/dspace/utils/LicenseUtil.java b/dspace-oai/src/main/java/org/dspace/utils/LicenseUtil.java index b9f913edcab7..975dbf39f1c7 100644 --- a/dspace-oai/src/main/java/org/dspace/utils/LicenseUtil.java +++ b/dspace-oai/src/main/java/org/dspace/utils/LicenseUtil.java @@ -26,8 +26,8 @@ * https://github.com/ufal/clarin-dspace/blob * * /si-master-origin/dspace-oai/src/main/java/cz/cuni/mff/ufal/utils/LicenseUtil.java) and modified by * - * @author Marian Berger (marian.berger at dataquest.sk) - * @author Milan Majchrak (milan.majchrak at dataquest.sk) + * @author Marian Berger (dspace at dataquest.sk) + * @author Milan Majchrak (dspace at dataquest.sk) */ public class LicenseUtil { 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 4f842b8e944c..4930dd5956c3 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 @@ -425,8 +425,14 @@ private SolrInputDocument index(Item item) * because this will override the item.public flag. */ + boolean discoverable = item.isDiscoverable(); + // The Item is not deleted when it has local metadata `local.hidden = hidden`. + // Without this, the item is not discoverable and harvestable; however, it should be harvestable via OAI-PMH. + if (!discoverable && item.isHidden()) { + discoverable = true; + } doc.addField("item.deleted", - (item.isWithdrawn() || !item.isDiscoverable() || (isEmbargoed ? isPublic : false))); + (item.isWithdrawn() || (!discoverable) || (isEmbargoed ? isPublic : false))); /* * An item that is embargoed will potentially not be harvested by incremental diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/ColComFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/ColComFilter.java index b2a2f09da7a9..7efe6994dcb2 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/ColComFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/ColComFilter.java @@ -18,14 +18,14 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; +import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; import org.dspace.core.Constants; +import org.dspace.handle.factory.HandleServiceFactory; +import org.dspace.handle.service.HandleService; import org.dspace.xoai.data.DSpaceItem; import org.dspace.xoai.filter.results.SolrFilterResult; -import org.dspace.xoai.services.api.HandleResolver; -import org.dspace.xoai.services.api.HandleResolverException; -import org.springframework.beans.factory.annotation.Autowired; /** * Serves as filter in xoai for OAI-PMH interface. @@ -39,14 +39,11 @@ public class ColComFilter extends DSpaceFilter { private DSpaceObject dso = null; - @Autowired - private HandleResolver handleResolver; + private static HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - @Autowired - private CommunityService communityService; + private static CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); - @Autowired - private CollectionService collectionService; + private static CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); @Override public SolrFilterResult buildSolrQuery() { @@ -88,14 +85,14 @@ private String getSetSpec() { } private DSpaceObject getDSpaceObject() { - if (Objects.isNull(dso)) { + if (Objects.nonNull(dso)) { return dso; } if (Objects.nonNull(getConfiguration().get("handle"))) { String handle = getConfiguration().get("handle").asSimpleType().asString(); try { - dso = handleResolver.resolve(handle); - } catch (HandleResolverException e) { + dso = handleService.resolveToObject(context, handle); + } catch (SQLException e) { log.error(e); } } else if (Objects.nonNull(getConfiguration().get("name"))) { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/DSpaceResourceResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/DSpaceResourceResolver.java index aec4ea516e14..9d4790b9ff47 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/DSpaceResourceResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/DSpaceResourceResolver.java @@ -34,6 +34,7 @@ import org.dspace.xoai.services.impl.resources.functions.GetUploadedMetadataFn; import org.dspace.xoai.services.impl.resources.functions.LogMissingFn; import org.dspace.xoai.services.impl.resources.functions.LogMissingMsgFn; +import org.dspace.xoai.services.impl.resources.functions.ShortestIdFn; import org.dspace.xoai.services.impl.resources.functions.StringReplaceFn; import org.dspace.xoai.services.impl.resources.functions.UriToLicenseFn; import org.dspace.xoai.services.impl.resources.functions.UriToMetaShareFn; @@ -50,7 +51,7 @@ public class DSpaceResourceResolver implements ResourceResolver { */ List extensionFunctionList = List.of( new GetPropertyFn(), new StringReplaceFn(), new UriToMetaShareFn(), - new UriToLicenseFn(), new LogMissingMsgFn(), new UriToRestrictionsFn(), + new UriToLicenseFn(), new LogMissingMsgFn(), new UriToRestrictionsFn(), new ShortestIdFn(), new GetContactFn(), new GetAuthorFn(), new GetFundingFn(), new GetLangForCodeFn(), new GetPropertyFn(), new GetSizeFn(), new GetUploadedMetadataFn(), new LogMissingFn(), new BibtexifyFn(), new FormatFn() @@ -62,6 +63,7 @@ public class DSpaceResourceResolver implements ResourceResolver { saxonTransformerFactory.getProcessor().registerExtensionFunction(en); } } + private final String basePath; public DSpaceResourceResolver() { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/LogMissingFn.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/LogMissingFn.java index c2ec365ac633..b9a60dc8bdae 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/LogMissingFn.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/LogMissingFn.java @@ -20,6 +20,7 @@ import net.sf.saxon.s9api.SequenceType; import net.sf.saxon.s9api.XdmAtomicValue; import net.sf.saxon.s9api.XdmValue; +import org.apache.logging.log4j.Logger; import org.bouncycastle.util.Arrays; import org.dspace.utils.XslLogUtil; @@ -30,6 +31,7 @@ */ public class LogMissingFn implements ExtensionFunction { + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(LogMissingFn.class); @Override public QName getName() { return new QName(BASE, "logMissing"); @@ -53,8 +55,27 @@ public XdmValue call(XdmValue[] xdmValues) throws SaxonApiException { if (Objects.isNull(xdmValues) || Arrays.isNullOrContainsNull(xdmValues)) { return new XdmAtomicValue(""); } - return new XdmAtomicValue(checks(XslLogUtil.logMissing(xdmValues[0].itemAt(0).getStringValue(), - xdmValues[1].itemAt(0).getStringValue()))); + + String val0; + try { + val0 = xdmValues[0].itemAt(0).getStringValue(); + } catch (Exception e) { + // e.g. when no parameter is passed and xdmValues[0] ends with index error + log.warn("Empty value to call of function LogMissingFn in the first argument"); + val0 = ""; + } + + String val1; + try { + val1 = xdmValues[1].itemAt(0).getStringValue(); + } catch (Exception e) { + // e.g. when no parameter is passed and xdmValues[0] ends with index error + log.warn("Empty value to call of function LogMissingFn in the second argument"); + val1 = ""; + } + + + return new XdmAtomicValue(checks(XslLogUtil.logMissing(val0,val1))); } private String checks(String got) { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/NodeListXslFunction.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/NodeListXslFunction.java index 46b198994f31..775d5c8c12be 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/NodeListXslFunction.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/NodeListXslFunction.java @@ -8,7 +8,6 @@ package org.dspace.xoai.services.impl.resources.functions; -import static org.apache.logging.log4j.LogManager.getLogger; import static org.dspace.xoai.services.impl.resources.functions.StringXSLFunction.BASE; import java.util.Objects; @@ -38,12 +37,10 @@ */ public abstract class NodeListXslFunction implements ExtensionFunction { + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(NodeListXslFunction.class); protected abstract String getFnName(); protected abstract NodeList getNodeList(String param); - - private static final Logger log = getLogger(NodeListXslFunction.class); - @Override final public QName getName() { return new QName(BASE, getFnName()); @@ -58,7 +55,7 @@ final public SequenceType getResultType() { final public SequenceType[] getArgumentTypes() { return new SequenceType[]{ SequenceType.makeSequenceType( - ItemType.STRING, OccurrenceIndicator.ONE)}; + ItemType.STRING, OccurrenceIndicator.ZERO_OR_MORE)}; } @Override @@ -67,7 +64,17 @@ final public XdmValue call(XdmValue[] xdmValues) throws SaxonApiException { return new XdmAtomicValue(""); } - NodeList nodeList = getNodeList(xdmValues[0].itemAt(0).getStringValue()); + String val; + try { + val = xdmValues[0].itemAt(0).getStringValue(); + } catch (Exception e) { + // e.g. when no parameter is passed and xdmValues[0] ends with index error + log.warn("Empty value in call of function of NodeListXslFunction type"); + val = ""; + } + + + NodeList nodeList = getNodeList(val); Node oneNode = nodeList.item(0); DocumentBuilder db = new Processor(false).newDocumentBuilder(); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/NodeXslFunction.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/NodeXslFunction.java index e727d3255120..684b9e3aa6ef 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/NodeXslFunction.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/NodeXslFunction.java @@ -25,6 +25,7 @@ import net.sf.saxon.s9api.SequenceType; import net.sf.saxon.s9api.XdmAtomicValue; import net.sf.saxon.s9api.XdmValue; +import org.apache.logging.log4j.Logger; import org.bouncycastle.util.Arrays; import org.w3c.dom.Node; @@ -35,6 +36,7 @@ */ public abstract class NodeXslFunction implements ExtensionFunction { + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(NodeXslFunction.class); protected abstract String getFnName(); protected abstract Node getNode(String param); @@ -61,7 +63,16 @@ final public XdmValue call(XdmValue[] xdmValues) throws SaxonApiException { if (Objects.isNull(xdmValues) || Arrays.isNullOrContainsNull(xdmValues)) { return new XdmAtomicValue(""); } - Node node = getNode(xdmValues[0].itemAt(0).getStringValue()); + String val; + try { + val = xdmValues[0].itemAt(0).getStringValue(); + } catch (Exception e) { + // e.g. when no parameter is passed and xdmValues[0] ends with index error + log.warn("Empty value in call of function of NodeXslFunction type"); + val = ""; + } + + Node node = getNode(val); if (Objects.isNull(node)) { try { node = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/ShortestIdFn.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/ShortestIdFn.java new file mode 100644 index 000000000000..022755d68662 --- /dev/null +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/ShortestIdFn.java @@ -0,0 +1,26 @@ +/** + * 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.xoai.services.impl.resources.functions; + +import org.dspace.utils.LangUtil; + +/** + * Serves as proxy for call from XSL engine. Calls LicenseUtil + * @author Marian Berger (marian.berger at dataquest.sk) + */ +public class ShortestIdFn extends StringXSLFunction { + @Override + protected String getFnName() { + return "shortestIdFn"; + } + + @Override + protected String getStringResult(String param) { + return LangUtil.getShortestId(param); + } +} diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/StringXSLFunction.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/StringXSLFunction.java index b472c485abbd..163a9eb49ca1 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/StringXSLFunction.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/functions/StringXSLFunction.java @@ -18,6 +18,7 @@ import net.sf.saxon.s9api.SequenceType; import net.sf.saxon.s9api.XdmAtomicValue; import net.sf.saxon.s9api.XdmValue; +import org.apache.logging.log4j.Logger; import org.bouncycastle.util.Arrays; @@ -28,6 +29,7 @@ */ public abstract class StringXSLFunction implements ExtensionFunction { + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(StringXSLFunction.class); public static final String BASE = "http://custom.crosswalk.functions"; protected String uncertainString(Object val) { @@ -55,7 +57,7 @@ final public SequenceType getResultType() { final public SequenceType[] getArgumentTypes() { return new SequenceType[]{ SequenceType.makeSequenceType( - ItemType.STRING, OccurrenceIndicator.ONE)}; + ItemType.STRING, OccurrenceIndicator.ZERO_OR_MORE)}; } @Override @@ -63,7 +65,17 @@ final public XdmValue call(XdmValue[] xdmValues) throws SaxonApiException { if (Objects.isNull(xdmValues) || Arrays.isNullOrContainsNull(xdmValues)) { return new XdmAtomicValue(""); } - return new XdmAtomicValue(checks(getStringResult(xdmValues[0].itemAt(0).getStringValue()))); + + String val; + try { + val = xdmValues[0].itemAt(0).getStringValue(); + } catch (Exception e) { + // e.g. when no parameter is passed and xdmValues[0] ends with index error + log.warn("Empty value in call of function of StringXslFunction type"); + val = ""; + } + + return new XdmAtomicValue(checks(getStringResult(val))); } private String checks(String got) { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinRefBoxController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinRefBoxController.java index 710a96648152..05600878b97f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinRefBoxController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinRefBoxController.java @@ -10,8 +10,10 @@ import static java.util.Arrays.asList; import static javax.servlet.http.HttpServletResponse.SC_OK; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; @@ -191,7 +193,7 @@ public ResponseEntity getCitationText(@RequestParam(name = "type") String type, Context context = null; OAIPMH oaipmh = null; // ClarinOutputStream write OAI-PMH data into String instead of bytes. - ClarinOutputStream output = new ClarinOutputStream(); + OutputStream output = new UTF8ClarinOutputStream(); try { request.setCharacterEncoding("UTF-8"); context = contextService.getContext(); @@ -402,17 +404,17 @@ private String getXmlTextContent(String xml) throws ParserConfigurationException /** * This ClarinOutputStream write the content into the string instead of bytes. */ -class ClarinOutputStream extends OutputStream { - private StringBuilder string = new StringBuilder(); +class UTF8ClarinOutputStream extends OutputStream { + private ByteArrayOutputStream bao = new ByteArrayOutputStream(); @Override public void write(int b) throws IOException { - this.string.append((char) b ); + bao.write(b); } @Override public String toString() { - return this.string.toString(); + return bao.toString(StandardCharsets.UTF_8); } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinUserMetadataImportController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinUserMetadataImportController.java index 706d538ade74..a728fbb94b4a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinUserMetadataImportController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ClarinUserMetadataImportController.java @@ -168,12 +168,12 @@ public ClarinUserMetadataRest importUserMetadata(HttpServletRequest request) thr //create user metadata and license resource user allowance newClarinUserMetadataList = clarinUserMetadataRestController.processSignedInUser( context, ePerson, clarinUserMetadataRestList, - clarinLicenseResourceMapping, bitstreamUUID, token); + clarinLicenseResourceMapping, token); } else { // The user not is signed in //create user metadata and license resource user allowance newClarinUserMetadataList = clarinUserMetadataRestController.processNonSignedInUser( - context, clarinUserMetadataRestList, clarinLicenseResourceMapping, bitstreamUUID, token); + context, clarinUserMetadataRestList, clarinLicenseResourceMapping, token); } //set eperson_id (user registration) in user_metadata newClarinUserMetadataList.get(0).setEperson(userRegistration); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ItemAddBundleController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ItemAddBundleController.java index 5175dec5e2e3..b3444a739e77 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ItemAddBundleController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ItemAddBundleController.java @@ -11,9 +11,12 @@ import java.io.IOException; import java.sql.SQLException; +import java.util.List; +import java.util.Objects; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.BadRequestException; import com.fasterxml.jackson.databind.ObjectMapper; import org.dspace.app.rest.converter.ConverterService; @@ -26,10 +29,17 @@ import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.Utils; import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; import org.dspace.content.Bundle; import org.dspace.content.Item; +import org.dspace.content.clarin.ClarinLicense; import org.dspace.content.service.ItemService; +import org.dspace.content.service.clarin.ClarinLicenseResourceMappingService; +import org.dspace.content.service.clarin.ClarinLicenseService; +import org.dspace.core.Constants; import org.dspace.core.Context; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.rest.webmvc.ControllerUtils; import org.springframework.data.rest.webmvc.ResourceNotFoundException; @@ -41,6 +51,7 @@ 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; /** @@ -64,6 +75,8 @@ + "/" + BundleRest.PLURAL_NAME) public class ItemAddBundleController { + private static final Logger log = LoggerFactory.getLogger(ItemAddBundleController.class); + @Autowired ConverterService converter; @@ -79,6 +92,12 @@ public class ItemAddBundleController { @Autowired Utils utils; + @Autowired + ClarinLicenseService clarinLicenseService; + + @Autowired + ClarinLicenseResourceMappingService clarinLicenseResourceMappingService; + /** * Method to add a Bundle to an Item with the given UUID in the URL. This will create a Bundle with the * name provided in the request and attach this to the Item that matches the UUID in the URL. @@ -111,4 +130,61 @@ public ResponseEntity> addBundleToItem(@PathVariable UUID return ControllerUtils.toResponseEntity(HttpStatus.CREATED, new HttpHeaders(), bundleResource); } + /** + * Method to update the license for all bitstreams in the bundle of an item with the given UUID in the URL. + * This will remove the old license and attach the new license to all bitstreams in the bundle. + * The license is identified by the licenseID parameter in the request. If the licenseID is not found (-1), the old + * license will be detached, but the new license will not be attached. + * @param uuid + * @param licenseId + * @param request + * @param response + * @return + * @throws SQLException + * @throws AuthorizeException + */ + @RequestMapping(method = RequestMethod.PUT) + @PreAuthorize("hasPermission(#uuid, 'ITEM', 'ADD')") + public ItemRest updateLicenseForBundle(@PathVariable UUID uuid, + @RequestParam("licenseID") Integer licenseId, + HttpServletRequest request, + HttpServletResponse response) + throws SQLException, AuthorizeException { + Context context = ContextUtil.obtainContext(request); + if (Objects.isNull(context)) { + throw new BadRequestException("No context found for current user"); + } + Item item = itemService.find(context, uuid); + + if (item == null) { + throw new ResourceNotFoundException("Could not find item with id " + uuid); + } + + ClarinLicense clarinLicense = clarinLicenseService.find(context, licenseId); + if (Objects.isNull(clarinLicense)) { + log.warn("Cannot find clarin license with id: " + licenseId + ". The old license will be detached, " + + "but the new one will not be attached."); + } + List bundles = item.getBundles(Constants.CONTENT_BUNDLE_NAME); + for (Bundle clarinBundle : bundles) { + List bitstreamList = clarinBundle.getBitstreams(); + for (Bitstream bundleBitstream : bitstreamList) { + // in case bitstream ID exists in license table for some reason .. just remove it + this.clarinLicenseResourceMappingService.detachLicenses(context, bundleBitstream); + if (Objects.nonNull(clarinLicense)) { + // add the license to bitstream + this.clarinLicenseResourceMappingService.attachLicense(context, clarinLicense, bundleBitstream); + } + } + } + clarinLicenseService.clearLicenseMetadataFromItem(context, item); + if (Objects.nonNull(clarinLicense)) { + clarinLicenseService.addLicenseMetadataToItem(context, clarinLicense, item); + } + + itemService.update(context, item); + context.commit(); + + return converter.toRest(item, utils.obtainProjection()); + } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/CanManageLicense.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/CanManageLicense.java new file mode 100644 index 000000000000..a8c4a494ad56 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/CanManageLicense.java @@ -0,0 +1,53 @@ +/** + * 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.authorization.impl; + +import java.sql.SQLException; +import java.util.Objects; +import java.util.UUID; + +import org.dspace.app.rest.authorization.AuthorizationFeature; +import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation; +import org.dspace.app.rest.model.BaseObjectRest; +import org.dspace.app.rest.model.ItemRest; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.Item; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.dspace.discovery.SearchServiceException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@AuthorizationFeatureDocumentation(name = CanManageLicense.NAME, + description = "It can be used to verify if the user can attach/detach a license to an Item") +public class CanManageLicense implements AuthorizationFeature { + + public static final String NAME = "canManageLicense"; + + @Autowired + private ItemService itemService; + @Autowired + private AuthorizeService authorizeService; + + @Override + public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException, SearchServiceException { + Item item = itemService.find(context, UUID.fromString(((ItemRest) object).getUuid())); + if (Objects.nonNull(item)) { + return authorizeService.isAdmin(context, item); + } + return false; + } + + @Override + public String[] getSupportedTypes() { + return new String[]{ + ItemRest.CATEGORY + "." + ItemRest.NAME + }; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/DiscoverConfigurationConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/DiscoverConfigurationConverter.java index 41cf235a878b..2252e394824f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/DiscoverConfigurationConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/DiscoverConfigurationConverter.java @@ -7,10 +7,12 @@ */ package org.dspace.app.rest.converter; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.dspace.app.rest.model.SearchConfigurationRest; import org.dspace.app.rest.projection.Projection; @@ -19,6 +21,8 @@ import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; import org.dspace.discovery.configuration.DiscoverySortConfiguration; import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration; +import org.dspace.services.ConfigurationService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -29,6 +33,9 @@ public class DiscoverConfigurationConverter implements DSpaceConverter { + @Autowired + ConfigurationService configurationService; + @Override public SearchConfigurationRest convert(DiscoveryConfiguration configuration, Projection projection) { SearchConfigurationRest searchConfigurationRest = new SearchConfigurationRest(); @@ -70,6 +77,12 @@ private void addSortOptions(SearchConfigurationRest searchConfigurationRest, if (searchSortConfiguration != null) { for (DiscoverySortFieldConfiguration discoverySearchSortConfiguration : CollectionUtils .emptyIfNull(searchSortConfiguration.getSortFields())) { + List filteredSortOptions = Arrays.asList(ArrayUtils.nullToEmpty(( + configurationService.getArrayProperty("sort.options.filtered", new String[0])))); + if (filteredSortOptions.contains(discoverySearchSortConfiguration.getMetadataField())) { + return; + } + SearchConfigurationRest.SortOption sortOption = new SearchConfigurationRest.SortOption(); if (StringUtils.isBlank(discoverySearchSortConfiguration.getMetadataField())) { sortOption.setName(DiscoverySortConfiguration.SCORE); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java index 433c15363c05..9f280e55a6de 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ItemConverter.java @@ -24,8 +24,10 @@ import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; +import org.dspace.content.service.clarin.ClarinItemService; import org.dspace.core.Context; import org.dspace.discovery.IndexableObject; +import org.dspace.services.model.Request; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; @@ -44,25 +46,23 @@ public class ItemConverter @Autowired private ItemService itemService; + @Autowired + private ClarinItemService clarinItemService; + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemConverter.class); @Override public ItemRest convert(Item obj, Projection projection) { - List approximatedDates = - itemService.getMetadata(obj, "local", "approximateDate", "issued", Item.ANY, false); - if (CollectionUtils.isNotEmpty(approximatedDates) && - StringUtils.isNotBlank(approximatedDates.get(0).getValue())) { - List issuedDates = - itemService.getMetadata(obj, "dc", "date", "issued", Item.ANY, false); - issuedDates.forEach(metadataValue -> metadataValue.setValue(approximatedDates.get(0).getValue())); - - // Remove the date from the `dc.date.issued` because it was added into `local.approximateDate.issued`. - Context context = ContextUtil.obtainContext(requestService.getCurrentRequest().getHttpServletRequest()); - try { - itemService.clearMetadata(context, obj, "dc", "date", "issued", Item.ANY); - } catch (SQLException e) { - log.error("Cannot remove `dc.date.issued` metadata because: " + e.getMessage()); - } + Context context = null; + Request currentRequest = requestService.getCurrentRequest(); + if (currentRequest != null) { + context = ContextUtil.obtainContext(currentRequest.getHttpServletRequest()); + } + try { + clarinItemService.updateItemDatesMetadata(context, obj); + } catch (SQLException e) { + log.error("Error updating item dates metadata", e); + throw new RuntimeException(e); } ItemRest item = super.convert(obj, projection); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinItemImportController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinItemImportController.java index d37b54ab708c..02ce099dfe97 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinItemImportController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinItemImportController.java @@ -53,6 +53,7 @@ import org.dspace.identifier.IdentifierException; import org.dspace.identifier.service.IdentifierService; import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.util.UUIDUtils; import org.dspace.workflow.WorkflowException; import org.dspace.xmlworkflow.service.XmlWorkflowService; @@ -317,11 +318,19 @@ public ItemRest importItem(HttpServletRequest request) throws SQLException, Auth context.setCurrentUser(eperson); context.turnOffAuthorisationSystem(); WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, false); + // created item + Item item = workspaceItem.getItem(); + // if the created item has pre-registered PID and the importing Item has handle which must be imported, the + // pre-registered PID must be unbound from the created Item, otherwise the Item will have two handles. + if (DSpaceServicesFactory.getInstance().getConfigurationService() + .getBooleanProperty("identifiers.submission.register", false) && + StringUtils.isNotEmpty(itemRest.getHandle())) { + handleService.unbindHandle(context, item); + } + context.restoreAuthSystemState(); context.setCurrentUser(currUser); - //created item - Item item = workspaceItem.getItem(); item.setOwningCollection(collection); //the method set withdraw to true and isArchived to false if (itemRest.getWithdrawn()) { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinUserMetadataRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinUserMetadataRestController.java index 44036147c7f4..3c03adb85d04 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinUserMetadataRestController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinUserMetadataRestController.java @@ -32,14 +32,19 @@ import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.model.BitstreamRest; import org.dspace.app.rest.model.ClarinUserMetadataRest; +import org.dspace.app.rest.model.ItemRest; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.clarin.ClarinLicense; import org.dspace.content.clarin.ClarinLicenseResourceMapping; import org.dspace.content.clarin.ClarinLicenseResourceUserAllowance; import org.dspace.content.clarin.ClarinUserMetadata; import org.dspace.content.clarin.ClarinUserRegistration; import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.ItemService; import org.dspace.content.service.clarin.ClarinLicenseResourceMappingService; import org.dspace.content.service.clarin.ClarinLicenseResourceUserAllowanceService; import org.dspace.content.service.clarin.ClarinUserMetadataService; @@ -76,9 +81,105 @@ public class ClarinUserMetadataRestController { ClarinUserRegistrationService clarinUserRegistrationService; @Autowired BitstreamService bitstreamService; + + @Autowired + ItemService itemService; + @Autowired ConfigurationService configurationService; + @RequestMapping(value = "/zip", method = POST, consumes = APPLICATION_JSON) + @PreAuthorize("permitAll()") + public ResponseEntity manageUserMetadataForZIP(@RequestParam("itemUUID") UUID itemUUID, + HttpServletRequest request) + throws SQLException, ParseException, IOException, AuthorizeException, MessagingException { + + // Get context from the request + Context context = obtainContext(request); + // Validate parameters + if (Objects.isNull(context)) { + return null; + } + if (Objects.isNull(itemUUID)) { + return null; + } + + // Get current user from the context to find out if the user is signed in + EPerson currentUser = context.getCurrentUser(); + String downloadToken = this.generateToken(); + + Item item = itemService.find(context, itemUUID); + if (Objects.isNull(item)) { + log.error("Cannot find the item with ID: " + itemUUID); + throw new NotFoundException("Cannot find the item with ID: " + itemUUID); + } + // Load the name because it is used in the email, and it must be loaded before the `sendEmailWithDownloadLink` + // method otherwise it will throw an exception about Lazy loading. + item.getName(); + + boolean shouldEmailToken = false; + ClarinLicense clarinLicense = null; + // Get ClarinUserMetadataRest Array from the request body + ClarinUserMetadataRest[] clarinUserMetadataRestArray = + new ObjectMapper().readValue(request.getInputStream(), ClarinUserMetadataRest[].class); + if (Objects.isNull(clarinUserMetadataRestArray)) { + throw new RuntimeException("The clarinUserMetadataRestArray cannot be null. It could be empty, but" + + " not null"); + } + + // Convert Array to the List + List clarinUserMetadataRestList = Arrays.asList(clarinUserMetadataRestArray); + List bundles = item.getBundles("ORIGINAL"); + for (Bundle original : bundles) { + List bss = original.getBitstreams(); + for (Bitstream bitstream : bss) { + UUID bitstreamUUID = bitstream.getID(); + // Get mapping between clarin license and the bitstream + ClarinLicenseResourceMapping clarinLicenseResourceMapping = + this.getLicenseResourceMapping(context, bitstreamUUID); + if (Objects.isNull(clarinLicenseResourceMapping)) { + throw new NotFoundException("Cannot find the license resource mapping between clarin license" + + " and the bitstream"); + } + if (Objects.isNull(currentUser)) { + // The user is not signed in + this.processNonSignedInUser(context, clarinUserMetadataRestList, clarinLicenseResourceMapping, + downloadToken); + + } else { + // The user is signed in + this.processSignedInUser(context, currentUser, clarinUserMetadataRestList, + clarinLicenseResourceMapping, downloadToken); + } + + // Check (only once) if the Clarin License contains the required information to SEND_TOKEN, which means + // the item must be downloaded after the user confirms the download with the token sent by email. + if (Objects.isNull(clarinLicense)) { + clarinLicense = this.getClarinLicense(clarinLicenseResourceMapping); + shouldEmailToken = this.shouldEmailToken(clarinLicenseResourceMapping); + } + } + } + + context.commit(); + if (shouldEmailToken) { + // If yes - send token to e-mail + try { + String email = getEmailFromUserMetadata(clarinUserMetadataRestList); + this.sendEmailWithDownloadLink(context, item, clarinLicense, + email, downloadToken); + } catch (MessagingException e) { + log.error("Cannot send the download email because: " + e.getMessage()); + throw new RuntimeException("Cannot send the download email because: " + e.getMessage()); + } + + return ResponseEntity.ok().body(CHECK_EMAIL_RESPONSE_CONTENT); + } else { + // If no - send token in the response to download the bitstream immediately + return ResponseEntity.ok().body(downloadToken); + } + } + @RequestMapping(method = POST, consumes = APPLICATION_JSON) @PreAuthorize("permitAll()") public ResponseEntity manageUserMetadata(@RequestParam("bitstreamUUID") UUID bitstreamUUID, @@ -91,13 +192,24 @@ public ResponseEntity manageUserMetadata(@RequestParam("bitstreamUUID") UUID bit if (Objects.isNull(context)) { return null; } - if (Objects.isNull(bitstreamUUID)) { + + + Bitstream bitstream = bitstreamService.find(context, bitstreamUUID); + if (Objects.isNull(bitstream)) { + log.error("Cannot find the bitstream with ID: " + bitstreamUUID); return null; } + // Load the name because it is used in the email, and it must be loaded before the `sendEmailWithDownloadLink` + // method otherwise it will throw an exception about Lazy loading. + bitstream.getName(); + + // Get current user from the context to find out if the user is signed in + EPerson currentUser = context.getCurrentUser(); + String downloadToken = this.generateToken(); // Get mapping between clarin license and the bitstream ClarinLicenseResourceMapping clarinLicenseResourceMapping = - this.getLicenseResourceMapping(context, bitstreamUUID); + this.getLicenseResourceMapping(context, bitstream.getID()); if (Objects.isNull(clarinLicenseResourceMapping)) { throw new NotFoundException("Cannot find the license resource mapping between clarin license" + " and the bitstream"); @@ -113,28 +225,26 @@ public ResponseEntity manageUserMetadata(@RequestParam("bitstreamUUID") UUID bit // Convert Array to the List List clarinUserMetadataRestList = Arrays.asList(clarinUserMetadataRestArray); - - // Get current user from the context to find out if the user is signed in - EPerson currentUser = context.getCurrentUser(); - String downloadToken = this.generateToken(); if (Objects.isNull(currentUser)) { // The user is not signed in this.processNonSignedInUser(context, clarinUserMetadataRestList, clarinLicenseResourceMapping, - bitstreamUUID, downloadToken); + downloadToken); } else { // The user is signed in this.processSignedInUser(context, currentUser, clarinUserMetadataRestList, clarinLicenseResourceMapping, - bitstreamUUID, downloadToken); + downloadToken); } - boolean shouldEmailToken = this.shouldEmailToken(context, bitstreamUUID, clarinLicenseResourceMapping); + boolean shouldEmailToken = this.shouldEmailToken(clarinLicenseResourceMapping); context.commit(); if (shouldEmailToken) { // If yes - send token to e-mail try { - this.sendEmailWithDownloadLink(context, bitstreamUUID, clarinLicenseResourceMapping, - clarinUserMetadataRestList, downloadToken); + String email = getEmailFromUserMetadata(clarinUserMetadataRestList); + ClarinLicense clarinLicense = this.getClarinLicense(clarinLicenseResourceMapping); + this.sendEmailWithDownloadLink(context, bitstream, clarinLicense, + email, downloadToken); } catch (MessagingException e) { log.error("Cannot send the download email because: " + e.getMessage()); throw new RuntimeException("Cannot send the download email because: " + e.getMessage()); @@ -147,30 +257,19 @@ public ResponseEntity manageUserMetadata(@RequestParam("bitstreamUUID") UUID bit } } - private void sendEmailWithDownloadLink(Context context, UUID bitstreamUUID, - ClarinLicenseResourceMapping clarinLicenseResourceMapping, - List clarinUserMetadataRestList, + private void sendEmailWithDownloadLink(Context context, DSpaceObject dso, + ClarinLicense clarinLicense, + String email, String downloadToken) throws IOException, SQLException, MessagingException { - // Get the recipient email - String email = getEmailFromUserMetadata(clarinUserMetadataRestList); if (StringUtils.isBlank(email)) { log.error("Cannot send email with download link because the email is empty."); throw new BadRequestException("Cannot send email with download link because the email is empty."); } - // Get the file name - Bitstream bitstream = bitstreamService.find(context, bitstreamUUID); - if (Objects.isNull(bitstream)) { - log.error("Cannot find bitstream with ID: " + bitstreamUUID); - throw new BadRequestException("Cannot find bitstream with ID: " + bitstreamUUID); - } - - // Get Clarin License - ClarinLicense clarinLicense = getClarinLicense(context, bitstreamUUID, clarinLicenseResourceMapping); - if (Objects.isNull(clarinLicense)) { - log.error("Cannot find the clarin license for the bitstream with ID: " + bitstreamUUID); - throw new BadRequestException("Cannot find the clarin license for the bitstream with ID: " + bitstreamUUID); + if (Objects.isNull(dso)) { + log.error("Cannot send email with download link because the DSpaceObject is null."); + throw new BadRequestException("Cannot send email with download link because the DSpaceObject is null."); } // Fetch DSpace main cfg info and send it in the email @@ -185,13 +284,15 @@ private void sendEmailWithDownloadLink(Context context, UUID bitstreamUUID, throw new RuntimeException("Cannot load the `dspace.ui.url` property from the cfg."); } // Compose download link - String downloadLink = uiUrl + "/" + BitstreamRest.PLURAL_NAME + "/" + bitstream.getID() + "/download?dtoken=" + - downloadToken; + // Redirect to `/api/bitstreams/{bitstreamId}/download?dtoken={downloadToken}` or + // `/api/items/{itemId}/download?dtoken={downloadToken}` + String downloadLink = uiUrl + "/" + (dso instanceof Item ? ItemRest.PLURAL_NAME : BitstreamRest.PLURAL_NAME) + + "/" + dso.getID() + "/download?dtoken=" + downloadToken; try { Locale locale = context.getCurrentLocale(); Email bean = Email.getEmail(I18nUtil.getEmailFilename(locale, "clarin_download_link")); - bean.addArgument(bitstream.getName()); + bean.addArgument(dso.getName()); bean.addArgument(downloadLink); bean.addArgument(clarinLicense.getDefinition()); bean.addArgument(helpDeskEmail); @@ -220,7 +321,7 @@ private String getEmailFromUserMetadata(List clarinUserM public List processSignedInUser(Context context, EPerson currentUser, List clarinUserMetadataRestList, ClarinLicenseResourceMapping clarinLicenseResourceMapping, - UUID bitstreamUUID, String downloadToken) + String downloadToken) throws SQLException { // If exists userMetadata records in the table update them or create them in other case // Get UserRegistration which has the UserMetadata list @@ -289,7 +390,6 @@ private ClarinLicenseResourceUserAllowance createClrua(Context context, public List processNonSignedInUser(Context context, List clarinUserMetadataRestList, ClarinLicenseResourceMapping clarinLicenseResourceMapping, - UUID bitstreamUUID, String downloadToken) throws SQLException { // Create ClarinUserMetadataRecord from the ClarinUserMetadataRest List. // Add created ClarinUserMetadata to the List. @@ -343,9 +443,7 @@ public ClarinLicenseResourceMapping getLicenseResourceMapping(Context context, U return clarinLicenseResourceMapping; } - private ClarinLicense getClarinLicense(Context context, UUID bitstreamUUID, - ClarinLicenseResourceMapping clarinLicenseResourceMapping) - throws SQLException { + private ClarinLicense getClarinLicense(ClarinLicenseResourceMapping clarinLicenseResourceMapping) { if (Objects.isNull(clarinLicenseResourceMapping)) { throw new NullPointerException("The clarinLicenseResourceMapping object is null."); } @@ -359,9 +457,8 @@ private ClarinLicense getClarinLicense(Context context, UUID bitstreamUUID, return clarinLicense; } - private boolean shouldEmailToken(Context context, UUID bitstreamUUID, - ClarinLicenseResourceMapping clarinLicenseResourceMapping) throws SQLException { - ClarinLicense clarinLicense = this.getClarinLicense(context, bitstreamUUID, clarinLicenseResourceMapping); + private boolean shouldEmailToken(ClarinLicenseResourceMapping clarinLicenseResourceMapping) { + ClarinLicense clarinLicense = this.getClarinLicense(clarinLicenseResourceMapping); if (Objects.isNull(clarinLicense)) { throw new NullPointerException("The ClarinLicense is null."); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/IdentifierRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/IdentifierRestRepository.java index 1be569d18e5d..60b6749eef22 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/IdentifierRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/IdentifierRestRepository.java @@ -281,6 +281,10 @@ public void getDSObyIdentifier(HttpServletRequest request, if (dso != null) { // Convert and respond with a redirect to the object itself DSpaceObjectRest dsor = converter.toRest(dso, utils.obtainProjection()); + if (dsor == null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication is required"); + return; + } URI link = linkTo(dsor.getController(), dsor.getCategory(), English.plural(dsor.getType())) .slash(dsor.getId()).toUri(); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/MetadataBitstreamRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/MetadataBitstreamRestRepository.java index d2daabe9a4da..4778cec279e3 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/MetadataBitstreamRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/MetadataBitstreamRestRepository.java @@ -20,8 +20,11 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.xml.parsers.ParserConfigurationException; @@ -60,6 +63,7 @@ import org.dspace.util.FileInfo; import org.dspace.util.FileTreeViewGenerator; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -72,7 +76,6 @@ @Component(MetadataBitstreamWrapperRest.CATEGORY + "." + MetadataBitstreamWrapperRest.NAME) public class MetadataBitstreamRestRepository extends DSpaceRestRepository { private static Logger log = org.apache.logging.log4j.LogManager.getLogger(MetadataBitstreamRestRepository.class); - private final static int MAX_FILE_PREVIEW_COUNT = 1000; @Autowired HandleService handleService; @@ -102,6 +105,10 @@ public class MetadataBitstreamRestRepository extends DSpaceRestRepository findByHandle(@Parameter(value = "handle", required = true) String handle, @Parameter(value = "fileGrpType") String fileGrpType, @@ -345,29 +352,28 @@ public String extractFile(InputStream inputStream, String fileType) { } } + // Is a folder regex + String folderRegex = "/|\\d+"; + Pattern pattern = Pattern.compile(folderRegex); + StringBuilder sb = new StringBuilder(); sb.append(("")); - List allFiles = filePaths; + Iterator iterator = filePaths.iterator(); int fileCounter = 0; - for (String filePath : allFiles) { - if (!filePath.isEmpty() && filePath.length() > 3) { - if (filePath.contains(".")) { - fileCounter++; - } - sb.append(""); - sb.append(filePath); - sb.append(""); - - if (fileCounter > MAX_FILE_PREVIEW_COUNT) { - sb.append(""); - sb.append("/|0"); - sb.append(""); - sb.append(""); - sb.append("...too many files...|0"); - sb.append(""); - break; - } + while ((iterator.hasNext() && fileCounter < maxPreviewCount)) { + String filePath = iterator.next(); + + // Check if the file is a folder + Matcher matcher = pattern.matcher(filePath); + if (!matcher.matches()) { + // It is a file + fileCounter++; } + sb.append("").append(filePath).append(""); + } + + if (fileCounter > maxPreviewCount) { + sb.append("...too many files...|0"); } sb.append(("")); return sb.toString(); 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 3add833152e9..d3fb87b0e501 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 @@ -466,9 +466,12 @@ private void uploadFileFromURL(Context context, HttpServletRequest request, Inte wis.update(context, witem); + // remove metadata from the item, because that file was uploading after every save + itemService.clearMetadata(context, witem.getItem(), "local", "bitstream", "redirectToURL", Item.ANY); + // delete file - String shouldDeleteFile = configurationService.getProperty("delete.big.file.after.upload"); - if (StringUtils.isNotBlank(shouldDeleteFile) && StringUtils.equals("true", shouldDeleteFile)) { + boolean shouldDeleteFile = configurationService.getBooleanProperty("delete.big.file.after.upload", false); + if (shouldDeleteFile) { FileUtils.forceDelete(file); } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/DescribeStep.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/DescribeStep.java index 9765529eca08..a54473e66d1e 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/DescribeStep.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/DescribeStep.java @@ -241,8 +241,6 @@ private Operation getOperationWithChangedMetadataField(Operation oldOp, String m String[] opPathArray = oldOpPathArray.clone(); // metadata field could has more metadata values - // TO DO problem je v tom, ze sa volala replace metoda pri add - // potrebujem zvlast odchytit ADD metodu a REPLACE boolean isNotFirstValue = false; boolean removeMetadata = false; @@ -262,6 +260,10 @@ private Operation getOperationWithChangedMetadataField(Operation oldOp, String m // Operation has a value wrapped in the JsonValueEvaluator JsonValueEvaluator jsonValEvaluator = (JsonValueEvaluator) oldOp.getValue(); + if (jsonValEvaluator == null) { + log.warn("The complex input field is not processed, because the operation doesn't have a value."); + return null; + } Iterator jsonNodes = jsonValEvaluator.getValueNode().elements(); if (isNotFirstValue) { @@ -277,10 +279,6 @@ private Operation getOperationWithChangedMetadataField(Operation oldOp, String m } } - if (ObjectUtils.isEmpty(jsonNodeValue) || StringUtils.isBlank(jsonNodeValue.asText())) { - throw new UnprocessableEntityException("Cannot load JsonNode value from the operation: " + - oldOp.getPath()); - } // get the value from the old operation as a string oldOpValue = jsonNodeValue.asText(); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/validation/CMDIFileBundleMaintainer.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/validation/CMDIFileBundleMaintainer.java index 36640ed631d7..071e93891a7a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/validation/CMDIFileBundleMaintainer.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/validation/CMDIFileBundleMaintainer.java @@ -32,7 +32,7 @@ */ public class CMDIFileBundleMaintainer { - private static final String hasCMDYesOptionValue = "yes"; + private static final String hasCMDYesOptionValue = "true"; private static BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); private static ItemService itemService = ContentServiceFactory.getInstance().getItemService(); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/validation/MetadataValidation.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/validation/MetadataValidation.java index 07eba4d73237..1ff9639906ac 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/validation/MetadataValidation.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/step/validation/MetadataValidation.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.Map; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; @@ -142,8 +143,9 @@ public List validate(SubmissionService submissionService, InProgressS } } validateMetadataValues(mdv, input, config, isAuthorityControlled, fieldKey, errors); - if ((input.isRequired() && mdv.size() == 0) && input.isVisible(DCInput.SUBMISSION_SCOPE) - && !valuesRemoved) { + if (((input.isRequired() && mdv.size() == 0) && input.isVisible(DCInput.SUBMISSION_SCOPE) + && !valuesRemoved) + || !isValidComplexDefinitionMetadata(input, mdv)) { // Is the input required for *this* type? In other words, are we looking at a required // input that is also allowed for this document type if (input.isAllowedFor(documentTypeValue)) { @@ -169,26 +171,76 @@ public List validate(SubmissionService submissionService, InProgressS return errors; } + /** + * Check if the metadata values for a complex definition input are valid. + * Valid if: + * - the complex input field is required and all required nested input fields are filled in. + * - the complex input field is not required, if there is a valued in the nested input field - all required nested + * input fields must be filled in. + * - the complex input field is not required, and none of the nested input fields are required. + */ private boolean isValidComplexDefinitionMetadata(DCInput input, List mdv) { - if (input.getInputType().equals("complex")) { - int complexDefinitionIndex = 0; - Map> complexDefinitionInputs = input.getComplexDefinition().getInputs(); - for (String complexDefinitionInputName : complexDefinitionInputs.keySet()) { - Map complexDefinitionInputValues = - complexDefinitionInputs.get(complexDefinitionInputName); - - List filledInputValues = null; - String isRequired = complexDefinitionInputValues.get("required"); - if (StringUtils.equals(BooleanUtils.toStringTrueFalse(true), isRequired)) { - filledInputValues = new ArrayList<>(Arrays.asList( - mdv.get(0).getValue().split(DCInput.ComplexDefinitions.getSeparator(),-1))); - - if (StringUtils.isBlank(filledInputValues.get(complexDefinitionIndex))) { - return false; - } - } - complexDefinitionIndex++; + // The input is not a complex definition - do not validate it + if (!input.getInputType().equals("complex")) { + return true; + } + + // Get the complex definition nested inputs + Map> complexDefinitionInputs = input.getComplexDefinition().getInputs(); + + // Check valid state of the complex definition input when it is required + if (input.isRequired()) { + // There are no values in the complex input field + if (CollectionUtils.isEmpty(mdv)) { + return false; } + } else { + // The complex input field is not required + if (CollectionUtils.isEmpty(mdv)) { + // There are no values in the complex input field + return true; + } + } + return checkAllRequiredInputFieldsAreFilledIn(complexDefinitionInputs, mdv); + } + + /** + * Check if all required nested input fields are filled in. + */ + private boolean checkAllRequiredInputFieldsAreFilledIn(Map> complexDefinitionInputs, + List mdv) { + // If any of the nested input fields are filled in - all required nested input fields must be filled in + int complexDefinitionIndex = -1; + // Go through all nested input fields + for (String complexDefinitionInputName : complexDefinitionInputs.keySet()) { + complexDefinitionIndex++; + + // Get the definition of the nested input field + Map complexDefinitionInputValues = + complexDefinitionInputs.get(complexDefinitionInputName); + // Check if the nested input field is required - if not do not check if it is filled in + if (!StringUtils.equals(BooleanUtils.toStringTrueFalse(true), + complexDefinitionInputValues.get("required"))) { + continue; + } + + // Load filled in values of the nested input field + List filledInputValues = new ArrayList<>(Arrays.asList( + mdv.get(0).getValue().split(DCInput.ComplexDefinitions.getSeparator(),-1))); + + // Check if the required nested input field is filled in. It is valid if there is a value in the nested + // input. + if (!StringUtils.isBlank(filledInputValues.get(complexDefinitionIndex))) { + continue; + } + + // EU identifier must have `openaire_id` value otherwise the `openaire_id` could be empty. + if (StringUtils.equals("openaire_id", complexDefinitionInputName) && + !StringUtils.equals("euFunds", filledInputValues.get(0))) { + continue; + } + return false; + } return true; } diff --git a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/test-discovery.xml b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/test-discovery.xml index 4a91ef051e88..68726b343086 100644 --- a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/test-discovery.xml +++ b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/test-discovery.xml @@ -34,6 +34,7 @@ + @@ -144,6 +145,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (search.resourcetype:Item) OR search.resourcetype:Collection OR search.resourcetype:Community + -withdrawn:true AND -discoverable:false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + dc.title + dc.contributor.author + dc.creator + dc.contributor.other + dc.subject + + + + + + + + + + + + + + @@ -1114,5 +1275,18 @@ + + + + + dc.subject.* + + + + + + + + diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoveryRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoveryRestControllerIT.java index 460373091d27..d8aca96b37b3 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoveryRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinDiscoveryRestControllerIT.java @@ -966,6 +966,9 @@ public void discoverFacetsDateTestWithSearchFilter() throws Exception { @Test public void discoverSearchTest() throws Exception { + // Hide the sorting option for dc.date.accessioned, but ensure it is still configured + // for loading recent submissions on the browsing page. + // This sort filtering is configured by `sort.options.filtered` property //When calling this root endpoint getClient().perform(get("/api/discover/search")) @@ -998,7 +1001,9 @@ public void discoverSearchTest() throws Exception { SearchFilterMatcher.clarinLicenseRightsFilter(), SearchFilterMatcher.clarinItemsLanguageFilter(), SearchFilterMatcher.clarinItemsCommunityFilter(), - SearchFilterMatcher.clarinItemsTypeFilter() + SearchFilterMatcher.clarinItemsTypeFilter(), + SearchFilterMatcher.clarinSubjectFirstValueFilter(), + SearchFilterMatcher.clarinDataProviderFacet() ))) //These sortOptions need to be present as it's the default in the configuration .andExpect(jsonPath("$.sortOptions", contains( @@ -1023,7 +1028,7 @@ public void checkSortOrderInPersonOrOrgunitConfigurationTest() throws Exception .andExpect(jsonPath("$.type", is("discover"))) .andExpect(jsonPath("$._links.objects.href", containsString("api/discover/search/objects"))) .andExpect(jsonPath("$._links.self.href", containsString("api/discover/search"))) - .andExpect(jsonPath("$.sortOptions", contains( + .andExpect(jsonPath("$.sortOptions", containsInAnyOrder( SortOptionMatcher.sortOptionMatcher("dspace.entity.type", DiscoverySortFieldConfiguration.SORT_ORDER.desc.name()), SortOptionMatcher.sortOptionMatcher("organization.legalName", @@ -1033,14 +1038,6 @@ public void checkSortOrderInPersonOrOrgunitConfigurationTest() throws Exception SortOptionMatcher.sortOptionMatcher("organisation.address.addressLocality", DiscoverySortFieldConfiguration.SORT_ORDER.asc.name()), SortOptionMatcher.sortOptionMatcher("organisation.foundingDate", - DiscoverySortFieldConfiguration.SORT_ORDER.desc.name()), - SortOptionMatcher.sortOptionMatcher("dc.date.accessioned", - DiscoverySortFieldConfiguration.SORT_ORDER.desc.name()), - SortOptionMatcher.sortOptionMatcher("person.familyName", - DiscoverySortFieldConfiguration.SORT_ORDER.asc.name()), - SortOptionMatcher.sortOptionMatcher("person.givenName", - DiscoverySortFieldConfiguration.SORT_ORDER.asc.name()), - SortOptionMatcher.sortOptionMatcher("person.birthDate", DiscoverySortFieldConfiguration.SORT_ORDER.desc.name()) ))); } @@ -5952,4 +5949,112 @@ public void discoverFacetsTestWithDsoTypeTest() throws Exception { .andExpect(jsonPath("$._embedded.values").value(Matchers.hasSize(1))); } + + @Test + public void showFacetValuesWithSplitterInSearchPage() throws Exception { + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + + ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withSubject("People") + .build(); + + ItemBuilder.createItem(context, col1) + .withTitle("Public item 2") + .withIssueDate("2020-02-13") + .withAuthor("Doe, Jane") + .withSubject("People::Jane") + .build(); + + ItemBuilder.createItem(context, col1) + .withTitle("Public item 2") + .withIssueDate("2020-02-13") + .withAuthor("Doe, Jane") + .withSubject("People::Jane") + .build(); + + context.restoreAuthSystemState(); + + getClient().perform(get("/api/discover/facets/subject")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.type", is("discover"))) + .andExpect(jsonPath("$.name", is("subject"))) + .andExpect(jsonPath("$.facetType", is("hierarchical"))) + .andExpect(jsonPath("$.scope", is(emptyOrNullString()))) + .andExpect(jsonPath("$._links.self.href", + containsString("api/discover/facets/subject"))) + .andExpect(jsonPath("$._embedded.values[0].label", is("People"))) + .andExpect(jsonPath("$._embedded.values[0].count", is(3))) + .andExpect(jsonPath("$._embedded.values[1].label", is("People::Jane"))) + .andExpect(jsonPath("$._embedded.values[1].count", is(2))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("_embedded.values[2].label"))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("_embedded.values[2].count"))) + .andExpect(jsonPath("$._embedded.values").value(Matchers.hasSize(2))); + } + + @Test + public void doNotShowFacetValuesWithSplitterInHomePage() throws Exception { + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + + ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withSubject("People") + .build(); + + ItemBuilder.createItem(context, col1) + .withTitle("Public item 2") + .withIssueDate("2020-02-13") + .withAuthor("Doe, Jane") + .withSubject("People::Jane") + .build(); + + ItemBuilder.createItem(context, col1) + .withTitle("Public item 2") + .withIssueDate("2020-02-13") + .withAuthor("Doe, Jane") + .withSubject("People::Jane") + .build(); + + ItemBuilder.createItem(context, col1) + .withTitle("Public item 2") + .withIssueDate("2020-02-13") + .withAuthor("Doe, Jane") + .withSubject("Another subject") + .build(); + + context.restoreAuthSystemState(); + + getClient().perform(get("/api/discover/facets/subjectFirstValue") + .param("configuration", "homepage")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.type", is("discover"))) + .andExpect(jsonPath("$.name", is("subjectFirstValue"))) + .andExpect(jsonPath("$.facetType", is("hierarchical"))) + .andExpect(jsonPath("$.scope", is(emptyOrNullString()))) + .andExpect(jsonPath("$._links.self.href", + containsString("api/discover/facets/subjectFirstValue"))) + .andExpect(jsonPath("$._embedded.values[0].label", is("People"))) + .andExpect(jsonPath("$._embedded.values[0].count", is(3))) + .andExpect(jsonPath("$._embedded.values[1].label", is("Another subject"))) + .andExpect(jsonPath("$._embedded.values[1].count", is(1))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("_embedded.values[2].label"))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("_embedded.values[2].count"))) + .andExpect(jsonPath("$._embedded.values").value(Matchers.hasSize(2))); + } } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinItemImportControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinItemImportControllerIT.java index b561433b48c5..d11ddaa5a260 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinItemImportControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinItemImportControllerIT.java @@ -41,6 +41,8 @@ import org.dspace.content.service.ItemService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.eperson.EPerson; +import org.dspace.handle.Handle; +import org.dspace.handle.service.HandleService; import org.dspace.services.ConfigurationService; import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.WorkflowItemService; @@ -63,6 +65,8 @@ public class ClarinItemImportControllerIT extends AbstractControllerIntegrationT private ItemService itemService; @Autowired private ConfigurationService configurationService; + @Autowired + private HandleService handleService; private Collection col; private EPerson submitter; @@ -227,15 +231,19 @@ public void importWithdrawnItemTest() throws Exception { @Test public void importArchivedItemTest() throws Exception { + boolean preRegisterPID = configurationService.getBooleanProperty("identifiers.submission.register", false); + // enable submission's PID to be pre-registered + configurationService.setProperty("identifiers.submission.register", true); String PROVENANCE_VALUE = "first provenance metadata value"; String DATE_VALUE = "2014-07-30T21:26:36Z"; - String IDENTIFIER_VALUE = "some handle url"; + String IDENTIFIER_VALUE = configurationService.getProperty("handle.canonical.prefix") + "/123456789/99985"; context.turnOffAuthorisationSystem(); ObjectNode node = jsonNodeFactory.objectNode(); node.set("withdrawn", jsonNodeFactory.textNode("false")); node.set("inArchive", jsonNodeFactory.textNode("true")); node.set("discoverable", jsonNodeFactory.textNode("false")); + node.set("handle", jsonNodeFactory.textNode(IDENTIFIER_VALUE)); // Metadata which should be kept after installing the new Item. ObjectNode metadataNode = jsonNodeFactory.objectNode(); @@ -301,6 +309,10 @@ public void importArchivedItemTest() throws Exception { assertEquals(item.getSubmitter().getID(), submitter.getID()); assertEquals(item.getOwningCollection().getID(), col.getID()); + // When the Item has pre-registered PID - it could have two handles + List createdHandles = item.getHandles(); + assertEquals(createdHandles.size(), 1); + // check `dc.description.provenance` - there should be just one value List provenanceValues = itemService.getMetadata(item, "dc", "description", "provenance", "en_US"); @@ -329,6 +341,7 @@ public void importArchivedItemTest() throws Exception { context.turnOffAuthorisationSystem(); ItemBuilder.deleteItem(uuid); context.restoreAuthSystemState(); + configurationService.setProperty("identifiers.submission.register", preRegisterPID); } // Fix of this issue: https://github.com/dataquest-dev/DSpace/issues/409 diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryVersioningIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryVersioningIT.java index 083b27d0e547..53e8dd77e3c3 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryVersioningIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryVersioningIT.java @@ -68,6 +68,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; @@ -290,6 +291,8 @@ protected Collection createCollection(String name, String entityType) { return collection; } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_default_expectLatestVersionsOnly() throws Exception { final String configuration = null; @@ -367,6 +370,8 @@ public void test_discoveryXml_defaultRelationships_allVersions() throws Exceptio )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_site_expectLatestVersionsOnly() throws Exception { final String configuration = "site"; @@ -405,6 +410,8 @@ public void test_discoveryXml_site_expectLatestVersionsOnly() throws Exception { )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_workspace_expectLatestVersionsOnly() throws Exception { final String configuration = "workspace"; @@ -444,9 +451,9 @@ public void test_discoveryXml_workspace_expectLatestVersionsOnly() throws Except } // NOTE: no test for discovery.xml configuration "workflow", because it by definition excludes items - // NOTE: no test for discovery.xml configuration "workflowAdmin", because it by definition excludes items - + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_undiscoverable_expectLatestVersionsOnly() throws Exception { final String configuration = "undiscoverable"; @@ -488,6 +495,8 @@ public void test_discoveryXml_undiscoverable_expectLatestVersionsOnly() throws E )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_administrativeView_expectLatestVersionsOnly() throws Exception { final String configuration = "administrativeView"; @@ -522,6 +531,8 @@ public void test_discoveryXml_administrativeView_expectLatestVersionsOnly() thro )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_publication_expectLatestVersionsOnly() throws Exception { final String configuration = "publication"; @@ -593,6 +604,8 @@ public void test_discoveryXml_publicationRelationships_allVersions() throws Exce )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_person_expectLatestVersionsOnly() throws Exception { final String configuration = "person"; @@ -664,6 +677,8 @@ public void test_discoveryXml_personRelationships_allVersions() throws Exception )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_orgunit_expectLatestVersionsOnly() throws Exception { final String configuration = "orgunit"; @@ -735,6 +750,8 @@ public void test_discoveryXml_orgunitRelationships_allVersions() throws Exceptio )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_journalissue_expectLatestVersionsOnly() throws Exception { final String configuration = "journalissue"; @@ -806,6 +823,8 @@ public void test_discoveryXml_journalissueRelationships_allVersions() throws Exc )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_journalvolume_expectLatestVersionsOnly() throws Exception { final String configuration = "journalvolume"; @@ -878,6 +897,8 @@ public void test_discoveryXml_journalvolumeRelationships_allVersions() throws Ex )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_journal_expectLatestVersionsOnly() throws Exception { final String configuration = "journal"; @@ -950,6 +971,8 @@ public void test_discoveryXml_journalRelationships_allVersions() throws Exceptio )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_project_expectLatestVersionsOnly() throws Exception { final String configuration = "project"; @@ -1021,6 +1044,8 @@ public void test_discoveryXml_projectRelationships_allVersions() throws Exceptio )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_personOrOrgunit_expectLatestVersionsOnly() throws Exception { final String configuration = "personOrOrgunit"; @@ -1056,6 +1081,8 @@ public void test_discoveryXml_personOrOrgunit_expectLatestVersionsOnly() throws )); } + // CLARIN - All items are indexed by all versions + @Ignore @Test public void test_discoveryXml_openAIREFundingAgency_expectLatestVersionsOnly() throws Exception { final String configuration = "openAIREFundingAgency"; diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java index 249daf994c92..8f139a03f5d2 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java @@ -4698,36 +4698,6 @@ public void findAccessStatusForItemTest() throws Exception { .andExpect(jsonPath("$.status", notNullValue())); } - @Test - public void findItemWithUnknownIssuedDate() throws Exception { - context.turnOffAuthorisationSystem(); - - //** GIVEN ** - //1. A community-collection structure with one parent community and one collection - parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); - Collection col = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection").build(); - - //2. Three public items that are readable by Anonymous with different subjects - Item publicItem = ItemBuilder.createItem(context, col) - .withTitle("Public item") - .withIssueDate("2021-04-27") - .withMetadata("local", "approximateDate", "issued", "unknown") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .withSubject("ExtraEntry") - .build(); - - context.restoreAuthSystemState(); - Matcher publicItemMatcher = ItemMatcher.matchItemWithTitleAndApproximateDateIssued(publicItem, - "Public item", "unknown"); - - getClient().perform(get("/api/core/items/" + publicItem.getID())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$", HalMatcher.matchNoEmbeds())) - .andExpect(jsonPath("$", publicItemMatcher)); - } - @Test public void submitterShouldSeeLocalNoteMetadata() throws Exception { // Admin - should see `local.submission.note` and `dc.description.provenance` @@ -4837,4 +4807,68 @@ public void searchByHandle() throws Exception { ))); } + /** + * If the local.approximateDate.issued has a value like 'cca 1938 - 1945', then dc.date.issued = 0000. + */ + @Test + public void copyApproximateDateIntoDateIssued_whenApproximateDateHasMultipleValues() throws Exception { + context.turnOffAuthorisationSystem(); + //** GIVEN ** + 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(); + + Item publicItem = ItemBuilder.createItem(context, col1) + .withTitle("Item with dates") + .withIssueDate("2017-10-17") + .withMetadata("local", "approximateDate", "issued", "cca 1938 - 1945") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + getClient(adminToken).perform(get("/api/core/items/" + publicItem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", HalMatcher.matchNoEmbeds())) + .andExpect(jsonPath("$.metadata", Matchers.allOf( + matchMetadata("dc.date.issued", "0000")))); + } + + /** + * If the local.approximateDate.issued has a value like '1938, 1945, 2022', then dc.date.issued = 2022. + */ + @Test + public void copyApproximateDateIntoDateIssued_whenApproximateDateHasRangeOfValues() throws Exception { + context.turnOffAuthorisationSystem(); + //** GIVEN ** + 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(); + + Item publicItem = ItemBuilder.createItem(context, col1) + .withTitle("Item with dates") + .withIssueDate("2017-10-17") + .withMetadata("local", "approximateDate", "issued", "1938, 1945, 2022") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + getClient(adminToken).perform(get("/api/core/items/" + publicItem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", HalMatcher.matchNoEmbeds())) + .andExpect(jsonPath("$.metadata", Matchers.allOf( + matchMetadata("dc.date.issued", "2022")))); + } + } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java index 2a07dc479807..f86a451256e0 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java @@ -88,6 +88,8 @@ public class StatisticsRestRepositoryIT extends AbstractControllerIntegrationTes private Item itemVisited; private Bitstream bitstreamNotVisited; private Bitstream bitstreamVisited; + private Bitstream bitstream1; + private Bitstream bitstream2; private String loggedInToken; private String adminToken; @@ -123,6 +125,17 @@ public void setUp() throws Exception { .createBitstream(context, itemNotVisitedWithBitstreams, toInputStream("test", UTF_8)) .withName("BitstreamVisitedName").build(); + // Create bitstreams for the test `usageReportsSearch_ItemVisited_FilesVisited` before the `visitedItem` + // is detached, otherwise the error `detached entity passed to persist: org.dspace.content.DSpaceObject` occurs. + bitstream1 = BitstreamBuilder + .createBitstream(context, itemVisited, toInputStream("test", UTF_8)) + .withName("bitstream1") + .build(); + bitstream2 = BitstreamBuilder + .createBitstream(context, itemVisited, toInputStream("test", UTF_8)) + .withName("bitstream2") + .build(); + loggedInToken = getAuthToken(eperson.getEmail(), password); adminToken = getAuthToken(admin.getEmail(), password); @@ -1388,15 +1401,6 @@ public void usageReportsSearch_Item_Visited_FileNotVisited() throws Exception { @Test public void usageReportsSearch_ItemVisited_FilesVisited() throws Exception { - context.turnOffAuthorisationSystem(); - Bitstream bitstream1 = - BitstreamBuilder.createBitstream(context, itemVisited, toInputStream("test", UTF_8)).withName("bitstream1") - .build(); - Bitstream bitstream2 = - BitstreamBuilder.createBitstream(context, itemVisited, toInputStream("test", UTF_8)).withName("bitstream2") - .build(); - context.restoreAuthSystemState(); - // ** WHEN ** // We visit an item ViewEventRest viewEventRest = new ViewEventRest(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/converter/DiscoverConfigurationConverterTest.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/converter/DiscoverConfigurationConverterTest.java index b4440616d77f..eb75fbfb4f15 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/converter/DiscoverConfigurationConverterTest.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/converter/DiscoverConfigurationConverterTest.java @@ -21,6 +21,7 @@ import org.dspace.discovery.configuration.DiscoverySearchFilter; import org.dspace.discovery.configuration.DiscoverySortConfiguration; import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration; +import org.dspace.services.ConfigurationService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,6 +46,9 @@ public class DiscoverConfigurationConverterTest { @Mock private DiscoveryConfiguration discoveryConfiguration; + @Mock + private ConfigurationService configurationService; + @Before public void setUp() throws Exception { } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java index b60f26940ff8..b5533a955505 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java @@ -206,4 +206,24 @@ public static Matcher publisherFilter() { ); } + + public static Matcher clarinSubjectFirstValueFilter() { + return allOf( + hasJsonPath("$.filter", is("subjectFirstValue")), + hasJsonPath("$.hasFacets", is(false)), + hasJsonPath("$.type", is("hierarchical")), + hasJsonPath("$.openByDefault", is(false)), + checkOperators() + ); + } + + public static Matcher clarinDataProviderFacet() { + return allOf( + hasJsonPath("$.filter", is("dataProvider")), + hasJsonPath("$.hasFacets", is(false)), + hasJsonPath("$.type", is("text")), + hasJsonPath("$.openByDefault", is(false)), + checkOperators() + ); + } } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/submit/step/validation/CMDIFileBundleMaintainerTest.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/submit/step/validation/CMDIFileBundleMaintainerTest.java index 64ec9716dfb4..afc1e0dbb771 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/submit/step/validation/CMDIFileBundleMaintainerTest.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/submit/step/validation/CMDIFileBundleMaintainerTest.java @@ -108,7 +108,7 @@ public void setUp() throws SQLException, AuthorizeException, IOException { this.it = installItemService.installItem(context, workspaceItem); this.mf = metadataFieldService.findByString(context, "local.hasCMDI", '.'); this.mv = metadataValueService.create(context, it, mf); - this.mv.setValue("yes"); + this.mv.setValue("true"); this.listMv = new ArrayList<>(); listMv.add(this.mv); this.dspaceObject = it; diff --git a/dspace/config/clarin-dspace.cfg b/dspace/config/clarin-dspace.cfg index 6bffb412dc49..bc9687fdebd1 100644 --- a/dspace/config/clarin-dspace.cfg +++ b/dspace/config/clarin-dspace.cfg @@ -64,8 +64,8 @@ lr.help.mail = test@test.sk lr.help.phone = 0000 # Admin could upload the file bigger than maximum upload size. -# Should be this big file deleted from the '/temp' folder? -delete.big.file.after.upload = true +# Should be this big file deleted from where it was uploaded? +delete.big.file.after.upload = false ##### BITSTREAM DOWNLOAD ##### @@ -154,6 +154,7 @@ matomo.auth.token = 26388b4164695d69e6ee6e2dd527b723 matomo.site.id = 1 matomo.tracker.bitstream.site_id = 1 matomo.tracker.oai.site_id = 1 +matomo.tracker.host.url = http://url:port/matomo.php statistics.cache-server.uri = http://cache-server.none #### Statistic usage reports #### @@ -162,7 +163,7 @@ statistics.cache-server.uri = http://cache-server.none ##### Citacepro config ##### # citace.pro.url = https://www.citacepro.com/api/dspace/citace/oai -# citace.pro.university = dspace.tul.cz +# citace.pro.university = dspace.url.com # only use true or false for the value of citace pro allowed # citace.pro.allowed = true @@ -245,6 +246,9 @@ shibboleth.name.conversion.outputEncoding = UTF-8 ### File preview ### # File preview is enabled by default file.preview.enabled = false +# It the ZIP file contains more than 1000 files show only the first 1000 files +file.preview.zip.limit.length = 1000 + ### Storage service ### # Synchronization is NOT enabled by default @@ -260,3 +264,22 @@ build.version.file.path = ${dspace.dir}/config/VERSION_D.txt #### Item View #### # Show handle and doi as identifiers - show only DOI if it exists instead of handle by default item-page.show-handle-and-doi = false + + +#### Searching properties #### +# Filter sort options for the search - sorting options in the search page +sort.options.filtered = dc.date.accessioned +# Show splitters and all values for the these hierarchical facets +# `subject` - hierarchical facet defined in the `discovery.xml` +discovery.solr.facets.allvalues = subject + + +#### File download options #### +# minimum number of files for enabling zipped download: +download.all.limit.min.file.count = 1 +# maximum total size of files for enabling zipped download: +download.all.limit.max.file.size = 1073741824 +# minimum total size of files for enabling download alert: +download.all.alert.min.file.size = 10485760 +# used in elg crosswalk exposing download locations +elg.download-location.exposed = 0 \ No newline at end of file diff --git a/dspace/config/crosswalks/oai/description-olac.xml b/dspace/config/crosswalks/oai/description-olac.xml new file mode 100644 index 000000000000..a352d1dc4612 --- /dev/null +++ b/dspace/config/crosswalks/oai/description-olac.xml @@ -0,0 +1,16 @@ + + ${description.archiveURL} + + ${description.institution} + ${description.institutionURL} + ${description.shortLocation} + ${description.location} + ${description.synopsis} + ${description.access} + ${description.archivalSubmissionPolicy} + diff --git a/dspace/config/crosswalks/oai/metadataFormats/elg.xsl b/dspace/config/crosswalks/oai/metadataFormats/elg.xsl new file mode 100644 index 000000000000..b822d6e2fad5 --- /dev/null +++ b/dspace/config/crosswalks/oai/metadataFormats/elg.xsl @@ -0,0 +1,912 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value automatically assigned - leave as is + + + + + + + + + + + http://w3id.org/meta-share/meta-share/ELG-SHARE + + LINDAT/CLARIAH-CZ + + + + http://purl.org/spar/datacite/handle + + + + + + + + + + + + LanguageResource + + + unspecified + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Organization + + + + + + + + + + + + + + + + + + + , + + + + + + Person + + + + + + + + + Organization + + + + + + + + + + + + + + + + + + + + + + http://w3id.org/meta-share/meta-share/OpenAIRE + + + + + + + + + + + + http://w3id.org/meta-share/meta-share/other + + + + + + + + Organization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corpus + http://w3id.org/meta-share/meta-share/unspecified + + + + + + + + http://w3id.org/meta-share/meta-share/noP + http://w3id.org/meta-share/meta-share/noS + + + + + + + + + + + + + + + + + + + + + + + + lcrMediaType + ldMediaType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://w3id.org/meta-share/meta-share/ + + monolingual + bilingual + multilingual + + + http://w3id.org/meta-share/meta-share/unspecified + + + + + + + + + + + http://w3id.org/meta-share/meta-share/ + + monolingual + bilingual + multilingual + + + + + + + + + + + unspecified + + + unspecified + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + downloadable + sourceCode + + + + + + + + + + + + + + + + + + + + + + + + + + + demo + samples + + + + + + + + + + + + + + + + + + + + http://w3id.org/meta-share/meta-share/unspecified + + + + + + + ToolService + + undefined + + + + + + + + + + + false + + + + + + + http://w3id.org/meta-share/meta-share/unspecified + + + + + + + http://w3id.org/meta-share/meta-share/unspecified + + + + + false + + + + + + + LanguageDescription + + + http://w3id.org/meta-share/meta-share/grammar + http://w3id.org/meta-share/meta-share/model + http://w3id.org/meta-share/meta-share/other + + + + + + + + Grammar + http://w3id.org/meta-share/meta-share/unspecified + + + + + + + + + + + + http://w3id.org/meta-share/meta-share/unspecified + + -1 + + + + + + + + + + + + + Unspecified + + + + + + + + + + + LexicalConceptualResource + + + http://w3id.org/meta-share/meta-share/wordNet + + + + + + http://w3id.org/meta-share/meta-share/unspecified + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://w3id.org/meta-share/meta-share/four-gram + + + + + http://w3id.org/meta-share/meta-share/five-gram + + + + + http://w3id.org/meta-share/meta-share/T-HPair + + + + + http://w3id.org/meta-share/meta-share/article + + + + + http://w3id.org/meta-share/meta-share/bigram + + + + + http://w3id.org/meta-share/meta-share/byte + + + + + http://w3id.org/meta-share/meta-share/class + + + + + http://w3id.org/meta-share/meta-share/concept + + + + + http://w3id.org/meta-share/meta-share/diphone1 + + + + + http://w3id.org/meta-share/meta-share/element + + + + + http://w3id.org/meta-share/meta-share/entry + + + + + http://w3id.org/meta-share/meta-share/expression + + + + + http://w3id.org/meta-share/meta-share/file + + + + + http://w3id.org/meta-share/meta-share/frame1 + + + + + http://w3id.org/meta-share/meta-share/gb + + + + + http://w3id.org/meta-share/meta-share/hour1 + + + + + http://w3id.org/meta-share/meta-share/idiomaticExpression + + + + + http://w3id.org/meta-share/meta-share/image2 + + + + + http://w3id.org/meta-share/meta-share/item + + + + + http://w3id.org/meta-share/meta-share/kb + + + + + http://w3id.org/meta-share/meta-share/keyword1 + + + + + http://w3id.org/meta-share/meta-share/lexicalType + + + + + http://w3id.org/meta-share/meta-share/mb + + + + + http://w3id.org/meta-share/meta-share/minute + + + + + http://w3id.org/meta-share/meta-share/multiWordUnit + + + + + http://w3id.org/meta-share/meta-share/neologism + + + + + http://w3id.org/meta-share/meta-share/other + + + + + http://w3id.org/meta-share/meta-share/phoneme2 + + + + + http://w3id.org/meta-share/meta-share/phoneticUnit + + + + + http://w3id.org/meta-share/meta-share/predicate + + + + + http://w3id.org/meta-share/meta-share/rule + + + + + http://w3id.org/meta-share/meta-share/second + + + + + http://w3id.org/meta-share/meta-share/semanticUnit1 + + + + + http://w3id.org/meta-share/meta-share/sentence1 + + + + + http://w3id.org/meta-share/meta-share/shot1 + + + + + http://w3id.org/meta-share/meta-share/syllable2 + + + + + http://w3id.org/meta-share/meta-share/synset + + + + + http://w3id.org/meta-share/meta-share/syntacticUnit1 + + + + + http://w3id.org/meta-share/meta-share/term + + + + + http://w3id.org/meta-share/meta-share/text1 + + + + + http://w3id.org/meta-share/meta-share/token + + + + + http://w3id.org/meta-share/meta-share/trigram + + + + + http://w3id.org/meta-share/meta-share/turn + + + + + http://w3id.org/meta-share/meta-share/unigram + + + + + http://w3id.org/meta-share/meta-share/unit + + + + + http://w3id.org/meta-share/meta-share/utterance1 + + + + + http://w3id.org/meta-share/meta-share/word3 + + + + + + + + + + + + + + + + + + + + + + + + + + Model + + http://w3id.org/meta-share/meta-share/unspecified + + + http://w3id.org/meta-share/meta-share/unspecified + + + + + + + + + + + \ No newline at end of file diff --git a/dspace/config/crosswalks/oai/metadataFormats/metasharev2.xsl b/dspace/config/crosswalks/oai/metadataFormats/metasharev2.xsl index cf43751882d8..e716844112e6 100644 --- a/dspace/config/crosswalks/oai/metadataFormats/metasharev2.xsl +++ b/dspace/config/crosswalks/oai/metadataFormats/metasharev2.xsl @@ -139,7 +139,7 @@ - + @@ -155,7 +155,7 @@ - + @@ -178,7 +178,7 @@ test="doc:metadata/doc:element[@name='local']/doc:element[@name='contact']/doc:element[@name='person']/doc:element/doc:field[@name='value']"> - + @@ -199,7 +199,7 @@ - + @@ -251,7 +251,7 @@ - + @@ -270,7 +270,7 @@ - + @@ -456,7 +456,7 @@ - + @@ -473,7 +473,7 @@ - + diff --git a/dspace/config/crosswalks/oai/xoai.xml b/dspace/config/crosswalks/oai/xoai.xml index ef721c10423f..723aa02d7311 100644 --- a/dspace/config/crosswalks/oai/xoai.xml +++ b/dspace/config/crosswalks/oai/xoai.xml @@ -23,6 +23,7 @@ + This is the default context of the DSpace OAI-PMH data provider. @@ -97,7 +98,7 @@ - + @@ -105,7 +106,6 @@ This context exports items following the openaire data archive rules. - @@ -116,19 +116,6 @@ http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd - - cmdi - metadataFormats/lindat_cmdi.xsl - http://www.clarin.eu/cmd/ - http://catalog.clarin.eu/ds/ComponentRegistry/rest/registry/profiles/clarin.eu:cr1:p_1349361150622/xsd - - - - oai_metasharev2 - metadataFormats/metasharev2.xsl - http://www.ilsp.gr/META-XMLSchema - http://metashare.ilsp.gr/META-XMLSchema/v2.0/META-SHARE-Resource.xsd - mets metadataFormats/mets.xsl @@ -191,12 +178,6 @@ http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd - - olac - metadataFormats/olac.xsl - http://www.language-archives.org/OLAC/1.1/olac.xsd - http://www.language-archives.org/OLAC/1.1/ - uketd_dc metadataFormats/uketd_dc.xsl @@ -204,12 +185,6 @@ http://naca.central.cranfield.ac.uk/ethos-oai/2.0/uketd_dc.xsd - - bibtex - metadataFormats/bibtex.xsl - http://lindat.mff.cuni.cz/ns/experimental/bibtex - http://lindat.mff.cuni.cz/schemas/experimental/bibtex.xsd - junii2 metadataFormats/junii2.xsl @@ -225,13 +200,44 @@ http://namespace.openaire.eu/schema/oaire/ https://www.openaire.eu/schema/repo-lit/4.0/openaire.xsd - + + bibtex + metadataFormats/bibtex.xsl + http://lindat.mff.cuni.cz/ns/experimental/bibtex + http://lindat.mff.cuni.cz/schemas/experimental/bibtex.xsd + + + oai_metasharev2 + metadataFormats/metasharev2.xsl + http://www.ilsp.gr/META-XMLSchema + http://metashare.ilsp.gr/META-XMLSchema/v2.0/META-SHARE-Resource.xsd + + + cmdi + metadataFormats/lindat_cmdi.xsl + http://www.clarin.eu/cmd/ + http://catalog.clarin.eu/ds/ComponentRegistry/rest/registry/profiles/clarin.eu:cr1:p_1349361150622/xsd + + + + olac + metadataFormats/olac.xsl + http://www.language-archives.org/OLAC/1.1/olac.xsd + http://www.language-archives.org/OLAC/1.1/ + oai_datacite metadataFormats/datacite_openaire.xsl http://schema.datacite.org/oai/oai-1.1/ http://schema.datacite.org/oai/oai-1.1/oai.xsd + + elg + metadataFormats/elg.xsl + http://w3id.org/meta-share/meta-share/ + http://w3id.org/meta-share/meta-share/ ../Schema/ELG-SHARE.xsd + + @@ -248,14 +254,21 @@ - + - + - + + + + + + + + @@ -267,11 +280,6 @@ * AND Driver "open access" condition is specified This filter is only used in the DRIVER context ([oai]/driver) --> - - - - - @@ -462,6 +470,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -556,6 +591,59 @@ + + org.dspace.xoai.filter.DSpaceAtLeastOneMetadataFilter + + local.has.files + equal + yes + + + + + org.dspace.xoai.filter.DSpaceMetadataExistsFilter + + metashare.ResourceInfo#ContentInfo.mediaType + + + + + org.dspace.xoai.filter.DSpaceAtLeastOneMetadataFilter + + dc.type + equal + toolService + + + + + org.dspace.xoai.filter.DSpaceAtLeastOneMetadataFilter + + dc.type + equal + + corpus + lexicalConceptualResource + languageDescription + toolService + + + + + + org.dspace.xoai.filter.ColComFilter + + 20.500.12800/1 + + + + + org.dspace.xoai.filter.ColComFilter + + 11234/5011 + + + org.dspace.xoai.filter.DSpaceMetadataExistsFilter @@ -578,13 +666,6 @@ - - - org.dspace.xoai.filter.ColComFilter - - XXX - - diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index 4cf68c17f82f..971757f34794 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -603,13 +603,13 @@ crosswalk.dissemination.DataCite.stylesheet = crosswalks/DIM2DataCite.xsl ## For DataCite via EZID, comment above and uncomment this: #crosswalk.dissemination.DataCite.stylesheet = crosswalks/DIM2EZID.xsl crosswalk.dissemination.DataCite.schemaLocation = \ - http://datacite.org/schema/kernel-3 \ - http://schema.datacite.org/meta/kernel-3/metadata.xsd + http://datacite.org/schema/kernel-4 \ + http://schema.datacite.org/meta/kernel-4/metadata.xsd crosswalk.dissemination.DataCite.preferList = false crosswalk.dissemination.DataCite.publisher = My University #crosswalk.dissemination.DataCite.dataManager = # defaults to publisher #crosswalk.dissemination.DataCite.hostingInstitution = # defaults to publisher -crosswalk.dissemination.DataCite.namespace = http://datacite.org/schema/kernel-3 +crosswalk.dissemination.DataCite.namespace = http://datacite.org/schema/kernel-4 # Crosswalk Plugin Configuration: # The purpose of Crosswalks is to translate an external metadata format to/from @@ -1268,7 +1268,7 @@ default.locale = en # A comma-separated list of Locales. All types of Locales country, country_language, country_language_variant # Note that the appropriate file are present, especially that all the Messages_x.properties are there # may be used, e.g: -# webui.supported.locales = en, de +webui.supported.locales = en, cs #### Submission License substitution variables #### # it is possible include contextual information in the submission license using substitution variables diff --git a/dspace/config/emails/clarin_autoregistration b/dspace/config/emails/clarin_autoregistration index 694151db102c..01727722b7e0 100644 --- a/dspace/config/emails/clarin_autoregistration +++ b/dspace/config/emails/clarin_autoregistration @@ -9,7 +9,7 @@ ## ## See org.dspace.core.Email for information on the format of this file. ## -Subject: ${params[3]}: Account Registration +#set($subject = 'Account Registration') To complete registration for a ${params[3]} repository account at {params[5]}, please click the link below: ${params[0]} diff --git a/dspace/config/emails/clarin_download_link b/dspace/config/emails/clarin_download_link index dfc9e07df4a6..58256186eb6c 100644 --- a/dspace/config/emails/clarin_download_link +++ b/dspace/config/emails/clarin_download_link @@ -11,7 +11,7 @@ ## ## See org.dspace.core.Email for information on the format of this file. ## -Subject: ${params[5]}: Download instructions for ${params[0]} +#set($subject = 'Download instructions') To download the file you have requested, please click the link below: ${params[1]} diff --git a/dspace/config/item-submission.xml b/dspace/config/item-submission.xml index fffeb35776fc..18b25e5c2d0c 100644 --- a/dspace/config/item-submission.xml +++ b/dspace/config/item-submission.xml @@ -46,10 +46,10 @@ --> - + + + + + + yyyy-MM-dd + + + + + + + + + yyyy-MM-dd + + + + @@ -82,6 +111,13 @@ + + + + + @@ -100,6 +136,7 @@ + diff --git a/dspace/config/modules/identifiers.cfg b/dspace/config/modules/identifiers.cfg index 63a9cda30f17..3a30f8dad858 100644 --- a/dspace/config/modules/identifiers.cfg +++ b/dspace/config/modules/identifiers.cfg @@ -13,7 +13,7 @@ # any filters, in the item status page. # This option doesn't require the Show Identifiers submission step to be visible. # Default: false -#identifiers.submission.register = true +identifiers.submission.register = true # This configuration property can be set to a filter name to determine if a PENDING DOI for an item # should be queued for registration. If the filter doesn't match, the DOI will stay in PENDING or MINTED status @@ -47,5 +47,5 @@ identifiers.item-status.register-doi = false # Which identifier types to show in submission step? # Default: handle, doi (currently the only supported identifier 'types') -#identifiers.submission.display = handle +identifiers.submission.display = handle #identifiers.submission.display = doi diff --git a/dspace/config/modules/oai.cfg b/dspace/config/modules/oai.cfg index 98b10f59dee9..b08addfda999 100644 --- a/dspace/config/modules/oai.cfg +++ b/dspace/config/modules/oai.cfg @@ -42,7 +42,20 @@ oai.bitstream.baseUrl = ${dspace.ui.url} oai.config.dir = ${dspace.dir}/config/crosswalks/oai # Description -oai.description.file = ${dspace.dir}/config/crosswalks/oai/description.xml +oai.description.file.0 = ${dspace.dir}/config/crosswalks/oai/description.xml +oai.description.file.1 = ${dspace.dir}/config/crosswalks/oai/description-olac.xml + +# Values below used in description-olac.xml for identifying repository in OAI-PMH +description.archiveURL = http://lindat.cz/ +description.participant.name = Name Surname +help.mail = dspace-help@ufal.mff.cuni.cz +description.institution = Institute of Formal and Applied Linguistics +description.institutionURL = http://ufal.mff.cuni.cz +description.shortLocation = Prague, Czech Republic +description.location = Malostranské náměstí 25,118 00 Prague, Czech Republic +description.synopsis = http://lindat.cz +description.access = https://lindat.mff.cuni.cz/repository/static/about +description.archivalSubmissionPolicy = https://lindat.mff.cuni.cz/repository/static/about # Cache enabled? oai.cache.enabled = true diff --git a/dspace/config/modules/rest.cfg b/dspace/config/modules/rest.cfg index 32dcc0fb1e67..2035077baffe 100644 --- a/dspace/config/modules/rest.cfg +++ b/dspace/config/modules/rest.cfg @@ -71,8 +71,10 @@ rest.properties.exposed = identifier.doi.resolver rest.properties.exposed = spring.servlet.multipart.max-file-size rest.properties.exposed = authentication-shibboleth.show.idp-attributes rest.properties.exposed = item-page.show-handle-and-doi +rest.properties.exposed = download.all.limit.min.file.count +rest.properties.exposed = download.all.limit.max.file.size +rest.properties.exposed = download.all.alert.min.file.size -# TUL rest.properties.exposed = dspace.ui.url rest.properties.exposed = versioning.item.history.include.submitter rest.properties.exposed = statistics.cache-server.uri diff --git a/dspace/config/modules/signposting.cfg b/dspace/config/modules/signposting.cfg index fba80da41481..001c55c5359a 100644 --- a/dspace/config/modules/signposting.cfg +++ b/dspace/config/modules/signposting.cfg @@ -26,7 +26,7 @@ signposting.path = signposting # When "true", the signposting controller is accessible on ${signposting.path} # When "false" or commented out, signposting is disabled/inaccessible. # (Requires reboot of servlet container, e.g. Tomcat, to reload) -signposting.enabled = true +signposting.enabled = false # Name of crosswalk to use for handling of 'describedby' links. signposting.describedby.crosswalk-name = DataCite diff --git a/dspace/config/registries/local-types.xml b/dspace/config/registries/local-types.xml index ad1aba088034..e05977c5cd26 100644 --- a/dspace/config/registries/local-types.xml +++ b/dspace/config/registries/local-types.xml @@ -145,4 +145,18 @@ ISO language name + + local + files + size + Size of all the files in the item in bytes + + + + local + files + count + Count of files in the item + + diff --git a/dspace/config/spiders/ufal.ignore.txt b/dspace/config/spiders/ufal.ignore.txt new file mode 100644 index 000000000000..8333f0a0600a --- /dev/null +++ b/dspace/config/spiders/ufal.ignore.txt @@ -0,0 +1,51 @@ +# monitoring from ufal-point-dev +ufal-point-dev.ms.mff.cuni.cz +195.113.20.155 +# monitoring from GWDG +134.76.10.179 +134.76.10.175 +134.76.4.132 +#lindat-monitoring + stuff from piwik filters (2015/11/19) +195.113.20.66 +195.113.20.155 +134.76.10.179 +134.76.10.175 +134.76.4.132 +74.86.158.0/24 +46.137.190.132 +122.248.234.23 +188.226.183.141 +178.62.52.237 +54.79.28.129 +54.94.142.218 +104.131.107.63 +54.67.10.127 +54.64.67.106 +139.162.154.49 +74.86.158.106 +74.86.158.107 +74.86.158.109 +74.86.158.110 +69.162.124.226 +69.162.124.227 +69.162.124.228 +69.162.124.229 +69.162.124.230 +69.162.124.231 +69.162.124.232 +69.162.124.233 +69.162.124.234 +69.162.124.235 +69.162.124.236 +69.162.124.237 +69.162.124.238 +74.86.158.108 +46.137.190.132 +122.248.234.23 +188.226.183.141 +178.62.52.237 +54.79.28.129 +54.94.142.218 +104.131.107.63 +54.67.10.127 +54.64.67.106 diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 9b11f1c20cfa..9fdb45d082fa 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -173,8 +173,7 @@ - - + diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index 138c771dedb4..a5cce1ffd2b9 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -201,6 +201,8 @@ + + @@ -213,6 +215,7 @@ + @@ -222,7 +225,7 @@ - (search.resourcetype:Item AND latestVersion:true) OR search.resourcetype:Collection OR search.resourcetype:Community + (search.resourcetype:Item) OR search.resourcetype:Collection OR search.resourcetype:Community -withdrawn:true AND -discoverable:false @@ -327,7 +330,7 @@ - + @@ -344,6 +347,7 @@ + @@ -381,7 +385,7 @@ - (search.resourcetype:Item AND latestVersion:true) OR search.resourcetype:Collection OR search.resourcetype:Community + (search.resourcetype:Item) OR search.resourcetype:Collection OR search.resourcetype:Community -withdrawn:true AND -discoverable:false @@ -674,7 +678,7 @@ - search.resourcetype:Item AND latestVersion:true + search.resourcetype:Item withdrawn:true OR discoverable:false @@ -819,7 +823,7 @@ - search.resourcetype:Item AND latestVersion:true + search.resourcetype:Item @@ -950,7 +954,7 @@ - (search.resourcetype:Item AND latestVersion:true) OR search.resourcetype:WorkspaceItem OR search.resourcetype:XmlWorkflowItem + (search.resourcetype:Item) OR search.resourcetype:WorkspaceItem OR search.resourcetype:XmlWorkflowItem @@ -1344,7 +1348,7 @@ - search.resourcetype:Item AND latestVersion:true AND entityType_keyword:Publication + search.resourcetype:Item AND entityType_keyword:Publication -withdrawn:true AND -discoverable:false @@ -1479,7 +1483,7 @@ - search.resourcetype:Item AND latestVersion:true AND entityType_keyword:Person + search.resourcetype:Item AND entityType_keyword:Person -withdrawn:true AND -discoverable:false @@ -1596,7 +1600,7 @@ - search.resourcetype:Item AND latestVersion:true AND entityType_keyword:Project + search.resourcetype:Item AND entityType_keyword:Project -withdrawn:true AND -discoverable:false @@ -1714,7 +1718,7 @@ - search.resourcetype:Item AND latestVersion:true AND entityType_keyword:OrgUnit + search.resourcetype:Item AND entityType_keyword:OrgUnit -withdrawn:true AND -discoverable:false @@ -1839,7 +1843,7 @@ - search.resourcetype:Item AND latestVersion:true AND entityType_keyword:JournalIssue + search.resourcetype:Item AND entityType_keyword:JournalIssue -withdrawn:true AND -discoverable:false @@ -1959,7 +1963,7 @@ - search.resourcetype:Item AND latestVersion:true AND entityType_keyword:JournalVolume + search.resourcetype:Item AND entityType_keyword:JournalVolume -withdrawn:true AND -discoverable:false @@ -2078,7 +2082,7 @@ - search.resourcetype:Item AND latestVersion:true AND entityType_keyword:Journal + search.resourcetype:Item AND entityType_keyword:Journal -withdrawn:true AND -discoverable:false @@ -2212,7 +2216,7 @@ - search.resourcetype:Item AND latestVersion:true AND (entityType_keyword:OrgUnit OR entityType_keyword:Person) + search.resourcetype:Item AND (entityType_keyword:OrgUnit OR entityType_keyword:Person) -withdrawn:true AND -discoverable:false @@ -2268,7 +2272,7 @@ - search.resourcetype:Item AND latestVersion:true AND entityType_keyword:OrgUnit AND dc.type:FundingOrganization + search.resourcetype:Item AND entityType_keyword:OrgUnit AND dc.type:FundingOrganization -withdrawn:true AND -discoverable:false @@ -2564,6 +2568,18 @@ + + + + + local.dataProvider + + + + + + + @@ -2589,6 +2605,28 @@ + + + + + + + + + + dc.subject.* + + + + + + + diff --git a/dspace/config/submission-forms_cs.xml b/dspace/config/submission-forms_cs.xml new file mode 100644 index 000000000000..d1fcbc629c66 --- /dev/null +++ b/dspace/config/submission-forms_cs.xml @@ -0,0 +1,2130 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + dc + title + + false + + onebox + Enter the name of the file. + You must enter a name for this file + + + + + dc + description + true + + textarea + Enter a description for the file + + + +
+ + +
+ + + + local + contact + person + true + + + complex + This is contact person + + + + + + local + sponsor + true + + + complex + This is funding + + + + + + dc + contributor + author + true + + clarin-name + Enter the author's name (Family name, Given names). + + + + + + + dc + title + + false + + onebox + Uveďte anglický název tohoto příspěvku. + Musíte uvést název. + + + + + dc + title + alternative + true + + onebox + If the item has any alternative titles, please enter them here. + + + + + + dc + date + issued + false + + + date + Please give the date of previous publication or public distribution. + You can leave out the day and/or month if they aren't applicable. + + You must enter at least the year. + + + + dc + publisher + + false + + + onebox + Enter the name of the publisher of the previously issued instance of this item. + + + + + + dc + identifier + citation + false + + onebox + Enter the standard citation for the previously issued instance of this item. + + + + + + dc + relation + ispartofseries + true + + Technical Report + series + Enter the series and number assigned to this item by your community. + + + + + + dc + identifier + + + true + + qualdrop_value + If the item has any identification numbers or codes associated with + it, please enter the types and the actual numbers or codes. + + + + + + + dc + type + + true + + dropdown + Select the type of content of the item. + + + + + + + dc + language + iso + false + + dropdown + Select the language of the main content of the item. If the language does not appear in the + list, please select 'Other'. If the content does not really have a language (for example, if it + is a dataset or an image) please select 'N/A'. + + + + + + + local + hasCMDI + true + + list + Are you going to upload cmdi file? + + + policy=deny,action=read,grantee-type=user,grantee-id=* + + + + + + local + hidden + + true + + + list + Should item be harvestable thru OAI-PMH but behave like private? + + + policy=deny,action=read,grantee-type=user,grantee-id=* + + + + + + local + bitstream + redirectToURL + false + + onebox + + The actual maximum upload size of the file is 4GB. To upload the file bigger than maximum + upload size type the URL of that big file. Admin must know URL to that bitstream file. + Then click on the 'Save' button and the file will start to upload. The file will be loaded + from the '/temp' folder of the server. Example: /tomcat/temp/bitstream.png + + + + policy=deny,action=read,grantee-type=user,grantee-id=* + + + +
+ + +
+ + + dc + subject + + + true + + tag + Enter appropriate subject keywords or phrases. + + srsc + + + + + dc + description + abstract + false + + textarea + Enter the abstract of the item. + + + + + + dc + description + sponsorship + false + + textarea + Enter the names of any sponsors and/or funding codes in the box. + + + + + + dc + description + + false + + textarea + Enter any other description or comments in this box. + + + +
+ + + +
+ + + isAuthorOfPublication + person + true + + Enter the author's name (Family name, Given names). + + dc + contributor + author + onebox + + orcid + + + + + + + + dc + title + + false + + onebox + Enter the main title of the item. + You must enter a main title for this item. + + + + + dc + title + alternative + true + + onebox + If the item has any alternative titles, please enter them here. + + + + + + dc + date + issued + false + + + date + Please give the date of previous publication or public distribution. + You can leave out the day and/or month if they aren't applicable. + + You must enter at least the year. + + + + dc + publisher + + false + + + onebox + Enter the name of the publisher of the previously issued instance of this item. + + + + + + dc + identifier + citation + false + + onebox + Enter the standard citation for the previously issued instance of this item. + + + + + + dc + relation + ispartofseries + true + + series + Enter the series and number assigned to this item by your community. + + + + + + dc + identifier + + + true + + qualdrop_value + If the item has any identification numbers or codes associated with + it, please enter the types and the actual numbers or codes. + + + + + + + dc + type + + true + + dropdown + Select the type(s) of content of the item. To select more than one value in the list, you may + have to hold down the "CTRL" or "Shift" key. + + + + + + + dc + language + iso + false + + dropdown + Select the language of the main content of the item. If the language does not appear in the + list, please select 'Other'. If the content does not really have a language (for example, if it + is a dataset or an image) please select 'N/A'. + + + + +
+ + +
+ + + isPublicationOfAuthor + publication + + import a publicaton + pubmed + + + + + person + familyName + + onebox + Enter the last name of the person + + + + + person + givenName + + onebox + Enter the first name of the person + + + + + person + email + + onebox + Enter the email of the person + + + + + + + + + + + + + + + person + birthDate + + date + Enter the birth date of the person + + + + + + + + + + + + + + + person + jobTitle + + onebox + Enter the job title of the person + + +
+ + +
+ + + dc + title + + onebox + Enter the name of the project + + + + + dc + identifier + + onebox + Enter the id of the project + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + isProjectOfPerson + person + true + + Enter the investigator's name (Family name, Given names). + + project + investigator + onebox + + orcid + + + + + isProjectOfOrgUnit + orgunit + false + + Enter the organization's name + + project + funder + name + onebox + + + + + + + dc + subject + true + + onebox + Enter the keywords of the project + + + + + project + startDate + + date + Enter the start date of the project + + + project + endDate + + date + Enter the end date of the project + + + + + project + amount + + onebox + Enter the amount of the project + + + project + amount + currency + + onebox + Enter the amount currency of the project + + + + + dc + description + + textarea + Enter the description of the project + + +
+ + +
+ + + organization + legalName + + onebox + Enter the name of the orgunit + + + + + dc + identifier + + onebox + Enter the id of the orgunit + + + + + organization + foundingDate + + date + Enter the established date of the orgunit + + + + + organization + address + addressLocality + + onebox + Enter the city of the orgunit + + + + + organization + address + addressCountry + + onebox + Enter the country of the orgunit + + + + + dc + description + + textarea + Enter the description of the orgunit + + +
+ + +
+ + + dc + title + + onebox + Enter the name of the journal + + + + + creativework + editor + + name + Enter the editor of the journal + + + + + creativeworkseries + issn + + onebox + Enter the issn of the journal + + + + + dc + description + + textarea + Enter the description of the journal + + + + + creativework + publisher + + onebox + Enter the publisher of the journal + + + +
+ + +
+ + + isJournalOfVolume + journal + + + + Select the journal related to this volume. + sherpaJournal + + + + + dc + title + + onebox + Enter the name of the journal volume + + + + + publicationvolume + volumeNumber + + onebox + Enter the volume of the journal volume + + + + + creativework + datePublished + + date + Enter the issue date of the journal volume + + + + + dc + description + + textarea + Enter the description of the journal volume + + +
+ + +
+ + + isJournalVolumeOfIssue + journalvolume + + Select the journal volume related to this issue. + + + + + dc + title + + onebox + Enter the name of the journal issue + + + + + publicationissue + issueNumber + + onebox + Enter the number of the journal issue + + + + + creativework + datePublished + + date + Enter the issue date of the journal issue + + + + + dc + description + + textarea + Enter the description of the journal issue + + + + + creativework + keywords + true + + onebox + Enter the keywords of the journal issue + + + +
+ + + +
+ + + dc + title + + false + + onebox + Enter the main title of the item. + You must enter a main title for this item. + + + + + dc + title + alternative + true + + onebox + If the item has any alternative titles, please enter them here. + + + + + + isAuthorOfPublication + personOrOrgunit + true + true + + Add an author + + dc + contributor + author + name + + orcid + At least one author (plain text or relationship) is required + + + + + + + + dc + date + issued + false + + + date + Please give the date of previous publication or public distribution. + You can leave out the day + and/or month if they aren't applicable. + + You must enter at least the year. + + + + + dc + publisher + + false + + + onebox + Enter the name of the publisher of the previously issued instance of this item. + + + + + + dc + relation + hasversion + false + + onebox + Enter the URL/DOI of the editor version of this item. + + + + + + dcterms + references + + false + + onebox + Enter the URL/DOI of the related Dataset. + + + + + + dc + identifier + + + true + + qualdrop_value + If the item has any identification numbers or codes associated with + it, please enter the types + and the actual numbers or codes. + + + + + + + oaire + citation + title + false + + onebox + Include the name of related item like the journal name, book title or event name. + + + + + + oaire + citation + conferencePlace + false + + onebox + Enter the event location. + + + + + + oaire + citation + conferenceDate + false + + date + Enter the date of the event. + + + + + + oaire + citation + volume + false + + onebox + Enter the volume of the item. + + + + + + oaire + citation + issue + false + + onebox + Enter the issue number of the item. + + + + + + oaire + citation + edition + false + + onebox + Enter the edition of the item. + + + + + + oaire + citation + startPage + false + + onebox + Enter the start page number. + + + + oaire + citation + endPage + false + + onebox + Enter the last page number. + + + + + + dc + type + + true + + dropdown + Select the type(s) of content of the item. To select more than one value in the list, you may + have to hold down the "CTRL" or "Shift" key. + + + + + + + oaire + version + false + + dropdown + Select the version of the resource. If the resource does not have that information, please + select "Not Applicable (or Unknown)". + + + + dc + language + iso + false + + dropdown + Select the language of the main content of the item. If the language does not appear in the + list, please select 'Other'. If the content does not really have a language (for example, if it + is a dataset or an image) please select 'N/A'. + + + + +
+ +
+ + + dc + subject + + + true + + tag + Enter appropriate subject keywords or phrases. + + srsc + + + + + + + + + + + dc + description + abstract + false + + textarea + Enter the abstract of the item. + + + + + + isProjectOfPublication + project + true + false + + Add a related Funding + + dc + relation + onebox + + openAIREFunding + + + + + + dc + rights + false + + dropdown + Select the access type of the resource. + + + + + + oaire + license + condition + false + + dropdown + Select the license of the resource. + + + + + + dc + coverage + + false + + onebox + Enter the coverage of the item, like a period, jurisdiction, etc. + + + + + + dc + description + + false + + textarea + Enter any other description or comments in this box. + + + +
+ +
+ + + person + familyName + + onebox + Enter surname or last name of the person + + + person + givenName + + onebox + Enter personal or first name of the person + + + + + dc + title + + onebox + Enter the preferred name of this person regarding the authorship + + + + + person + affiliation + name + true + + onebox + Enter the organizational or institutional affiliation of this person + + + + + person + email + true + + onebox + Enter the email of the person + + + + + person + identifier + + + true + + qualdrop_value + If the author has any identifiers or codes associated with + it, please enter the types and the actual numbers or codes. + + + + +
+ +
+ + + dc + title + + onebox + Enter the name of the project + + + + + dc + identifier + uri + + onebox + Enter the URL of the project webpage + + + + + isFundingAgencyOfProject + openAIREFundingAgency + false + false + + Add a Funding Agency + + project + funder + name + onebox + + + One funding agency is required + + + + + oaire + fundingStream + + onebox + Enter the name of the funding stream of the project + + + dc + identifier + + onebox + Enter the identifier of the project + + +
+ +
+ + + organization + legalName + + onebox + Enter the name of the orgunit or organization + + + + + organization + identifier + + + true + + qualdrop_value + If the organization has any identifiers or codes associated with + it, please enter the types and the actual numbers or codes. + + + + + + + dc + type + + dropdown + Choose the attributes of the Organization + + + + + + dc + description + + textarea + Enter the description of the orgunit + + +
+ +
+ + + + + + + + + + + + + + + + + + + Yes + true + + + + + ISSN + issn + + + Other + other + + + ISMN + ismn + + + Gov't Doc # + govdoc + + + URI + uri + + + ISBN + isbn + + + + + + + N/A + N/A + + + EU + euFunds + + + Own funds + ownFunds + + + National + nationalFunds + + + other + Other + + + + + + Animation + Animation + + + Article + Article + + + Book + Book + + + Book chapter + Book chapter + + + Dataset + Dataset + + + Learning Object + Learning Object + + + Image + Image + + + Image, 3-D + Image, 3-D + + + Map + Map + + + Musical Score + Musical Score + + + Plan or blueprint + Plan or blueprint + + + Preprint + Preprint + + + Presentation + Presentation + + + Recording, acoustical + Recording, acoustical + + + Recording, musical + Recording, musical + + + Recording, oral + Recording, oral + + + Software + Software + + + Technical Report + Technical Report + + + Thesis + Thesis + + + Video + Video + + + Working Paper + Working Paper + + + Other + Other + + + + + + + N/A + + + + English (United States) + en_US + + + English + en + + + Spanish + es + + + German + de + + + French + fr + + + Italian + it + + + Japanese + ja + + + Chinese + zh + + + Portuguese + pt + + + Turkish + tr + + + (Other) + other + + + + + + + + + + + Without License + + + + Attribution (CC-BY) + http://creativecommons.org/licenses/by/4.0/ + + + Attribution, No Derivative Works (CC-BY-ND) + http://creativecommons.org/licenses/by-nd/4.0/ + + + Attribution, Share-alike (CC-BY-SA) + http://creativecommons.org/licenses/by-sa/4.0/ + + + Attribution, Non-commercial (CC-BY-NC) + http://creativecommons.org/licenses/by-nc/4.0/ + + + Attribution, Non-commercial, No Derivative Works (CC-BY-NC-ND) + http://creativecommons.org/licenses/by-nc-nd/4.0/ + + + Attribution, Non-commercial, Share-alike (CC-BY-NC-SA) + http://creativecommons.org/licenses/by-nc-sa/4.0/ + + + + Other + other + + + + + + + + Interactive Resource + interactive resource + + + - Website + website + + + Dataset + dataset + + + - Interview + interview + + + Image + image + + + - Moving Image + moving image + + + -- Video + video + + + - Still Image + still image + + + Other + other + + + Software + software + + + - Research Software + research software + + + Workflow + workflow + + + Cartographic Material + cartographic material + + + - Map + map + + + Sound + sound + + + - Musical Composition + musical composition + + + Text + text + + + - Annotation + annotation + + + - Bibliography + bibliography + + + - Book + book + + + -- Book Part + book part + + + - Conference Object + conference object + + + -- Conference Proceedings + conference proceedings + + + --- Conference Paper + conference paper + + + --- Conference Poster + conference poster + + + -- Conference Paper Not In Proceedings + conference paper not in proceedings + + + -- Conference Poster Not In Proceedings + conference poster not in proceedings + + + - Lecture + lecture + + + - Letter + letter + + + - Periodical + periodical + + + -- Journal + journal + + + --- Contribution to Journal + contribution to journal + + + ---- Journal Article + journal article + + + ----- Data Paper + data paper + + + ----- Review Article + review article + + + ----- Research Article + research article + + + ----- Corrigendum + corrigendum + + + ----- Software Paper + software paper + + + ---- Editorial + editorial + + + ---- Letter to the Editor + letter to the editor + + + -- Newspaper + newspaper + + + --- Newspaper Article + newspaper article + + + -- Magazine + magazine + + + - Patent + patent + + + - Preprint + preprint + + + - Report + report + + + -- Report Part + report part + + + -- Internal Report + internal report + + + -- Memorandum + memorandum + + + -- Other Type of Report + other type of report + + + -- Policy Report + policy report + + + -- Project Deliverable + project deliverable + + + --- Data Management Plan + data management plan + + + -- Report to Funding Agency + report to funding agency + + + -- Research Report + research report + + + -- Technical Report + technical report + + + - Research Proposal + research proposal + + + - Review + review + + + -- Book Review + book review + + + - Technical Documentation + technical documentation + + + - Working Paper + working paper + + + - Thesis + thesis + + + -- Bachelor Thesis + bachelor thesis + + + -- Doctoral Thesis + doctoral thesis + + + -- Master Thesis + master thesis + + + - Musical Notation + musical notation + + + - Blog Post + blog post + + + - Manuscript + website + + + Learning Object + learning object + + + Clinical Trial + clinical trial + + + Clinical Study + clinical study + + + + + + Author’s Original + http://purl.org/coar/version/c_b1a7d7d4d402bcce + + + Submitted Manuscript Under Review + http://purl.org/coar/version/c_71e4c1898caa6e32 + + + Accepted Manuscript + http://purl.org/coar/version/c_ab4af688f83e57aa + + + Proof + http://purl.org/coar/version/c_fa2ee174bc00049f + + + Version of Record + http://purl.org/coar/version/c_970fb48d4fbd8a85 + + + Corrected Version of Record + http://purl.org/coar/version/c_e19f295774971610 + + + Enhanced Version of Record + http://purl.org/coar/version/c_dc82b40f9837b551 + + + Not Applicable (or Unknown) + http://purl.org/coar/version/c_be7fb7dd8ff6fe43 + + + + + + open access + http://purl.org/coar/access_right/c_abf2 + + + embargoed access + http://purl.org/coar/access_right/c_f1cf + + + restricted access + http://purl.org/coar/access_right/c_16ec + + + metadata only access + http://purl.org/coar/access_right/c_14cb + + + + + + Scopus Author ID + scopus-author-id + + + Ciencia ID + ciencia-id + + + Google Scholar ID + gsid + + + Open Researcher and Contributor ID (ORCID) + orcid + + + Web of Science ResearcherID + rid + + + ISNI - International Standard Name Identifier + isni + + + Other + + + + + + + ISNI - International Standard Name Identifier + isni + + + Ringgold identifier + rin + + + Research Organization Registry + ror + + + Other + + + + + + + N/A + + + + Is a Funding Organization + FundingOrganization + + + + + + Hidden + hidden + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/dspace/src/main/docker/dspace-solr/Dockerfile b/dspace/src/main/docker/dspace-solr/Dockerfile index 9fe9adf9440f..cd874dc9e998 100644 --- a/dspace/src/main/docker/dspace-solr/Dockerfile +++ b/dspace/src/main/docker/dspace-solr/Dockerfile @@ -33,4 +33,6 @@ COPY dspace/solr/statistics/conf/* $STATISTICS_CONFIGSET_PATH/ RUN chown -R solr:solr /opt/solr/server/solr/configsets +COPY scripts/log4j2.solr.xml /var/solr/log4j2.xml + USER solr diff --git a/scripts/envs/__basic.example.bat b/scripts/envs/__basic.example.bat index 731c7d4d95f6..bc50cb505244 100644 --- a/scripts/envs/__basic.example.bat +++ b/scripts/envs/__basic.example.bat @@ -3,4 +3,5 @@ set dspace_source=C:\workspace\DSpace\ set tomcat=C:\apache-tomcat-9.0.64\ set dspace_application=C:\dspace\ set m2_source=%USERPROFILE%\.m2 +set dspace_solr=C:\workspace\solr set dspace_source=C:\workspace\DSpace \ No newline at end of file diff --git a/scripts/fast-build/config-update.bat b/scripts/fast-build/config-update.bat index 800fc97205f2..6f80ae31ce7d 100644 --- a/scripts/fast-build/config-update.bat +++ b/scripts/fast-build/config-update.bat @@ -6,3 +6,5 @@ rem copy all config files xcopy /e /h /i /q /y %dspace_source%\dspace\config\ %dspace_application%\config\ cd %dspace_source%\scripts\fast-build\ + +call update-solr-configsets.bat diff --git a/scripts/fast-build/update-solr-configsets.bat b/scripts/fast-build/update-solr-configsets.bat new file mode 100644 index 000000000000..e5ca174ff29f --- /dev/null +++ b/scripts/fast-build/update-solr-configsets.bat @@ -0,0 +1,5 @@ +call ..\envs\__basic.bat + +rm -rf %dspace_solr%server\solr\configsets\authority %dspace_solr%server\solr\configsets\oai dspace_solr%server\solr\configsets\search dspace_solr%server\solr\configsets\statistics +xcopy /e /h /i /q /y %dspace_application%solr\ %dspace_solr%server\solr\configsets\ + diff --git a/scripts/log4j2.solr.xml b/scripts/log4j2.solr.xml new file mode 100644 index 000000000000..6f0e30e5b5b4 --- /dev/null +++ b/scripts/log4j2.solr.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + %maxLen{%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p (%t) [%X{collection} %X{shard} %X{replica} %X{core}] %c{1.} %m%notEmpty{ =>%ex{short}}}{10240}%n + + + + + + + + %maxLen{%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p (%t) [%X{collection} %X{shard} %X{replica} %X{core}] %c{1.} %m%notEmpty{ =>%ex{short}}}{10240}%n + + + + + + + + + + + + + %maxLen{%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p (%t) [%X{collection} %X{shard} %X{replica} %X{core}] %c{1.} %m%notEmpty{ =>%ex{short}}}{10240}%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file