From 16159f37611834bc177338f7f29fecfed4cbf368 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Thu, 28 Sep 2023 15:07:14 +0200 Subject: [PATCH 001/230] 106812: Refactor resource policies to have either group or eperson --- .../app/itemimport/ItemImportServiceImpl.java | 2 +- .../authorize/AuthorizeServiceImpl.java | 8 +- .../dspace/authorize/FixDefaultPolicies.java | 3 +- .../java/org/dspace/authorize/PolicySet.java | 9 +- .../authorize/ResourcePolicyServiceImpl.java | 16 +- .../service/ResourcePolicyService.java | 30 +- .../crosswalk/METSRightsCrosswalk.java | 108 ++--- ...ce_group_or_eperson_for_resourcepolicy.sql | 10 + .../status/DefaultAccessStatusHelperTest.java | 25 +- .../org/dspace/builder/CollectionBuilder.java | 3 +- .../dspace/builder/ResourcePolicyBuilder.java | 20 +- .../java/org/dspace/content/BundleTest.java | 6 +- .../java/org/dspace/content/ItemTest.java | 11 +- .../dspace/content/packager/ITDSpaceAIP.java | 11 +- .../dspace/content/service/ItemServiceIT.java | 12 +- .../ResourcePolicyRestRepository.java | 31 +- .../app/rest/BitstreamControllerIT.java | 130 +++--- .../app/rest/BitstreamRestControllerIT.java | 3 +- .../app/rest/BitstreamRestRepositoryIT.java | 13 +- .../app/rest/BundleRestRepositoryIT.java | 2 +- .../app/rest/CollectionRestRepositoryIT.java | 31 +- .../app/rest/CommunityRestRepositoryIT.java | 16 +- .../app/rest/GroupRestRepositoryIT.java | 18 +- ...wningCollectionUpdateRestControllerIT.java | 18 +- .../dspace/app/rest/ItemRestRepositoryIT.java | 3 +- .../rest/ItemTemplateRestControllerIT.java | 12 +- .../rest/ResourcePolicyRestRepositoryIT.java | 425 ++++++++---------- .../app/rest/StatisticsRestRepositoryIT.java | 15 +- .../rest/WorkspaceItemRestRepositoryIT.java | 64 +-- .../authorization/CCLicenseFeatureRestIT.java | 6 +- .../CanManageBitstreamBundlesFeatureIT.java | 20 +- .../CanManageMappingsFeatureIT.java | 9 +- .../authorization/CanSubscribeFeatureIT.java | 5 +- .../rest/authorization/EditItemFeatureIT.java | 12 +- .../GenericAuthorizationFeatureIT.java | 89 ++-- .../ManageAdminGroupFeatureIT.java | 6 +- .../ManageSubmitterGroupFeatureIT.java | 6 +- .../ManageTemplateItemFeatureIT.java | 6 +- .../ManageWorkflowGroupFeatureIT.java | 6 +- .../rest/authorization/SubmitFeatureIT.java | 24 +- 40 files changed, 572 insertions(+), 672 deletions(-) create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql 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 4148232cf3ba..a77d854ade26 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 @@ -1810,7 +1810,7 @@ protected void setPermission(Context c, Group g, int actionID, Bitstream bs) authorizeService.removeAllPolicies(c, bs); // add the policy - ResourcePolicy rp = resourcePolicyService.create(c); + ResourcePolicy rp = resourcePolicyService.create(c, null, g); rp.setdSpaceObject(bs); rp.setAction(actionID); diff --git a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java index fc438c234cda..3f326de3c740 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java @@ -550,13 +550,11 @@ public void addPolicies(Context c, List policies, DSpaceObject d List newPolicies = new ArrayList<>(policies.size()); for (ResourcePolicy srp : policies) { - ResourcePolicy rp = resourcePolicyService.create(c); + ResourcePolicy rp = resourcePolicyService.create(c, srp.getEPerson(), srp.getGroup()); // copy over values rp.setdSpaceObject(dest); rp.setAction(srp.getAction()); - rp.setEPerson(srp.getEPerson()); - rp.setGroup(srp.getGroup()); rp.setStartDate(srp.getStartDate()); rp.setEndDate(srp.getEndDate()); rp.setRpName(srp.getRpName()); @@ -670,11 +668,9 @@ public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Gr "We need at least an eperson or a group in order to create a resource policy."); } - ResourcePolicy myPolicy = resourcePolicyService.create(context); + ResourcePolicy myPolicy = resourcePolicyService.create(context, eperson, group); myPolicy.setdSpaceObject(dso); myPolicy.setAction(type); - myPolicy.setGroup(group); - myPolicy.setEPerson(eperson); myPolicy.setRpType(rpType); myPolicy.setRpName(rpName); myPolicy.setRpDescription(rpDescription); diff --git a/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java b/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java index 61e783920ae5..b430a2635fd9 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java +++ b/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java @@ -126,10 +126,9 @@ private static void addAnonymousPolicy(Context c, DSpaceObject t, // now create the default policies for submitted items ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); - ResourcePolicy myPolicy = resourcePolicyService.create(c); + ResourcePolicy myPolicy = resourcePolicyService.create(c, null, anonymousGroup); myPolicy.setdSpaceObject(t); myPolicy.setAction(myaction); - myPolicy.setGroup(anonymousGroup); resourcePolicyService.update(c, myPolicy); } } diff --git a/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java b/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java index 72998b9fd18a..e22b8e9df026 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java +++ b/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java @@ -229,11 +229,10 @@ public static void setPoliciesFilter(Context c, int containerType, // before create a new policy check if an identical policy is already in place if (!authorizeService.isAnIdenticalPolicyAlreadyInPlace(c, myitem, group, actionID, -1)) { // now add the policy - ResourcePolicy rp = resourcePolicyService.create(c); + ResourcePolicy rp = resourcePolicyService.create(c, null, group); rp.setdSpaceObject(myitem); rp.setAction(actionID); - rp.setGroup(group); rp.setRpName(name); rp.setRpDescription(description); @@ -262,11 +261,10 @@ public static void setPoliciesFilter(Context c, int containerType, // before create a new policy check if an identical policy is already in place if (!authorizeService.isAnIdenticalPolicyAlreadyInPlace(c, bundle, group, actionID, -1)) { // now add the policy - ResourcePolicy rp = resourcePolicyService.create(c); + ResourcePolicy rp = resourcePolicyService.create(c, null, group); rp.setdSpaceObject(bundle); rp.setAction(actionID); - rp.setGroup(group); rp.setRpName(name); rp.setRpDescription(description); @@ -305,11 +303,10 @@ public static void setPoliciesFilter(Context c, int containerType, if (!authorizeService .isAnIdenticalPolicyAlreadyInPlace(c, bitstream, group, actionID, -1)) { // now add the policy - ResourcePolicy rp = resourcePolicyService.create(c); + ResourcePolicy rp = resourcePolicyService.create(c, null, group); rp.setdSpaceObject(bitstream); rp.setAction(actionID); - rp.setGroup(group); rp.setRpName(name); rp.setRpDescription(description); diff --git a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java index b762107a84c5..7b93b912378e 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java @@ -71,14 +71,22 @@ public ResourcePolicy find(Context context, int id) throws SQLException { * Create a new ResourcePolicy * * @param context DSpace context object + * @param ePerson + * @param group * @return ResourcePolicy * @throws SQLException if database error */ @Override - public ResourcePolicy create(Context context) throws SQLException { + public ResourcePolicy create(Context context, EPerson ePerson, Group group) throws SQLException { // FIXME: Check authorisation // Create a table row - ResourcePolicy resourcePolicy = resourcePolicyDAO.create(context, new ResourcePolicy()); + ResourcePolicy policyToBeCreated = new ResourcePolicy(); + if (ePerson == null && group == null) { + throw new IllegalArgumentException("A resource policy must contain a valid eperson or group"); + } + policyToBeCreated.setEPerson(ePerson); + policyToBeCreated.setGroup(group); + ResourcePolicy resourcePolicy = resourcePolicyDAO.create(context, policyToBeCreated); return resourcePolicy; } @@ -205,9 +213,7 @@ public boolean isDateValid(ResourcePolicy resourcePolicy) { @Override public ResourcePolicy clone(Context context, ResourcePolicy resourcePolicy) throws SQLException, AuthorizeException { - ResourcePolicy clone = create(context); - clone.setGroup(resourcePolicy.getGroup()); - clone.setEPerson(resourcePolicy.getEPerson()); + ResourcePolicy clone = create(context, resourcePolicy.getEPerson(), resourcePolicy.getGroup()); clone.setStartDate((Date) ObjectUtils.clone(resourcePolicy.getStartDate())); clone.setEndDate((Date) ObjectUtils.clone(resourcePolicy.getEndDate())); clone.setRpType((String) ObjectUtils.clone(resourcePolicy.getRpType())); diff --git a/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java b/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java index 43735fcd6089..523bd64006d0 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java +++ b/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java @@ -17,7 +17,6 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import org.dspace.service.DSpaceCRUDService; /** * Service interface class for the ResourcePolicy object. @@ -26,7 +25,34 @@ * * @author kevinvandevelde at atmire.com */ -public interface ResourcePolicyService extends DSpaceCRUDService { +public interface ResourcePolicyService { + + public ResourcePolicy create(Context context, EPerson eperson, Group group) throws SQLException, AuthorizeException; + + public ResourcePolicy find(Context context, int id) throws SQLException; + + /** + * Persist a model object. + * + * @param context + * @param resourcePolicy object to be persisted. + * @throws SQLException passed through. + * @throws AuthorizeException passed through. + */ + public void update(Context context, ResourcePolicy resourcePolicy) throws SQLException, AuthorizeException; + + + /** + * Persist a collection of model objects. + * + * @param context + * @param resourcePolicies object to be persisted. + * @throws SQLException passed through. + * @throws AuthorizeException passed through. + */ + public void update(Context context, List resourcePolicies) throws SQLException, AuthorizeException; + + public void delete(Context context, ResourcePolicy resourcePolicy) throws SQLException, AuthorizeException; public List find(Context c, DSpaceObject o) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java index 7f6622841ba7..66a1f334284c 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java @@ -432,31 +432,7 @@ public void ingest(Context context, DSpaceObject dso, List ml, boolean //get what class of context this is String contextClass = element.getAttributeValue("CONTEXTCLASS"); - ResourcePolicy rp = resourcePolicyService.create(context); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - - // get reference to the element - // Note: we are assuming here that there will only ever be ONE - // element. Currently there are no known use cases for multiple. - Element permsElement = element.getChild("Permissions", METSRights_NS); - if (permsElement == null) { - log.error("No element was found. Skipping this element."); - continue; - } - - if (element.getAttributeValue("rpName") != null) { - rp.setRpName(element.getAttributeValue("rpName")); - } - try { - if (element.getAttributeValue("start-date") != null) { - rp.setStartDate(sdf.parse(element.getAttributeValue("start-date"))); - } - if (element.getAttributeValue("end-date") != null) { - rp.setEndDate(sdf.parse(element.getAttributeValue("end-date"))); - } - } catch (ParseException ex) { - log.error("Failed to parse embargo date. The date needs to be in the format 'yyyy-MM-dd'.", ex); - } + ResourcePolicy rp = null; //Check if this permission pertains to Anonymous users if (ANONYMOUS_CONTEXTCLASS.equals(contextClass)) { @@ -464,22 +440,23 @@ public void ingest(Context context, DSpaceObject dso, List ml, boolean Group anonGroup = groupService.findByName(context, Group.ANONYMOUS); if (anonGroup == null) { throw new CrosswalkInternalException( - "The DSpace database has not been properly initialized. The Anonymous Group is " + - "missing from the database."); + "The DSpace database has not been properly initialized. The Anonymous Group is " + + "missing from the database."); } - rp.setGroup(anonGroup); + rp = resourcePolicyService.create(context, null, anonGroup); } else if (ADMIN_CONTEXTCLASS.equals(contextClass)) { // else if this permission declaration pertains to Administrators // get DSpace Administrator group Group adminGroup = groupService.findByName(context, Group.ADMIN); if (adminGroup == null) { throw new CrosswalkInternalException( - "The DSpace database has not been properly initialized. The Administrator Group is " + - "missing from the database."); + "The DSpace database has not been properly initialized. " + + "The Administrator Group is " + + "missing from the database."); } - rp.setGroup(adminGroup); + rp = resourcePolicyService.create(context, null, adminGroup); } else if (GROUP_CONTEXTCLASS.equals(contextClass)) { // else if this permission pertains to another DSpace group try { @@ -498,18 +475,17 @@ public void ingest(Context context, DSpaceObject dso, List ml, boolean //if not found, throw an error -- user should restore group from the SITE AIP if (group == null) { throw new CrosswalkInternalException("Cannot restore Group permissions on object (" - + "type=" + Constants.typeText[dso - .getType()] + ", " - + "handle=" + dso.getHandle() + ", " - + "ID=" + dso.getID() - + "). The Group named '" + groupName + "' is" + - " missing from DSpace. " - + "Please restore this group using the SITE " + - "AIP, or recreate it."); + + "type=" + Constants.typeText[dso.getType()] + ", " + + "handle=" + dso.getHandle() + ", " + + "ID=" + dso.getID() + + "). The Group named '" + groupName + "' is" + + " missing from DSpace. " + + "Please restore this group using the SITE " + + "AIP, or recreate it."); } //assign group to policy - rp.setGroup(group); + rp = resourcePolicyService.create(context, null, group); } catch (PackageException pe) { //A PackageException will only be thrown if translateDefaultGroupName() fails //We'll just wrap it as a CrosswalkException and throw it upwards @@ -535,25 +511,51 @@ public void ingest(Context context, DSpaceObject dso, List ml, boolean //if not found, throw an error -- user should restore person from the SITE AIP if (person == null) { throw new CrosswalkInternalException("Cannot restore Person permissions on object (" - + "type=" + Constants.typeText[dso - .getType()] + ", " - + "handle=" + dso.getHandle() + ", " - + "ID=" + dso.getID() - + "). The Person with email/netid '" + - personEmail + "' is missing from DSpace. " - + "Please restore this Person object using the " + - "SITE AIP, or recreate it."); + + "type=" + Constants.typeText[dso.getType()] + ", " + + "handle=" + dso.getHandle() + ", " + + "ID=" + dso.getID() + + "). The Person with email/netid '" + + personEmail + "' is missing from DSpace. " + + "Please restore this Person object using the " + + "SITE AIP, or recreate it."); } - //assign person to the policy - rp.setEPerson(person); + //create rp with the person + rp = resourcePolicyService.create(context, person, null); } else { log.error("Unrecognized CONTEXTCLASS: " + contextClass); } + if (rp != null) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + + // get reference to the element + // Note: we are assuming here that there will only ever be ONE + // element. Currently there are no known use cases for multiple. + Element permsElement = element.getChild("Permissions", METSRights_NS); + if (permsElement == null) { + log.error("No element was found. Skipping this element."); + continue; + } + + if (element.getAttributeValue("rpName") != null) { + rp.setRpName(element.getAttributeValue("rpName")); + } + try { + if (element.getAttributeValue("start-date") != null) { + rp.setStartDate(sdf.parse(element.getAttributeValue("start-date"))); + } + if (element.getAttributeValue("end-date") != null) { + rp.setEndDate(sdf.parse(element.getAttributeValue("end-date"))); + } + } catch (ParseException ex) { + log.error("Failed to parse embargo date. The date needs to be in the format 'yyyy-MM-dd'.", + ex); + } - //set permissions on policy add to list of policies - rp.setAction(parsePermissions(permsElement)); - policies.add(rp); + //set permissions on policy add to list of policies + rp.setAction(parsePermissions(permsElement)); + policies.add(rp); + } } //end if "Context" element } //end for loop diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql new file mode 100644 index 000000000000..de40d0415dc6 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql @@ -0,0 +1,10 @@ +-- +-- 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/ +-- + +ALTER TABLE ResourcePolicy ADD CONSTRAINT resourcepolicy_eperson_and_epersongroup_not_nullobject_chk + CHECK (eperson_id is not null or epersongroup_id is not null) ; diff --git a/dspace-api/src/test/java/org/dspace/access/status/DefaultAccessStatusHelperTest.java b/dspace-api/src/test/java/org/dspace/access/status/DefaultAccessStatusHelperTest.java index 1134990e84f4..59dfbb2095ea 100644 --- a/dspace-api/src/test/java/org/dspace/access/status/DefaultAccessStatusHelperTest.java +++ b/dspace-api/src/test/java/org/dspace/access/status/DefaultAccessStatusHelperTest.java @@ -261,10 +261,9 @@ public void testWithEmbargo() throws Exception { bitstream.setName(context, "primary"); bundle.setPrimaryBitstreamID(bitstream); List policies = new ArrayList<>(); - ResourcePolicy policy = resourcePolicyService.create(context); - policy.setRpName("Embargo"); Group group = groupService.findByName(context, Group.ANONYMOUS); - policy.setGroup(group); + ResourcePolicy policy = resourcePolicyService.create(context, null, group); + policy.setRpName("Embargo"); policy.setAction(Constants.READ); policy.setStartDate(new LocalDate(9999, 12, 31).toDate()); policies.add(policy); @@ -290,10 +289,9 @@ public void testWithDateRestriction() throws Exception { bitstream.setName(context, "primary"); bundle.setPrimaryBitstreamID(bitstream); List policies = new ArrayList<>(); - ResourcePolicy policy = resourcePolicyService.create(context); - policy.setRpName("Restriction"); Group group = groupService.findByName(context, Group.ANONYMOUS); - policy.setGroup(group); + ResourcePolicy policy = resourcePolicyService.create(context, null, group); + policy.setRpName("Restriction"); policy.setAction(Constants.READ); policy.setStartDate(new LocalDate(10000, 1, 1).toDate()); policies.add(policy); @@ -317,10 +315,9 @@ public void testWithGroupRestriction() throws Exception { bitstream.setName(context, "primary"); bundle.setPrimaryBitstreamID(bitstream); List policies = new ArrayList<>(); - ResourcePolicy policy = resourcePolicyService.create(context); - policy.setRpName("Restriction"); Group group = groupService.findByName(context, Group.ADMIN); - policy.setGroup(group); + ResourcePolicy policy = resourcePolicyService.create(context, null, group); + policy.setRpName("Restriction"); policy.setAction(Constants.READ); policies.add(policy); authorizeService.removeAllPolicies(context, bitstream); @@ -380,10 +377,9 @@ public void testWithPrimaryAndMultipleBitstreams() throws Exception { new ByteArrayInputStream("1".getBytes(StandardCharsets.UTF_8))); bundle.setPrimaryBitstreamID(primaryBitstream); List policies = new ArrayList<>(); - ResourcePolicy policy = resourcePolicyService.create(context); - policy.setRpName("Embargo"); Group group = groupService.findByName(context, Group.ANONYMOUS); - policy.setGroup(group); + ResourcePolicy policy = resourcePolicyService.create(context, null, group); + policy.setRpName("Embargo"); policy.setAction(Constants.READ); policy.setStartDate(new LocalDate(9999, 12, 31).toDate()); policies.add(policy); @@ -411,10 +407,9 @@ public void testWithNoPrimaryAndMultipleBitstreams() throws Exception { Bitstream anotherBitstream = bitstreamService.create(context, bundle, new ByteArrayInputStream("1".getBytes(StandardCharsets.UTF_8))); List policies = new ArrayList<>(); - ResourcePolicy policy = resourcePolicyService.create(context); - policy.setRpName("Embargo"); Group group = groupService.findByName(context, Group.ANONYMOUS); - policy.setGroup(group); + ResourcePolicy policy = resourcePolicyService.create(context, null, group); + policy.setRpName("Embargo"); policy.setAction(Constants.READ); policy.setStartDate(new LocalDate(9999, 12, 31).toDate()); policies.add(policy); diff --git a/dspace-api/src/test/java/org/dspace/builder/CollectionBuilder.java b/dspace-api/src/test/java/org/dspace/builder/CollectionBuilder.java index f287c7aa8d32..74d745c07c75 100644 --- a/dspace-api/src/test/java/org/dspace/builder/CollectionBuilder.java +++ b/dspace-api/src/test/java/org/dspace/builder/CollectionBuilder.java @@ -253,8 +253,7 @@ public CollectionBuilder withAdminGroup(EPerson... members) throws SQLException, public CollectionBuilder withDefaultItemRead(Group group) throws SQLException, AuthorizeException { resourcePolicyService.removePolicies(context, collection, DEFAULT_ITEM_READ); - ResourcePolicy resourcePolicy = resourcePolicyService.create(context); - resourcePolicy.setGroup(group); + ResourcePolicy resourcePolicy = resourcePolicyService.create(context, null, group); resourcePolicy.setAction(DEFAULT_ITEM_READ); resourcePolicy.setdSpaceObject(collection); resourcePolicyService.update(context, resourcePolicy); diff --git a/dspace-api/src/test/java/org/dspace/builder/ResourcePolicyBuilder.java b/dspace-api/src/test/java/org/dspace/builder/ResourcePolicyBuilder.java index 70b1f8d73daf..c3b1b658ee1c 100644 --- a/dspace-api/src/test/java/org/dspace/builder/ResourcePolicyBuilder.java +++ b/dspace-api/src/test/java/org/dspace/builder/ResourcePolicyBuilder.java @@ -110,31 +110,23 @@ public static void delete(Integer id) indexingService.commit(); } - public static ResourcePolicyBuilder createResourcePolicy(Context context) + public static ResourcePolicyBuilder createResourcePolicy(Context context, EPerson ePerson, + Group group) throws SQLException, AuthorizeException { ResourcePolicyBuilder resourcePolicyBuilder = new ResourcePolicyBuilder(context); - return resourcePolicyBuilder.create(context); + return resourcePolicyBuilder.create(context, ePerson, group); } - private ResourcePolicyBuilder create(Context context) + private ResourcePolicyBuilder create(Context context, final EPerson ePerson, + final Group epersonGroup) throws SQLException, AuthorizeException { this.context = context; - resourcePolicy = resourcePolicyService.create(context); + resourcePolicy = resourcePolicyService.create(context, ePerson, epersonGroup); return this; } - public ResourcePolicyBuilder withUser(EPerson ePerson) throws SQLException { - resourcePolicy.setEPerson(ePerson); - return this; - } - - public ResourcePolicyBuilder withGroup(Group epersonGroup) throws SQLException { - resourcePolicy.setGroup(epersonGroup); - return this; - } - public ResourcePolicyBuilder withAction(int action) throws SQLException { resourcePolicy.setAction(action); return this; diff --git a/dspace-api/src/test/java/org/dspace/content/BundleTest.java b/dspace-api/src/test/java/org/dspace/content/BundleTest.java index 4ff35f5b4df8..e8ff69c47bed 100644 --- a/dspace-api/src/test/java/org/dspace/content/BundleTest.java +++ b/dspace-api/src/test/java/org/dspace/content/BundleTest.java @@ -598,9 +598,9 @@ public void testInheritCollectionDefaultPolicies() throws AuthorizeException, SQ @Test public void testReplaceAllBitstreamPolicies() throws SQLException, AuthorizeException { List newpolicies = new ArrayList(); - newpolicies.add(resourcePolicyService.create(context)); - newpolicies.add(resourcePolicyService.create(context)); - newpolicies.add(resourcePolicyService.create(context)); + newpolicies.add(resourcePolicyService.create(context, eperson, null)); + newpolicies.add(resourcePolicyService.create(context, eperson, null)); + newpolicies.add(resourcePolicyService.create(context, eperson, null)); bundleService.replaceAllBitstreamPolicies(context, b, newpolicies); List bspolicies = bundleService.getBundlePolicies(context, b); diff --git a/dspace-api/src/test/java/org/dspace/content/ItemTest.java b/dspace-api/src/test/java/org/dspace/content/ItemTest.java index d440597ec416..ada9bbc15905 100644 --- a/dspace-api/src/test/java/org/dspace/content/ItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/ItemTest.java @@ -1257,7 +1257,7 @@ public void testGetType() { @Test public void testReplaceAllItemPolicies() throws Exception { List newpolicies = new ArrayList(); - ResourcePolicy pol1 = resourcePolicyService.create(context); + ResourcePolicy pol1 = resourcePolicyService.create(context, eperson, null); newpolicies.add(pol1); itemService.replaceAllItemPolicies(context, it, newpolicies); @@ -1284,9 +1284,9 @@ public void testReplaceAllBitstreamPolicies() throws Exception { bundleService.addBitstream(context, created, result); List newpolicies = new ArrayList(); - newpolicies.add(resourcePolicyService.create(context)); - newpolicies.add(resourcePolicyService.create(context)); - newpolicies.add(resourcePolicyService.create(context)); + newpolicies.add(resourcePolicyService.create(context, eperson, null)); + newpolicies.add(resourcePolicyService.create(context, eperson, null)); + newpolicies.add(resourcePolicyService.create(context, eperson, null)); context.restoreAuthSystemState(); itemService.replaceAllBitstreamPolicies(context, it, newpolicies); @@ -1316,9 +1316,8 @@ public void testRemoveGroupPolicies() throws Exception { context.turnOffAuthorisationSystem(); List newpolicies = new ArrayList(); Group g = groupService.create(context); - ResourcePolicy pol1 = resourcePolicyService.create(context); + ResourcePolicy pol1 = resourcePolicyService.create(context, null, g); newpolicies.add(pol1); - pol1.setGroup(g); itemService.replaceAllItemPolicies(context, it, newpolicies); itemService.removeGroupPolicies(context, it, g); diff --git a/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java b/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java index a634b98130a6..c5a73ed539a7 100644 --- a/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java +++ b/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java @@ -386,9 +386,8 @@ public void testRestoreRestrictedCommunity() throws Exception { // Create a custom resource policy for this community List policies = new ArrayList<>(); - ResourcePolicy policy = resourcePolicyService.create(context); + ResourcePolicy policy = resourcePolicyService.create(context, null, group); policy.setRpName("Special Read Only"); - policy.setGroup(group); policy.setAction(Constants.READ); policies.add(policy); @@ -600,9 +599,8 @@ public void testRestoreRestrictedCollection() throws Exception { // Create a custom resource policy for this Collection List policies = new ArrayList<>(); - ResourcePolicy policy = resourcePolicyService.create(context); + ResourcePolicy policy = resourcePolicyService.create(context, null, group); policy.setRpName("Special Read Only"); - policy.setGroup(group); policy.setAction(Constants.READ); policies.add(policy); @@ -822,10 +820,9 @@ public void testRestoreRestrictedItem() throws Exception { // Create a custom resource policy for this Item List policies = new ArrayList<>(); - ResourcePolicy admin_policy = resourcePolicyService.create(context); - admin_policy.setRpName("Admin Read-Only"); Group adminGroup = groupService.findByName(context, Group.ADMIN); - admin_policy.setGroup(adminGroup); + ResourcePolicy admin_policy = resourcePolicyService.create(context, null, adminGroup); + admin_policy.setRpName("Admin Read-Only"); admin_policy.setAction(Constants.READ); policies.add(admin_policy); itemService.replaceAllItemPolicies(context, item, policies); diff --git a/dspace-api/src/test/java/org/dspace/content/service/ItemServiceIT.java b/dspace-api/src/test/java/org/dspace/content/service/ItemServiceIT.java index e40577ef36ea..e825acdad894 100644 --- a/dspace-api/src/test/java/org/dspace/content/service/ItemServiceIT.java +++ b/dspace-api/src/test/java/org/dspace/content/service/ItemServiceIT.java @@ -668,8 +668,7 @@ public void testFindItemsWithEditNoRights() throws Exception { @Test public void testFindAndCountItemsWithEditEPerson() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(item) .withAction(Constants.WRITE) .build(); @@ -682,8 +681,7 @@ public void testFindAndCountItemsWithEditEPerson() throws Exception { @Test public void testFindAndCountItemsWithAdminEPerson() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(item) .withAction(Constants.ADMIN) .build(); @@ -702,8 +700,7 @@ public void testFindAndCountItemsWithEditGroup() throws Exception { .build(); context.restoreAuthSystemState(); - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withGroup(group) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(item) .withAction(Constants.WRITE) .build(); @@ -722,8 +719,7 @@ public void testFindAndCountItemsWithAdminGroup() throws Exception { .build(); context.restoreAuthSystemState(); - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withGroup(group) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(item) .withAction(Constants.ADMIN) .build(); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ResourcePolicyRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ResourcePolicyRestRepository.java index 0b77f96b9b5f..a79a9fe4eaa4 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ResourcePolicyRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ResourcePolicyRestRepository.java @@ -254,14 +254,6 @@ protected ResourcePolicyRest createAndReturn(Context context) throws AuthorizeEx if (dspaceObject == null) { throw new UnprocessableEntityException("DSpaceObject with this uuid: " + resourceUuid + " not found"); } - resourcePolicy = resourcePolicyService.create(context); - resourcePolicy.setRpType(resourcePolicyRest.getPolicyType()); - resourcePolicy.setdSpaceObject(dspaceObject); - resourcePolicy.setRpName(resourcePolicyRest.getName()); - resourcePolicy.setRpDescription(resourcePolicyRest.getDescription()); - resourcePolicy.setAction(Constants.getActionID(resourcePolicyRest.getAction())); - resourcePolicy.setStartDate(resourcePolicyRest.getStartDate()); - resourcePolicy.setEndDate(resourcePolicyRest.getEndDate()); if (epersonUuidStr != null) { try { @@ -270,12 +262,11 @@ protected ResourcePolicyRest createAndReturn(Context context) throws AuthorizeEx if (ePerson == null) { throw new UnprocessableEntityException("EPerson with uuid: " + epersonUuid + " not found"); } - resourcePolicy.setEPerson(ePerson); - resourcePolicyService.update(context, resourcePolicy); + resourcePolicy = resourcePolicyService.create(context, ePerson, null); + } catch (SQLException excSQL) { throw new RuntimeException(excSQL.getMessage(), excSQL); } - return converter.toRest(resourcePolicy, utils.obtainProjection()); } else { try { UUID groupUuid = UUID.fromString(groupUuidStr); @@ -283,13 +274,27 @@ protected ResourcePolicyRest createAndReturn(Context context) throws AuthorizeEx if (group == null) { throw new UnprocessableEntityException("Group with uuid: " + groupUuid + " not found"); } - resourcePolicy.setGroup(group); - resourcePolicyService.update(context, resourcePolicy); + resourcePolicy = resourcePolicyService.create(context, null, group); } catch (SQLException excSQL) { throw new RuntimeException(excSQL.getMessage(), excSQL); } + } + + if (resourcePolicy != null) { + + resourcePolicy.setRpType(resourcePolicyRest.getPolicyType()); + resourcePolicy.setdSpaceObject(dspaceObject); + resourcePolicy.setRpName(resourcePolicyRest.getName()); + resourcePolicy.setRpDescription(resourcePolicyRest.getDescription()); + resourcePolicy.setAction(Constants.getActionID(resourcePolicyRest.getAction())); + resourcePolicy.setStartDate(resourcePolicyRest.getStartDate()); + resourcePolicy.setEndDate(resourcePolicyRest.getEndDate()); + resourcePolicyService.update(context, resourcePolicy); return converter.toRest(resourcePolicy, utils.obtainProjection()); + } else { + throw new UnprocessableEntityException("A resource policy must contain a valid eperson or group"); } + } @Override diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamControllerIT.java index a326d195c2a0..c31bb61f060e 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamControllerIT.java @@ -302,25 +302,25 @@ public void putOnBitstreamInOneBundle() throws Exception { .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -471,31 +471,31 @@ public void putOnBitstreamInMultipleBundles() throws Exception { .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle2).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle2).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -592,25 +592,25 @@ public void putOnBitstreamInNoBundle() throws Exception { .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -708,22 +708,22 @@ public void putOnBitstreamInOneBundleWithNoRemoveRights() throws Exception { .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -810,22 +810,22 @@ public void putOnBitstreamInOneBundleWithNoWriteOnCurrentBundleRights() throws E .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -913,22 +913,22 @@ public void putOnBitstreamInOneBundleWithNoWriteRightsOnTargetBundle() throws Ex .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -1015,22 +1015,22 @@ public void putOnBitstreamInOneBundleWithNoAddRightsOnTargetBundle() throws Exce .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -1117,22 +1117,22 @@ public void putOnBitstreamInOneBundleWithNoWriteRightsOnBitstream() throws Excep .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -1220,22 +1220,22 @@ public void putOnBitstreamInOneBundleWithNoWriteRightsOnCurrentItem() throws Exc .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetItem).build(); @@ -1322,22 +1322,22 @@ public void putOnBitstreamInOneBundleWithNoWriteRightsOnTargetItem() throws Exce .withPassword("test") .withNameInMetadata("Bundle", "Put").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.REMOVE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bundle1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.ADD) .withDspaceObject(targetBundle).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(bitstream).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson) + ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java index 4813cc659694..d2223e6baa7a 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java @@ -1086,8 +1086,7 @@ public void updateBitstreamFormatEPerson() throws Exception { context.turnOffAuthorisationSystem(); - createResourcePolicy(context) - .withUser(eperson) + createResourcePolicy(context, eperson, null) .withAction(WRITE) .withDspaceObject(bitstream) .build(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java index 8b34edb938a6..104b73a8cbab 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java @@ -644,7 +644,7 @@ public void findOneBitstreamTest_EmbargoedBitstream_ePersonREADRightsOnBundle() // Replace anon read policy on bundle of bitstream with ePerson READ policy resourcePolicyService.removePolicies(context, bitstream.getBundles().get(0), Constants.READ); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(bitstream.getBundles().get(0)).build(); @@ -707,9 +707,9 @@ public void findOneBitstreamFormatTest_EmbargoedBitstream_ePersonREADRightsOnBun // Replace anon read policy on bundle of bitstream with ePerson READ policy resourcePolicyService.removePolicies(context, bitstream.getBundles().get(0), Constants.READ); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson) - .withAction(Constants.READ) - .withDspaceObject(bitstream.getBundles().get(0)).build(); + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) + .withAction(Constants.READ) + .withDspaceObject(bitstream.getBundles().get(0)).build(); context.restoreAuthSystemState(); @@ -832,7 +832,7 @@ public void findOneBitstreamTest_EmbargoedBitstream_ePersonREADRightsOnItem() th // Replace anon read policy on item of bitstream with ePerson READ policy resourcePolicyService.removePolicies(context, publicItem1, Constants.READ); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(publicItem1).build(); @@ -1480,8 +1480,7 @@ public void testHiddenMetadataForUserWithWriteRights() throws Exception { .build(); } - ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(WRITE) .withDspaceObject(col1) .build(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BundleRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BundleRestRepositoryIT.java index 259580f8c081..6b148e88e132 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BundleRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BundleRestRepositoryIT.java @@ -347,7 +347,7 @@ public void createBundleWithSufficientPermissions() throws Exception { .withPassword("test") .withNameInMetadata("Create", "Bundle").build(); - ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(createBundleEperson) + ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context, createBundleEperson, null) .withAction(Constants.ADD) .withDspaceObject(item).build(); context.restoreAuthSystemState(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java index ee522db170c7..014a31c50112 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java @@ -1811,8 +1811,7 @@ public void testHiddenMetadataForUserWithWriteRights() throws Exception { - ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(WRITE) .withDspaceObject(col1) .build(); @@ -2894,11 +2893,10 @@ public void testSubGroupOfCommunityAdminGroupAuthorizedSearch() throws Exception communityC = CommunityBuilder.createCommunity(context) .withName("the last community is topLevelCommunityC") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COMMUNITY_" + + topLevelCommunityA.getID() + "_ADMIN")) .withDspaceObject(communityB) - .withAction(Constants.ADMIN) - .withGroup(groupService.findByName(context, "COMMUNITY_" + topLevelCommunityA.getID() + "_ADMIN")) - .build(); + .withAction(Constants.ADMIN).build(); collectionB = CollectionBuilder.createCollection(context, subCommunityA) .withName("collectionB is a very original name") .build(); @@ -2950,11 +2948,10 @@ public void testSubGroupOfSubCommunityAdminGroupAuthorizedSearch() throws Except .withName("the last community is topLevelCommunityC") .addParentCommunity(context, topLevelCommunityA) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COMMUNITY_" + + subCommunityA.getID() + "_ADMIN")) .withDspaceObject(communityB) - .withAction(Constants.ADMIN) - .withGroup(groupService.findByName(context, "COMMUNITY_" + subCommunityA.getID() + "_ADMIN")) - .build(); + .withAction(Constants.ADMIN).build(); collectionB = CollectionBuilder.createCollection(context, subCommunityA) .withName("collectionB is a very original name") .build(); @@ -3012,11 +3009,10 @@ public void testSubGroupOfCollectionAdminGroupAuthorizedSearch() throws Exceptio collectionC = CollectionBuilder.createCollection(context, communityC) .withName("the last collection is collectionC") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COLLECTION_" + + collectionA.getID() + "_ADMIN")) .withDspaceObject(collectionB) - .withAction(Constants.ADMIN) - .withGroup(groupService.findByName(context, "COLLECTION_" + collectionA.getID() + "_ADMIN")) - .build(); + .withAction(Constants.ADMIN).build(); context.restoreAuthSystemState(); String token = getAuthToken(eperson.getEmail(), password); @@ -3065,11 +3061,10 @@ public void testSubGroupOfSubmitterGroupAuthorizedSearch() throws Exception { collectionB = CollectionBuilder.createCollection(context, communityB) .withName("collectionB is a very original name") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COLLECTION_" + + collectionA.getID() + "_SUBMIT")) .withDspaceObject(collectionB) - .withAction(Constants.ADD) - .withGroup(groupService.findByName(context, "COLLECTION_" + collectionA.getID() + "_SUBMIT")) - .build(); + .withAction(Constants.ADD).build(); collectionC = CollectionBuilder.createCollection(context, communityC) .withName("the last collection is collectionC") .build(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java index 30614e6125f2..22e62c24168a 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java @@ -2370,10 +2370,10 @@ public void testSubGroupOfCommunityAdminGroupAuthorizedSearch() throws Exception communityC = CommunityBuilder.createCommunity(context) .withName("the last community is topLevelCommunityC") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COMMUNITY_" + + topLevelCommunityA.getID() + "_ADMIN")) .withDspaceObject(communityB) .withAction(Constants.ADMIN) - .withGroup(groupService.findByName(context, "COMMUNITY_" + topLevelCommunityA.getID() + "_ADMIN")) .build(); context.restoreAuthSystemState(); @@ -2423,10 +2423,10 @@ public void testSubGroupOfSubCommunityAdminGroupAuthorizedSearch() throws Except .withName("the last community is topLevelCommunityC") .addParentCommunity(context, topLevelCommunityA) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COMMUNITY_" + + subCommunityA.getID() + "_ADMIN")) .withDspaceObject(communityB) .withAction(Constants.ADMIN) - .withGroup(groupService.findByName(context, "COMMUNITY_" + subCommunityA.getID() + "_ADMIN")) .build(); context.restoreAuthSystemState(); @@ -2473,10 +2473,10 @@ public void testSubGroupOfCollectionAdminGroupAuthorizedSearch() throws Exceptio Collection collectionB = CollectionBuilder.createCollection(context, communityB) .withName("collectionB") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COLLECTION_" + + collectionA.getID() + "_ADMIN")) .withDspaceObject(collectionB) .withAction(Constants.ADMIN) - .withGroup(groupService.findByName(context, "COLLECTION_" + collectionA.getID() + "_ADMIN")) .build(); communityC = CommunityBuilder.createCommunity(context) .withName("the last community is topLevelCommunityC") @@ -2521,10 +2521,10 @@ public void testSubGroupOfSubmitterGroupAuthorizedSearch() throws Exception { Collection collectionB = CollectionBuilder.createCollection(context, communityB) .withName("collectionB") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COLLECTION_" + + collectionA.getID() + "_SUBMIT")) .withDspaceObject(collectionB) .withAction(Constants.ADD) - .withGroup(groupService.findByName(context, "COLLECTION_" + collectionA.getID() + "_SUBMIT")) .build(); communityC = CommunityBuilder.createCommunity(context) .withName("the last community is topLevelCommunityC") diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java index fda8b15effa3..ef4bfa2ac591 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java @@ -3124,10 +3124,10 @@ public void commAdminAndColAdminCannotExploitItemReadGroupTest() throws Exceptio .build(); Group adminGroup = groupService.findByName(context, Group.ADMIN); - ResourcePolicyBuilder.createResourcePolicy(context).withAction(Constants.DEFAULT_ITEM_READ) - .withGroup(adminGroup).withDspaceObject(child1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withAction(Constants.DEFAULT_ITEM_READ) - .withGroup(adminGroup).withDspaceObject(col1).build(); + ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup).withAction(Constants.DEFAULT_ITEM_READ) + .withDspaceObject(child1).build(); + ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup).withAction(Constants.DEFAULT_ITEM_READ) + .withDspaceObject(col1).build(); context.restoreAuthSystemState(); String tokenAdminComm = getAuthToken(adminChild1.getEmail(), password); @@ -3187,10 +3187,12 @@ public void commAdminAndColAdminCannotExpoloitBitstreamReadGroupTest() throws Ex .build(); Group adminGroup = groupService.findByName(context, Group.ADMIN); - ResourcePolicyBuilder.createResourcePolicy(context).withAction(Constants.DEFAULT_BITSTREAM_READ) - .withGroup(adminGroup).withDspaceObject(child1).build(); - ResourcePolicyBuilder.createResourcePolicy(context).withAction(Constants.DEFAULT_BITSTREAM_READ) - .withGroup(adminGroup).withDspaceObject(col1).build(); + ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) + .withAction(Constants.DEFAULT_BITSTREAM_READ) + .withDspaceObject(child1).build(); + ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) + .withAction(Constants.DEFAULT_BITSTREAM_READ) + .withDspaceObject(col1).build(); context.restoreAuthSystemState(); String tokenAdminComm = getAuthToken(adminChild1.getEmail(), password); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemOwningCollectionUpdateRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemOwningCollectionUpdateRestControllerIT.java index 73c2c8a3fe59..7d2d1d901ec7 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemOwningCollectionUpdateRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemOwningCollectionUpdateRestControllerIT.java @@ -131,13 +131,13 @@ public void moveItemTestByMinimallyAuthorizedUser() throws Exception { EPerson itemMoveEperson = EPersonBuilder.createEPerson(context).withEmail("item@move.org").withPassword("test") .withNameInMetadata("Item", "Move").build(); - ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.ADMIN) .withDspaceObject(col1).build(); - ResourcePolicy rp2 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp2 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicy rp3 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp3 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.ADD) .withDspaceObject(col2).build(); @@ -181,10 +181,10 @@ public void moveItemTestByAuthorizedUserWithoutAdd() throws Exception { EPerson itemMoveEperson = EPersonBuilder.createEPerson(context).withEmail("item@move.org").withPassword("test") .withNameInMetadata("Item", "Move").build(); - ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.ADMIN) .withDspaceObject(col1).build(); - ResourcePolicy rp2 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp2 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); @@ -222,10 +222,10 @@ public void moveItemTestByAuthorizedUserWithoutAdmin() throws Exception { EPerson itemMoveEperson = EPersonBuilder.createEPerson(context).withEmail("item@move.org").withPassword("test") .withNameInMetadata("Item", "Move").build(); - ResourcePolicy rp2 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp2 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.WRITE) .withDspaceObject(publicItem1).build(); - ResourcePolicy rp3 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp3 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.ADD) .withDspaceObject(col2).build(); @@ -263,10 +263,10 @@ public void moveItemTestByAuthorizedUserWithoutWrite() throws Exception { EPerson itemMoveEperson = EPersonBuilder.createEPerson(context).withEmail("item@move.org").withPassword("test") .withNameInMetadata("Item", "Move").build(); - ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.ADMIN) .withDspaceObject(col1).build(); - ResourcePolicy rp3 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(itemMoveEperson) + ResourcePolicy rp3 = ResourcePolicyBuilder.createResourcePolicy(context, itemMoveEperson, null) .withAction(Constants.ADD) .withDspaceObject(col2).build(); 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 801976be9f0d..7558f321e583 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 @@ -3012,8 +3012,7 @@ public void testHiddenMetadataForUserWithWriteRights() throws Exception { context.restoreAuthSystemState(); - ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(WRITE) .withDspaceObject(item) .build(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemTemplateRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemTemplateRestControllerIT.java index 1fd9e81ca88d..f3ba6d3aed1f 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemTemplateRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemTemplateRestControllerIT.java @@ -253,9 +253,9 @@ public void patchTemplateItemAsCollectionAdmin() throws Exception { String itemId = installTestTemplate(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson) - .withAction(Constants.ADMIN) - .withDspaceObject(childCollection).build(); + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) + .withAction(Constants.ADMIN) + .withDspaceObject(childCollection).build(); String collAdminToken = getAuthToken(eperson.getEmail(), password); getClient(collAdminToken).perform(patch(getTemplateItemUrlTemplate(itemId)) @@ -374,9 +374,9 @@ public void deleteTemplateItemAsCollectionAdmin() throws Exception { setupTestTemplate(); String itemId = installTestTemplate(); - ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson) - .withAction(Constants.ADMIN) - .withDspaceObject(childCollection).build(); + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) + .withAction(Constants.ADMIN) + .withDspaceObject(childCollection).build(); String collAdminToken = getAuthToken(eperson.getEmail(), password); getClient(collAdminToken).perform(delete(getTemplateItemUrlTemplate(itemId))) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ResourcePolicyRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ResourcePolicyRestRepositoryIT.java index 02834607113d..e7d2634525d3 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ResourcePolicyRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ResourcePolicyRestRepositoryIT.java @@ -80,8 +80,10 @@ public void findAllTest() throws Exception { context.turnOffAuthorisationSystem(); Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withDspaceObject(community).withAction(Constants.READ) - .withUser(admin).build(); + ResourcePolicyBuilder.createResourcePolicy(context, admin, null) + .withDspaceObject(community) + .withAction(Constants.READ) + .build(); context.restoreAuthSystemState(); String authToken = getAuthToken(admin.getEmail(), password); @@ -94,8 +96,10 @@ public void findAllUnAuthenticatedTest() throws Exception { context.turnOffAuthorisationSystem(); Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicyBuilder.createResourcePolicy(context).withDspaceObject(community).withAction(Constants.READ) - .withUser(admin).build(); + ResourcePolicyBuilder.createResourcePolicy(context, admin, null) + .withDspaceObject(community) + .withAction(Constants.READ) + .build(); context.restoreAuthSystemState(); getClient().perform(get("/api/authz/resourcepolicies")).andExpect(status().isUnauthorized()); @@ -112,10 +116,9 @@ public void findOneTest() throws Exception { Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) .withAction(Constants.READ) - .withUser(eperson1) .build(); context.restoreAuthSystemState(); @@ -144,10 +147,9 @@ public void findOneResourcePolicyOfAnonymousGroupTest() throws Exception { Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, groupAnonymous) .withDspaceObject(community) .withAction(Constants.READ) - .withGroup(groupAnonymous) .build(); context.restoreAuthSystemState(); @@ -165,8 +167,10 @@ public void findOneUnAuthenticatedTest() throws Exception { context.turnOffAuthorisationSystem(); Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context).withDspaceObject(community) - .withAction(Constants.READ).withUser(eperson).build(); + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) + .withDspaceObject(community) + .withAction(Constants.READ) + .build(); context.restoreAuthSystemState(); @@ -201,10 +205,9 @@ public void findOneForbiddenTest() throws Exception { Collection collection = CollectionBuilder.createCollection(context, community) .withName("My collection").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(collection) - .withAction(Constants.WRITE) - .withUser(eperson1).build(); + .withAction(Constants.WRITE).build(); context.restoreAuthSystemState(); @@ -228,10 +231,9 @@ public void findOneAccessGrantToAdminTest() throws Exception { Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) - .withAction(Constants.WRITE) - .withUser(eperson1).build(); + .withAction(Constants.WRITE).build(); context.restoreAuthSystemState(); @@ -262,10 +264,9 @@ public void findOneAccessGrantToSameUserTest() throws Exception { Collection collection = CollectionBuilder.createCollection(context, community) .withName("My collection").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(collection) .withAction(Constants.ADD) - .withGroup(group1) .build(); context.restoreAuthSystemState(); @@ -297,15 +298,13 @@ public void findOneResoucesPolicyByEpersonUuidTest() throws Exception { Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); Community community2 = CommunityBuilder.createCommunity(context).withName("My community_2").build(); - ResourcePolicy resourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) - .withAction(Constants.ADD) - .withUser(eperson1).build(); + .withAction(Constants.ADD).build(); - ResourcePolicy resourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context, eperson2, null) .withDspaceObject(community2) - .withAction(Constants.REMOVE) - .withUser(eperson2).build(); + .withAction(Constants.REMOVE).build(); context.restoreAuthSystemState(); @@ -336,20 +335,18 @@ public void findResoucesPoliciesByEpersonUuidAndResourceUuidTest() throws Except Collection collection = CollectionBuilder.createCollection(context, community).withName("My collection") .build(); - ResourcePolicy resourcePolicyOfCommunity = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfCommunity = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) - .withAction(Constants.READ) - .withUser(eperson1).build(); + .withAction(Constants.READ).build(); - ResourcePolicy secondResourcePolicyOfCommunity = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community) - .withAction(Constants.REMOVE) - .withUser(eperson1).build(); + ResourcePolicy secondResourcePolicyOfCommunity = ResourcePolicyBuilder + .createResourcePolicy(context, eperson1, null) + .withDspaceObject(community) + .withAction(Constants.REMOVE).build(); - ResourcePolicy resourcePolicyOfCollection = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfCollection = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(collection) - .withAction(Constants.REMOVE) - .withUser(eperson1).build(); + .withAction(Constants.REMOVE).build(); context.restoreAuthSystemState(); @@ -395,10 +392,9 @@ public void findResoucesPoliciesByEPersonUuidUnAuthenticatedTest() throws Except Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) - .withAction(Constants.READ) - .withUser(eperson1).build(); + .withAction(Constants.READ).build(); context.restoreAuthSystemState(); @@ -437,15 +433,13 @@ public void findResourcesPoliciesByEPersonUuidForbiddenTest() throws Exception { Community community2 = CommunityBuilder.createCommunity(context).withName("My 2 community").build(); - ResourcePolicy resourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community).withAction(Constants.WRITE) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson1).build(); + .withPolicyType(ResourcePolicy.TYPE_CUSTOM).build(); - ResourcePolicy resourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context, eperson2, null) .withDspaceObject(community2).withAction(Constants.ADD) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson2).build(); + .withPolicyType(ResourcePolicy.TYPE_CUSTOM).build(); context.restoreAuthSystemState(); @@ -474,16 +468,18 @@ public void findResourcePoliciesOfOneResourceWithoutActionTest() throws Exceptio Community community2 = CommunityBuilder.createCommunity(context).withName("My second community").build(); - ResourcePolicy firstResourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community) - .withAction(Constants.ADMIN) - .withUser(eperson1).build(); + ResourcePolicy firstResourcePolicyOfEPerson1 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson1, null) + .withDspaceObject(community) + .withAction(Constants.ADMIN) + .build(); - ResourcePolicy firstResourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community2) - .withAction(Constants.ADD) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson2).build(); + ResourcePolicy firstResourcePolicyOfEPerson2 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson2, null) + .withDspaceObject(community2) + .withAction(Constants.ADD) + .withPolicyType(ResourcePolicy.TYPE_CUSTOM) + .build(); ResourcePolicy resourcePolicyAnonymous = authorizeService .findByTypeGroupAction(context, community, EPersonServiceFactory.getInstance() @@ -528,20 +524,23 @@ public void findResourcePoliciesOfOneResourceWithActionTest() throws Exception { Community community2 = CommunityBuilder.createCommunity(context).withName("My 2 community").build(); - ResourcePolicy firstResourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community) - .withAction(Constants.ADMIN) - .withUser(eperson1).build(); + ResourcePolicy firstResourcePolicyOfEPerson1 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson1, null) + .withDspaceObject(community) + .withAction(Constants.ADMIN) + .build(); - ResourcePolicy firstResourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community) - .withAction(Constants.ADD) - .withUser(eperson2).build(); + ResourcePolicy firstResourcePolicyOfEPerson2 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson2, null) + .withDspaceObject(community) + .withAction(Constants.ADD) + .build(); - ResourcePolicy secondResourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community2) - .withAction(Constants.ADD) - .withUser(eperson2).build(); + ResourcePolicy secondResourcePolicyOfEPerson2 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson2, null) + .withDspaceObject(community2) + .withAction(Constants.ADD) + .build(); context.restoreAuthSystemState(); @@ -592,28 +591,32 @@ public void findResourcePoliciesOfOneResourcePaginationTest() throws Exception { Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy firstResourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community) - .withAction(Constants.ADMIN) - .withUser(eperson1).build(); + ResourcePolicy firstResourcePolicyOfEPerson1 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson1, null) + .withDspaceObject(community) + .withAction(Constants.ADMIN) + .build(); - ResourcePolicy firstResourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community) - .withAction(Constants.ADD) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson2).build(); + ResourcePolicy firstResourcePolicyOfEPerson2 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson2, null) + .withDspaceObject(community) + .withAction(Constants.ADD) + .withPolicyType(ResourcePolicy.TYPE_CUSTOM) + .build(); - ResourcePolicy firstResourcePolicyOfEPerson3 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community) - .withAction(Constants.DELETE) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson3).build(); + ResourcePolicy firstResourcePolicyOfEPerson3 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson3, null) + .withDspaceObject(community) + .withAction(Constants.DELETE) + .withPolicyType(ResourcePolicy.TYPE_CUSTOM) + .build(); - ResourcePolicy firstResourcePolicyOfEPerson4 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy firstResourcePolicyOfEPerson4 = ResourcePolicyBuilder + .createResourcePolicy(context, eperson4, null) .withDspaceObject(community) .withAction(Constants.WRITE) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson4).build(); + .build(); ResourcePolicy resourcePolicyAnonymous = authorizeService .findByTypeGroupAction(context, community, EPersonServiceFactory.getInstance() @@ -701,10 +704,9 @@ public void findResoucesPoliciesByResourceUuidUnAuthenticatedTest() throws Excep Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) - .withAction(Constants.READ) - .withUser(eperson1).build(); + .withAction(Constants.READ).build(); context.restoreAuthSystemState(); @@ -742,17 +744,15 @@ public void findResourcesPoliciesByResourceUuidForbiddenTest() throws Exception Community community2 = CommunityBuilder.createCommunity(context).withName("My 2 community").build(); - ResourcePolicy resourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfEPerson1 = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) .withAction(Constants.REMOVE) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson1).build(); + .withPolicyType(ResourcePolicy.TYPE_CUSTOM).build(); - ResourcePolicy resourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfEPerson2 = ResourcePolicyBuilder.createResourcePolicy(context, eperson2, null) .withDspaceObject(community2) .withAction(Constants.ADD) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson2).build(); + .withPolicyType(ResourcePolicy.TYPE_CUSTOM).build(); context.restoreAuthSystemState(); @@ -791,25 +791,22 @@ public void findResourcePoliciesByGroupUuidTest() throws Exception { .withName("My collection") .build(); - ResourcePolicy firstResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy firstResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community) - .withAction(Constants.ADD) - .withGroup(group1).build(); + .withAction(Constants.ADD).build(); - ResourcePolicy secondResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy secondResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community) - .withAction(Constants.READ) - .withGroup(group1).build(); + .withAction(Constants.READ).build(); - ResourcePolicy collectionResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(collection) - .withAction(Constants.WRITE) - .withGroup(group1).build(); + ResourcePolicy collectionResourcePolicyOfGroup1 = ResourcePolicyBuilder + .createResourcePolicy(context, null, group1) + .withDspaceObject(collection) + .withAction(Constants.WRITE).build(); - ResourcePolicy firstResourcePolicyOfGroup2 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy firstResourcePolicyOfGroup2 = ResourcePolicyBuilder.createResourcePolicy(context, null, group2) .withDspaceObject(community2) - .withAction(Constants.ADD) - .withGroup(group2).build(); + .withAction(Constants.ADD).build(); context.restoreAuthSystemState(); @@ -857,15 +854,13 @@ public void findResourcePoliciesByGroupUuidAndResourceUuidTest() throws Exceptio Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); Community community2 = CommunityBuilder.createCommunity(context).withName("My second community").build(); - ResourcePolicy firstResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy firstResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community) - .withAction(Constants.ADD) - .withGroup(group1).build(); + .withAction(Constants.ADD).build(); - ResourcePolicy secondResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy secondResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community2) - .withAction(Constants.WRITE) - .withGroup(group1).build(); + .withAction(Constants.WRITE).build(); context.restoreAuthSystemState(); @@ -913,10 +908,9 @@ public void findResoucesPoliciesByGroupUuidUnAuthenticatedTest() throws Exceptio Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy firstResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy firstResourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community) - .withAction(Constants.ADD) - .withGroup(group1).build(); + .withAction(Constants.ADD).build(); context.restoreAuthSystemState(); @@ -953,10 +947,9 @@ public void findResourcesPoliciesByGroupUuidForbiddenTest() throws Exception { Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy resourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community).withAction(Constants.WRITE) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withGroup(group1).build(); + .withPolicyType(ResourcePolicy.TYPE_CUSTOM).build(); context.restoreAuthSystemState(); @@ -981,10 +974,10 @@ public void findResourcesPoliciesByGroupAnonymousTest() throws Exception { Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy resourcePolicyOfGroup1 = ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(community).withAction(Constants.WRITE) - .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withGroup(groupAnonymous).build(); + ResourcePolicy resourcePolicyOfGroup1 = ResourcePolicyBuilder + .createResourcePolicy(context, null, groupAnonymous) + .withDspaceObject(community).withAction(Constants.WRITE) + .withPolicyType(ResourcePolicy.TYPE_CUSTOM).build(); context.restoreAuthSystemState(); @@ -1143,9 +1136,8 @@ public void deleteOne() throws Exception { .withName("My community") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) - .withUser(eperson1) .withAction(Constants.ADMIN) .build(); @@ -1170,11 +1162,10 @@ public void deleteOneUnAuthenticatedTest() throws Exception { .withPassword("qwerty01") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(community) .withAction(Constants.DELETE) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) - .withUser(eperson1) .build(); context.restoreAuthSystemState(); @@ -1200,10 +1191,9 @@ public void deleteOneForbiddenTest() throws Exception { Collection collection = CollectionBuilder.createCollection(context, community) .withName("My collection").build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withDspaceObject(collection) - .withAction(Constants.ADD) - .withUser(eperson1).build(); + .withAction(Constants.ADD).build(); context.restoreAuthSystemState(); @@ -1253,10 +1243,10 @@ public void patchReplaceStartDateTest() throws Exception { Date data = calendar.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withStartDate(data) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1323,10 +1313,10 @@ public void patchReplaceEndDateTest() throws Exception { Date date = calendar.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withEndDate(date) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1385,10 +1375,10 @@ public void patchAddStartDateTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1446,13 +1436,12 @@ public void patchAddEndDateTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context,null, + EPersonServiceFactory.getInstance().getGroupService() + .findByName(context, Group.ANONYMOUS) + ) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withGroup( - EPersonServiceFactory.getInstance().getGroupService() - .findByName(context, - Group.ANONYMOUS)) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1513,10 +1502,10 @@ public void patchRemoveStartDateTest() throws Exception { Date data = calendar.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withStartDate(data) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1574,10 +1563,10 @@ public void patchReplaceStartDateBadRequestTest() throws Exception { Date date = calendar.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withStartDate(date) .withDescription("my description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) @@ -1625,7 +1614,7 @@ public void patchReplaceStartDateUnAuthenticatedTest() throws Exception { Date date = calendar.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.WRITE) .withDspaceObject(item) .withStartDate(date) @@ -1687,10 +1676,10 @@ public void patchReplaceStartDateForbiddenTest() throws Exception { Date date = calendar.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(item) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withStartDate(date) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1793,10 +1782,9 @@ public void patchReplaceEndDateBeforeStartDateTest() throws Exception { Date endDate = calendarEndDate.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson1, null) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withUser(eperson1) .withStartDate(startDate) .withEndDate(endDate) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) @@ -1851,10 +1839,10 @@ public void patchReplaceDescriptionTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withDescription("my description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1903,10 +1891,10 @@ public void patchAddDescriptionTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(item) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1954,11 +1942,11 @@ public void patchRemoveDescriptionTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(item) .withDescription("my description") - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -1996,7 +1984,7 @@ public void patchReplaceDescriptionUnAuthenticatedTest() throws Exception { Item item = ItemBuilder.createItem(context, collection).build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.WRITE) .withDspaceObject(item) .withDescription("My Description") @@ -2042,10 +2030,10 @@ public void patchReplaceDescriptionForbiddenTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(item) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withDescription("My Description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2098,10 +2086,10 @@ public void patchReplaceDescriptionBadRequestTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withDescription("my description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2146,10 +2134,10 @@ public void patchReplaceNameTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(myItem) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withName("My name") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2197,10 +2185,10 @@ public void patchReplaceNameBadRequestTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(myItem) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withName("My name") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2245,10 +2233,10 @@ public void patchAddNameTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(myItem) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2290,10 +2278,9 @@ public void patchAddActionTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(myItem) - .withUser(eperson) .withName("My Name") .build(); @@ -2334,10 +2321,9 @@ public void patchReplaceActionTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(myItem) - .withUser(eperson) .withName("My name") .withPolicyType(ResourcePolicy.TYPE_SUBMISSION) .build(); @@ -2374,7 +2360,7 @@ public void patchReplaceActionUnauthenticatedTest() throws Exception { Item item = ItemBuilder.createItem(context, collection).build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.WRITE) .withDspaceObject(item) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) @@ -2413,10 +2399,9 @@ public void patchReplaceActionForbiddenTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(item) - .withUser(eperson) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2464,10 +2449,9 @@ public void patchReplaceActionUnprocessableEntityTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withUser(eperson) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2500,10 +2484,9 @@ public void patchAddPolicyTypeTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(myItem) - .withUser(eperson) .withName("My Name") .build(); @@ -2545,10 +2528,9 @@ public void patchRemovePolicyTypeTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(myItem) - .withUser(eperson) .withName("My Name") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2590,10 +2572,9 @@ public void patchReplacePolicyTypeTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(myItem) - .withUser(eperson) .withName("My name") .withPolicyType(ResourcePolicy.TYPE_SUBMISSION) .build(); @@ -2632,7 +2613,7 @@ public void patchReplacePolicyTypeUnauthenticatedTest() throws Exception { Item item = ItemBuilder.createItem(context, collection).build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.WRITE) .withDspaceObject(item) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) @@ -2672,10 +2653,9 @@ public void patchReplacePolicyTypeForbiddenTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(item) - .withUser(eperson) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2722,10 +2702,9 @@ public void patchReplacePolicyTypeBadRequestTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.READ) .withDspaceObject(publicItem1) - .withUser(eperson) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2763,11 +2742,11 @@ public void patchAddNameBadRequestTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(myItem) .withName("My name") - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2811,10 +2790,10 @@ public void patchRemoveNameTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(myItem) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withName("My Name") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2860,10 +2839,10 @@ public void patchRemoveNameForbiddenTest() throws Exception { .withTitle("Public item") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(myItem) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withName("My Name") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -2923,12 +2902,12 @@ public void patchSuccessfulMultipleOperationsTest() throws Exception { Date endDate = calendarEndDate.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) .withStartDate(startDate) .withEndDate(endDate) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -3013,12 +2992,12 @@ public void patchWithMultipleOperationsFailTest() throws Exception { Date endDate = calendarEndDate.getTime(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, + EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withAction(Constants.READ) .withDspaceObject(publicItem1) .withName("My Name") .withEndDate(endDate) - .withGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS)) .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -3092,25 +3071,21 @@ public void findResourcePoliciesByGroupUuidPaginationTest() throws Exception { .withName("My collection") .build(); - ResourcePolicy rpCommunityADD = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy rpCommunityADD = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community) - .withAction(Constants.ADD) - .withGroup(group1).build(); + .withAction(Constants.ADD).build(); - ResourcePolicy rpCommunityREAD = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy rpCommunityREAD = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community) - .withAction(Constants.READ) - .withGroup(group1).build(); + .withAction(Constants.READ).build(); - ResourcePolicy rpCommunity2READ = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy rpCommunity2READ = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community2) - .withAction(Constants.READ) - .withGroup(group1).build(); + .withAction(Constants.READ).build(); - ResourcePolicy rpCollectionWRITE = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy rpCollectionWRITE = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(collection) - .withAction(Constants.WRITE) - .withGroup(group1).build(); + .withAction(Constants.WRITE).build(); context.restoreAuthSystemState(); @@ -3213,10 +3188,9 @@ public void patchReplaceEPersonAdminTest() throws Exception { .withName("Collection 1") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.ADD) .withDspaceObject(col) - .withUser(eperson) .withDescription("My Description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -3260,10 +3234,9 @@ public void patchReplaceEPersonForbiddenTest() throws Exception { .withName("Collection 1") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.ADD) .withDspaceObject(col) - .withUser(eperson) .withDescription("My Description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -3308,10 +3281,9 @@ public void patchReplaceEPersonUnauthorizedTest() throws Exception { .withName("Collection 1") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(Constants.ADD) .withDspaceObject(col) - .withUser(eperson) .withDescription("My Description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -3358,10 +3330,9 @@ public void patchReplaceGroupAdminTest() throws Exception { .withName("Collection 1") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, originGroup) .withAction(Constants.ADD) .withDspaceObject(col) - .withGroup(originGroup) .withDescription("My Description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -3408,10 +3379,9 @@ public void patchReplaceGroupForbiddenTest() throws Exception { .withName("Collection 1") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, originGroup) .withAction(Constants.ADD) .withDspaceObject(col) - .withGroup(originGroup) .withDescription("My Description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -3459,10 +3429,9 @@ public void patchReplaceGroupUnauthorizedTest() throws Exception { .withName("Collection 1") .build(); - ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicy = ResourcePolicyBuilder.createResourcePolicy(context, null, originGroup) .withAction(Constants.ADD) .withDspaceObject(col) - .withGroup(originGroup) .withDescription("My Description") .withPolicyType(ResourcePolicy.TYPE_CUSTOM) .build(); @@ -3501,10 +3470,9 @@ public void updateResourcePolicyOfEPersonToGroupTest() throws Exception { .withName("My community") .build(); - ResourcePolicy resourcePolicyOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(community) .withAction(Constants.READ) - .withUser(eperson) .build(); context.restoreAuthSystemState(); @@ -3534,10 +3502,9 @@ public void updateResourcePolicyOfGroupToEPersonTest() throws Exception { .withName("My community") .build(); - ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(community) - .withAction(Constants.ADD) - .withGroup(group).build(); + .withAction(Constants.ADD).build(); context.restoreAuthSystemState(); @@ -3597,10 +3564,9 @@ public void updateResourcePolicyOfGroupWithEmptyTest() throws Exception { .build(); - ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(community) - .withAction(Constants.ADD) - .withGroup(group).build(); + .withAction(Constants.ADD).build(); context.restoreAuthSystemState(); String tokenAdmin = getAuthToken(admin.getEmail(), password); @@ -3622,10 +3588,9 @@ public void updateResourcePolicyOfGroupWithMultipleGroupsTest() throws Exception .withName("My community") .build(); - ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy resourcePolicyOfGroup = ResourcePolicyBuilder.createResourcePolicy(context, null, group1) .withDspaceObject(community) - .withAction(Constants.ADD) - .withGroup(group1).build(); + .withAction(Constants.ADD).build(); context.restoreAuthSystemState(); String tokenAdmin = getAuthToken(admin.getEmail(), password); @@ -3642,10 +3607,9 @@ public void updateResourcePolicyOfEPersonWithEmptyTest() throws Exception { Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy rpOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy rpOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(community) .withAction(Constants.READ) - .withUser(eperson) .build(); context.restoreAuthSystemState(); @@ -3671,10 +3635,9 @@ public void updateResourcePolicyOfEPersonWithMultipleEPersonsTest() throws Excep Community community = CommunityBuilder.createCommunity(context).withName("My community").build(); - ResourcePolicy rpOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy rpOfEPerson = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(community) .withAction(Constants.READ) - .withUser(eperson) .build(); context.restoreAuthSystemState(); 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 5544ecdb032b..613075fe8f3a 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 @@ -205,10 +205,9 @@ public void usagereport_loggedInUserReadRights() throws Exception { // ** WHEN ** context.turnOffAuthorisationSystem(); authorizeService.removeAllPolicies(context, itemNotVisitedWithBitstreams); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(itemNotVisitedWithBitstreams) - .withAction(Constants.READ) - .withUser(eperson).build(); + .withAction(Constants.READ).build(); EPerson eperson1 = EPersonBuilder.createEPerson(context) .withEmail("eperson1@mail.com") @@ -239,10 +238,9 @@ public void usagereport_loggedInUserReadRights_and_usage_statistics_admin_is_fal configurationService.setProperty("usage-statistics.authorization.admin.usage", false); context.turnOffAuthorisationSystem(); authorizeService.removeAllPolicies(context, itemNotVisitedWithBitstreams); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(itemNotVisitedWithBitstreams) - .withAction(Constants.READ) - .withUser(eperson).build(); + .withAction(Constants.READ).build(); EPerson eperson1 = EPersonBuilder.createEPerson(context) .withEmail("eperson1@mail.com") @@ -1150,10 +1148,9 @@ public void usagereportSearch_loggedInUserReadRights() throws Exception { // ** WHEN ** context.turnOffAuthorisationSystem(); authorizeService.removeAllPolicies(context, itemNotVisitedWithBitstreams); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(itemNotVisitedWithBitstreams) - .withAction(Constants.READ) - .withUser(eperson).build(); + .withAction(Constants.READ).build(); EPerson eperson1 = EPersonBuilder.createEPerson(context) .withEmail("eperson1@mail.com") diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java index 8b2f3f093a37..9c69e4715d77 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java @@ -121,6 +121,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration private Group embargoedGroup1; private Group embargoedGroup2; private Group anonymousGroup; + private Group adminGroup; @Before @Override @@ -144,6 +145,7 @@ public void setUp() throws Exception { .build(); anonymousGroup = EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS); + adminGroup = EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ADMIN); context.restoreAuthSystemState(); } @@ -6717,13 +6719,10 @@ public void patchAccesConditionDiscoverableTest() throws Exception { .build(); witem.getItem().setDiscoverable(false); - ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(witem.getItem()) - .withPolicyType(TYPE_CUSTOM) - .withName("administrator") +ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") @@ -6777,7 +6776,7 @@ public void patchAccesConditionDiscoverableWrongValueTest() throws Exception { .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") @@ -6824,7 +6823,7 @@ public void patcDiscoverableWithAccesConditionConfigurationDiscoverableDisabledT .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") @@ -6877,7 +6876,7 @@ public void patchAddAccesConditionTest() throws Exception { .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") @@ -6935,7 +6934,7 @@ public void patchAddNotSupportedAccesConditionTest() throws Exception { .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") @@ -7050,13 +7049,13 @@ public void patchRemoveAllAccesConditionsTest() throws Exception { .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("administrator") @@ -7110,16 +7109,13 @@ public void patchRemoveSpecificAccesConditionsTest() throws Exception { .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(witem.getItem()) - .withPolicyType(TYPE_CUSTOM) - .withName("administrator") +ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) .build(); Calendar calendar = Calendar.getInstance(); @@ -7130,7 +7126,7 @@ public void patchRemoveSpecificAccesConditionsTest() throws Exception { Date data = calendar.getTime(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, embargoedGroup1) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("embargoed") @@ -7192,16 +7188,13 @@ public void patchRemoveFirstAccesConditionsTest() throws Exception { .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(witem.getItem()) - .withPolicyType(TYPE_CUSTOM) - .withName("administrator") +ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) .build(); context.restoreAuthSystemState(); @@ -7255,16 +7248,13 @@ public void patchRemoveAccesConditionsIdxNotSupportedTest() throws Exception { .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(witem.getItem()) - .withPolicyType(TYPE_CUSTOM) - .withName("administrator") +ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) .build(); context.restoreAuthSystemState(); @@ -7320,16 +7310,13 @@ public void patchRemoveAccesConditionsUnprocessableEntityTest() throws Exception .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(witem.getItem()) - .withPolicyType(TYPE_CUSTOM) - .withName("administrator") +ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) .build(); context.restoreAuthSystemState(); @@ -7385,16 +7372,13 @@ public void patchReplaceAccesConditionTest() throws Exception { .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) - .withDspaceObject(witem.getItem()) - .withPolicyType(TYPE_CUSTOM) - .withName("administrator") +ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) .build(); context.restoreAuthSystemState(); @@ -7455,7 +7439,7 @@ public void patchReplaceAccesConditionsUpdateEmbargoStartDateTest() throws Excep .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") @@ -7469,7 +7453,7 @@ public void patchReplaceAccesConditionsUpdateEmbargoStartDateTest() throws Excep Date data = calendar.getTime(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, embargoedGroup1) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("embargo") @@ -7535,7 +7519,7 @@ public void patchReplaceAccesConditionsFromOpenaccessToAdministratorTest() throw .withSubject("ExtraEntry") .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) .withDspaceObject(witem.getItem()) .withPolicyType(TYPE_CUSTOM) .withName("openaccess") diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CCLicenseFeatureRestIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CCLicenseFeatureRestIT.java index 38fc9a06fd8d..be8851cb5c06 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CCLicenseFeatureRestIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CCLicenseFeatureRestIT.java @@ -202,8 +202,10 @@ public void checkAuthorizationAsItemAdminTest() throws Exception { Community com = CommunityBuilder.createCommunity(context).withName("A community").build(); Collection col = CollectionBuilder.createCollection(context, com).withName("A collection").build(); Item item = ItemBuilder.createItem(context, col).withTitle("Item to withdraw").build(); - ResourcePolicy resource = ResourcePolicyBuilder.createResourcePolicy(context).withAction(Constants.ADMIN) - .withUser(eperson).withDspaceObject(item).build(); + ResourcePolicy resource = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) + .withAction(Constants.ADMIN) + .withDspaceObject(item) + .build(); context.restoreAuthSystemState(); ItemRest itemRest = itemConverter.convert(item, Projection.DEFAULT); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageBitstreamBundlesFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageBitstreamBundlesFeatureIT.java index 6e29c5b9494b..8d900bfd7c0a 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageBitstreamBundlesFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageBitstreamBundlesFeatureIT.java @@ -216,9 +216,8 @@ public void checkCanCreateVersionsFeatureTest() throws Exception { @SuppressWarnings("unchecked") public void itemAdminSetPropertyCreateBitstreamToFalseTest() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, userA, null) .withAction(Constants.ADMIN) - .withUser(userA) .withDspaceObject(itemA).build(); configurationService.setProperty("core.authorization.item-admin.create-bitstream", false); @@ -260,9 +259,8 @@ public void itemAdminSetPropertyCreateBitstreamToFalseTest() throws Exception { @SuppressWarnings("unchecked") public void itemAdminSetPropertyDeleteBitstreamToFalseTest() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, userA, null) .withAction(Constants.ADMIN) - .withUser(userA) .withDspaceObject(itemA).build(); configurationService.setProperty("core.authorization.item-admin.delete-bitstream", false); @@ -304,9 +302,8 @@ public void itemAdminSetPropertyDeleteBitstreamToFalseTest() throws Exception { @SuppressWarnings("unchecked") public void itemAdminSetPropertyCollectionAdminCreateBitstreamToFalseTest() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, userA, null) .withAction(Constants.ADMIN) - .withUser(userA) .withDspaceObject(itemA).build(); configurationService.setProperty("core.authorization.collection-admin.item.create-bitstream", false); @@ -365,9 +362,8 @@ public void itemAdminSetPropertyCollectionAdminCreateBitstreamToFalseTest() thro @SuppressWarnings("unchecked") public void itemAdminSetPropertyCollectionAdminDeleteBitstreamToFalseTest() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, userA, null) .withAction(Constants.ADMIN) - .withUser(userA) .withDspaceObject(itemA).build(); configurationService.setProperty("core.authorization.collection-admin.item.delete-bitstream", false); @@ -426,9 +422,8 @@ public void itemAdminSetPropertyCollectionAdminDeleteBitstreamToFalseTest() thro @SuppressWarnings("unchecked") public void itemAdminSetPropertyCommunityAdminCreateBitstreamToFalseTest() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, userA, null) .withAction(Constants.ADMIN) - .withUser(userA) .withDspaceObject(itemA).build(); configurationService.setProperty("core.authorization.community-admin.item.create-bitstream", false); @@ -487,9 +482,8 @@ public void itemAdminSetPropertyCommunityAdminCreateBitstreamToFalseTest() throw @SuppressWarnings("unchecked") public void itemAdminSetPropertyCommunityAdminDeleteBitstreamToFalseTest() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, userA, null) .withAction(Constants.ADMIN) - .withUser(userA) .withDspaceObject(itemA).build(); configurationService.setProperty("core.authorization.community-admin.item.delete-bitstream", false); @@ -544,4 +538,4 @@ public void itemAdminSetPropertyCommunityAdminDeleteBitstreamToFalseTest() throw } -} \ No newline at end of file +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageMappingsFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageMappingsFeatureIT.java index e85ca857b916..498983ef65b8 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageMappingsFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageMappingsFeatureIT.java @@ -151,15 +151,13 @@ public void epersonCollectionNotFound() throws Exception { @Test public void addWriteEpersonCollectionSuccess() throws Exception { - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADD) - .withUser(eperson) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.WRITE) - .withUser(eperson) .build(); String epersonToken = getAuthToken(eperson.getEmail(), password); @@ -175,10 +173,9 @@ public void addWriteEpersonCollectionSuccess() throws Exception { @Test public void adminEpersonCollectionSuccess() throws Exception { - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); String epersonToken = getAuthToken(eperson.getEmail(), password); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanSubscribeFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanSubscribeFeatureIT.java index 7eb0960566fc..224ec0472cd0 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanSubscribeFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanSubscribeFeatureIT.java @@ -287,10 +287,9 @@ public void canNotSubscribeCommunityTest() throws Exception { private void setPermissions(DSpaceObject dSpaceObject, Group group, Integer permissions) { try { - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(dSpaceObject) .withAction(permissions) - .withGroup(group) .build(); } catch (SQLException | AuthorizeException sqlException) { log.error(sqlException.getMessage()); @@ -307,4 +306,4 @@ private void cleanUpPermissions(List resourcePolicies) { } } -} \ No newline at end of file +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/EditItemFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/EditItemFeatureIT.java index 4bdc7743b571..ec9020a761bb 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/EditItemFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/EditItemFeatureIT.java @@ -96,8 +96,7 @@ public void testNoRights() throws Exception { @Test public void testDirectEPersonWritePolicy() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(itemA1X) .withAction(Constants.WRITE) .build(); @@ -108,8 +107,7 @@ public void testDirectEPersonWritePolicy() throws Exception { @Test public void testDirectGroupWritePolicy() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withGroup(group) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(itemA1X) .withAction(Constants.WRITE) .build(); @@ -120,8 +118,7 @@ public void testDirectGroupWritePolicy() throws Exception { @Test public void testDirectEPersonAdminPolicy() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(itemA1X) .withAction(Constants.ADMIN) .build(); @@ -132,8 +129,7 @@ public void testDirectEPersonAdminPolicy() throws Exception { @Test public void testDirectGroupAdminPolicy() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withGroup(group) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(itemA1X) .withAction(Constants.ADMIN) .build(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/GenericAuthorizationFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/GenericAuthorizationFeatureIT.java index 1d3b5b051605..8ddd24348c8c 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/GenericAuthorizationFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/GenericAuthorizationFeatureIT.java @@ -148,25 +148,21 @@ public void setUp() throws Exception { .withName("item1AdminGroup") .addMember(item1Admin) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, null, item1AdminGroup) .withDspaceObject(item1) .withAction(Constants.ADMIN) - .withGroup(item1AdminGroup) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, communityAWriter, null) .withDspaceObject(communityA) .withAction(Constants.WRITE) - .withUser(communityAWriter) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, collectionXWriter, null) .withDspaceObject(collectionX) .withAction(Constants.WRITE) - .withUser(collectionXWriter) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, item1Writer, null) .withDspaceObject(item1) .withAction(Constants.WRITE) - .withUser(item1Writer) .build(); communityB = CommunityBuilder.createCommunity(context) @@ -798,10 +794,9 @@ public void testCanMoveAdmin() throws Exception { // grant item 1 admin REMOVE permissions on the item’s owning collection // verify item 1 admin has this feature on item 1 context.turnOffAuthorisationSystem(); - ResourcePolicy removePermission = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy removePermission = ResourcePolicyBuilder.createResourcePolicy(context, item1Writer, null) .withDspaceObject(collectionX) .withAction(Constants.REMOVE) - .withUser(item1Writer) .build(); context.restoreAuthSystemState(); @@ -820,10 +815,9 @@ public void testCanMoveWriter() throws Exception { // grant item 1 write REMOVE permissions on the item’s owning collection context.turnOffAuthorisationSystem(); - ResourcePolicy removePermission = ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicy removePermission = ResourcePolicyBuilder.createResourcePolicy(context, item1Writer, null) .withDspaceObject(collectionX) .withAction(Constants.REMOVE) - .withUser(item1Writer) .build(); context.restoreAuthSystemState(); @@ -901,10 +895,9 @@ public void testCanDeleteAdmin() throws Exception { .withEmail("communityAAAdmin@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, communityAAAdmin, null) .withDspaceObject(communityAA) .withAction(Constants.ADMIN) - .withUser(communityAAAdmin) .build(); context.restoreAuthSystemState(); String communityAAAdminToken = getAuthToken(communityAAAdmin.getEmail(), password); @@ -1082,10 +1075,9 @@ public void testCanDeleteAdminParent() throws Exception { .withEmail("communityAAAdmin@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, communityAAAdmin, null) .withDspaceObject(communityA) .withAction(Constants.REMOVE) - .withUser(communityAAAdmin) .build(); context.restoreAuthSystemState(); String communityAAAdminToken = getAuthToken(communityAAAdmin.getEmail(), password); @@ -1098,10 +1090,9 @@ public void testCanDeleteAdminParent() throws Exception { // Grant REMOVE permissions on community AA for collection X admin context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, collectionXAdmin, null) .withDspaceObject(communityAA) .withAction(Constants.REMOVE) - .withUser(collectionXAdmin) .build(); context.restoreAuthSystemState(); // verify collection X admin has this feature on collection X @@ -1113,10 +1104,9 @@ public void testCanDeleteAdminParent() throws Exception { // Grant REMOVE permissions on collection X for item 1 admin context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, item1Admin, null) .withDspaceObject(collectionX) .withAction(Constants.REMOVE) - .withUser(item1Admin) .build(); context.restoreAuthSystemState(); // verify item 1 admin has this feature on item 1 @@ -1143,10 +1133,9 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("communityADeleter@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, communityADeleter, null) .withDspaceObject(communityA) .withAction(Constants.DELETE) - .withUser(communityADeleter) .build(); context.restoreAuthSystemState(); String communityADeleterToken = getAuthToken(communityADeleter.getEmail(), password); @@ -1171,10 +1160,9 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("communityARemover@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, communityARemover, null) .withDspaceObject(communityA) .withAction(Constants.REMOVE) - .withUser(communityARemover) .build(); context.restoreAuthSystemState(); String communityARemoverToken = getAuthToken(communityARemover.getEmail(), password); @@ -1204,10 +1192,9 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("communityAARemover@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, communityAARemover, null) .withDspaceObject(communityAA) .withAction(Constants.REMOVE) - .withUser(communityAARemover) .build(); context.restoreAuthSystemState(); String communityAARemoverToken = getAuthToken(communityAARemover.getEmail(), password); @@ -1237,10 +1224,9 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("communityXRemover@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, collectionXRemover, null) .withDspaceObject(collectionX) .withAction(Constants.REMOVE) - .withUser(collectionXRemover) .build(); context.restoreAuthSystemState(); String collectionXRemoverToken = getAuthToken(collectionXRemover.getEmail(), password); @@ -1258,10 +1244,9 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("item1Deleter@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, item1Deleter, null) .withDspaceObject(item1) .withAction(Constants.DELETE) - .withUser(item1Deleter) .build(); context.restoreAuthSystemState(); String item1DeleterToken = getAuthToken(item1Deleter.getEmail(), password); @@ -1279,15 +1264,13 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("collectionXDeleter@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, collectionXRemoverItem1Deleter, null) .withDspaceObject(collectionX) .withAction(Constants.REMOVE) - .withUser(collectionXRemoverItem1Deleter) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, collectionXRemoverItem1Deleter, null) .withDspaceObject(item1) .withAction(Constants.DELETE) - .withUser(collectionXRemoverItem1Deleter) .build(); context.restoreAuthSystemState(); String collectionXRemoverItem1DeleterToken = getAuthToken(collectionXRemoverItem1Deleter.getEmail(), password); @@ -1320,10 +1303,9 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("item1Remover@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, item1Remover, null) .withDspaceObject(item1) .withAction(Constants.REMOVE) - .withUser(item1Remover) .build(); context.restoreAuthSystemState(); String item1RemoverToken = getAuthToken(item1Remover.getEmail(), password); @@ -1353,10 +1335,9 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("bundle1Remover@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1Remover, null) .withDspaceObject(bundle1) .withAction(Constants.REMOVE) - .withUser(bundle1Remover) .build(); context.restoreAuthSystemState(); String bundle1RemoverToken = getAuthToken(bundle1Remover.getEmail(), password); @@ -1375,15 +1356,13 @@ public void testCanDeleteMinimalPermissions() throws Exception { .withEmail("bundle1item1Remover@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1item1Remover, null) .withDspaceObject(bundle1) .withAction(Constants.REMOVE) - .withUser(bundle1item1Remover) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1item1Remover, null) .withDspaceObject(item1) .withAction(Constants.REMOVE) - .withUser(bundle1item1Remover) .build(); context.restoreAuthSystemState(); String bundle1item1RemoverToken = getAuthToken(bundle1item1Remover.getEmail(), password); @@ -1553,10 +1532,9 @@ public void testCanCreateBitstreamWriter() throws Exception { .withEmail("bundle1Writer@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1Writer, null) .withDspaceObject(bundle1) .withAction(Constants.WRITE) - .withUser(bundle1Writer) .build(); context.restoreAuthSystemState(); String bundle1WriterToken = getAuthToken(bundle1Writer.getEmail(), password); @@ -1574,10 +1552,9 @@ public void testCanCreateBitstreamWriter() throws Exception { .withEmail("bundle1Adder@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1Adder, null) .withDspaceObject(bundle1) .withAction(Constants.ADD) - .withUser(bundle1Adder) .build(); context.restoreAuthSystemState(); String bundle1AdderToken = getAuthToken(bundle1Adder.getEmail(), password); @@ -1596,25 +1573,21 @@ public void testCanCreateBitstreamWriter() throws Exception { .withEmail("bundle1WriterAdder@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1WriterAdder, null) .withDspaceObject(bundle1) .withAction(Constants.ADD) - .withUser(bundle1WriterAdder) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1WriterAdder, null) .withDspaceObject(bundle1) .withAction(Constants.WRITE) - .withUser(bundle1WriterAdder) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1WriterAdder, null) .withDspaceObject(item1) .withAction(Constants.ADD) - .withUser(bundle1WriterAdder) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, bundle1WriterAdder, null) .withDspaceObject(item1) .withAction(Constants.WRITE) - .withUser(bundle1WriterAdder) .build(); context.restoreAuthSystemState(); String bundle1WriterAdderToken = getAuthToken(bundle1WriterAdder.getEmail(), password); @@ -1666,15 +1639,13 @@ public void testCanCreateBundleWriter() throws Exception { .withEmail("item1AdderWriter@my.edu") .withPassword(password) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, item1AdderWriter, null) .withDspaceObject(item1) .withAction(Constants.ADD) - .withUser(item1AdderWriter) .build(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, item1AdderWriter, null) .withDspaceObject(item1) .withAction(Constants.WRITE) - .withUser(item1AdderWriter) .build(); context.restoreAuthSystemState(); String item1AdderWriterToken = getAuthToken(item1AdderWriter.getEmail(), password); @@ -1685,4 +1656,4 @@ public void testCanCreateBundleWriter() throws Exception { .andExpect(jsonPath("$._embedded.authorizations[?(@._embedded.feature.id=='" + feature + "')]").exists()); } -} \ No newline at end of file +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageAdminGroupFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageAdminGroupFeatureIT.java index cadb3e1ebba9..49082a1613f1 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageAdminGroupFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageAdminGroupFeatureIT.java @@ -123,10 +123,9 @@ public void anonymousCommunityTestNotFound() throws Exception { @Test public void collectionAdminCollectionTestSuccess() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); context.restoreAuthSystemState(); @@ -144,10 +143,9 @@ public void collectionAdminCollectionTestSuccess() throws Exception { @Test public void collectionAdminCommunityTestNotFound() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); context.restoreAuthSystemState(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageSubmitterGroupFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageSubmitterGroupFeatureIT.java index 42ad0c11055e..fbf20337ebbe 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageSubmitterGroupFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageSubmitterGroupFeatureIT.java @@ -123,10 +123,9 @@ public void anonymousCommunityTestNotFound() throws Exception { @Test public void collectionAdminCollectionTestSuccess() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); context.restoreAuthSystemState(); @@ -144,10 +143,9 @@ public void collectionAdminCollectionTestSuccess() throws Exception { @Test public void collectionAdminCommunityTestNotFound() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); context.restoreAuthSystemState(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageTemplateItemFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageTemplateItemFeatureIT.java index 613dfe11513e..97e32e55be5b 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageTemplateItemFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageTemplateItemFeatureIT.java @@ -123,10 +123,9 @@ public void anonymousCommunityTestNotFound() throws Exception { @Test public void collectionAdminCollectionTestSuccess() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); context.restoreAuthSystemState(); @@ -144,10 +143,9 @@ public void collectionAdminCollectionTestSuccess() throws Exception { @Test public void collectionAdminCommunityTestNotFound() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); context.restoreAuthSystemState(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageWorkflowGroupFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageWorkflowGroupFeatureIT.java index ddf0bbac5c4d..411aa76a2352 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageWorkflowGroupFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/ManageWorkflowGroupFeatureIT.java @@ -123,10 +123,9 @@ public void anonymousCommunityTestNotFound() throws Exception { @Test public void collectionAdminCollectionTestSuccess() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); context.restoreAuthSystemState(); @@ -144,10 +143,9 @@ public void collectionAdminCollectionTestSuccess() throws Exception { @Test public void collectionAdminCommunityTestNotFound() throws Exception { context.turnOffAuthorisationSystem(); - ResourcePolicyBuilder.createResourcePolicy(context) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA) .withAction(Constants.ADMIN) - .withUser(eperson) .build(); context.restoreAuthSystemState(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/SubmitFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/SubmitFeatureIT.java index bba45ecd229f..2613cf8ad205 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/SubmitFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/SubmitFeatureIT.java @@ -89,8 +89,7 @@ public void testNoRights() throws Exception { @Test public void testDirectEPersonAddPolicy() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA1) .withAction(Constants.ADD) .build(); @@ -99,8 +98,7 @@ public void testDirectEPersonAddPolicy() throws Exception { @Test public void testDirectGroupAddPolicy() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withGroup(group) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(collectionA1) .withAction(Constants.ADD) .build(); @@ -109,8 +107,7 @@ public void testDirectGroupAddPolicy() throws Exception { @Test public void testDirectEPersonAdminPolicy() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA1) .withAction(Constants.ADMIN) .build(); @@ -119,8 +116,7 @@ public void testDirectEPersonAdminPolicy() throws Exception { @Test public void testDirectGroupAdminPolicy() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withGroup(group) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(collectionA1) .withAction(Constants.ADMIN) .build(); @@ -199,8 +195,7 @@ public void testNoRightsOnCollection() throws Exception { @Test public void testDirectEPersonAddPolicyOnCollection() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA1) .withAction(Constants.ADD) .build(); @@ -210,8 +205,7 @@ public void testDirectEPersonAddPolicyOnCollection() throws Exception { @Test public void testDirectGroupAddPolicyOnCollection() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withGroup(group) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(collectionA1) .withAction(Constants.ADD) .build(); @@ -221,8 +215,7 @@ public void testDirectGroupAddPolicyOnCollection() throws Exception { @Test public void testDirectEPersonAdminPolicyOnCollection() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withDspaceObject(collectionA1) .withAction(Constants.ADMIN) .build(); @@ -232,8 +225,7 @@ public void testDirectEPersonAdminPolicyOnCollection() throws Exception { @Test public void testDirectGroupAdminPolicyOnCollection() throws Exception { - ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context) - .withGroup(group) + ResourcePolicy rp = ResourcePolicyBuilder.createResourcePolicy(context, null, group) .withDspaceObject(collectionA1) .withAction(Constants.ADMIN) .build(); From b923e13726a744f36d628b015ae30c89582ab0ad Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Fri, 29 Sep 2023 10:36:43 +0200 Subject: [PATCH 002/230] 106812: Fix and add new tests --- .../rest/ResourcePolicyRestRepositoryIT.java | 94 ++++++++++++++++++- .../rest/WorkspaceItemRestRepositoryIT.java | 29 ++++-- 2 files changed, 116 insertions(+), 7 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ResourcePolicyRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ResourcePolicyRestRepositoryIT.java index e7d2634525d3..5d2a05ab6440 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ResourcePolicyRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ResourcePolicyRestRepositoryIT.java @@ -998,7 +998,7 @@ public void createWithEPersonTest() throws Exception { AtomicReference idRef = new AtomicReference(); try { Community community = CommunityBuilder.createCommunity(context) - .withName("My commynity") + .withName("My community") .build(); EPerson eperson1 = EPersonBuilder.createEPerson(context) @@ -1045,6 +1045,98 @@ public void createWithEPersonTest() throws Exception { ResourcePolicyBuilder.delete(idRef.get()); } } + @Test + public void createWithGroupTest() throws Exception { + context.turnOffAuthorisationSystem(); + + AtomicReference idRef = new AtomicReference(); + try { + Community community = CommunityBuilder.createCommunity(context) + .withName("My community") + .build(); + + EPerson eperson1 = EPersonBuilder.createEPerson(context) + .withEmail("eperson1@mail.com") + .withPassword("qwerty01") + .build(); + + Group group1 = GroupBuilder.createGroup(context) + .withName("Group 1") + .addMember(eperson1) + .build(); + + context.restoreAuthSystemState(); + + ObjectMapper mapper = new ObjectMapper(); + ResourcePolicyRest resourcePolicyRest = new ResourcePolicyRest(); + + resourcePolicyRest.setPolicyType(ResourcePolicy.TYPE_SUBMISSION); + resourcePolicyRest.setAction(Constants.actionText[Constants.READ]); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken) + .perform(post("/api/authz/resourcepolicies") + .content(mapper.writeValueAsBytes(resourcePolicyRest)) + .param("resource", community.getID().toString()) + .param("group", group1.getID().toString()) + .param("projections", "full") + .contentType(contentType)) + .andExpect(status().isCreated()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", ResourcePolicyMatcher.matchFullEmbeds())) + .andExpect(jsonPath("$", Matchers.allOf( + hasJsonPath("$.name", is(resourcePolicyRest.getName())), + hasJsonPath("$.description", is(resourcePolicyRest.getDescription())), + hasJsonPath("$.policyType", is(resourcePolicyRest.getPolicyType())), + hasJsonPath("$.action", is(resourcePolicyRest.getAction())), + hasJsonPath("$.startDate", is(resourcePolicyRest.getStartDate())), + hasJsonPath("$.endDate", is(resourcePolicyRest.getEndDate())), + hasJsonPath("$.type", is(resourcePolicyRest.getType()))))) + .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id"))); + + String authToken1 = getAuthToken(eperson1.getEmail(), "qwerty01"); + getClient(authToken1).perform(get("/api/authz/resourcepolicies/" + idRef.get())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/authz/resourcepolicies/" + idRef.get()))); + } finally { + ResourcePolicyBuilder.delete(idRef.get()); + } + } + + @Test + public void createWithoutGroupOrPersonTest() throws Exception { + context.turnOffAuthorisationSystem(); + Community community = CommunityBuilder.createCommunity(context) + .withName("My commynity") + .build(); + + + context.restoreAuthSystemState(); + + ObjectMapper mapper = new ObjectMapper(); + ResourcePolicyRest resourcePolicyRest = new ResourcePolicyRest(); + + resourcePolicyRest.setPolicyType(ResourcePolicy.TYPE_SUBMISSION); + resourcePolicyRest.setAction(Constants.actionText[Constants.ADMIN]); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(post("/api/authz/resourcepolicies") + .content(mapper.writeValueAsBytes(resourcePolicyRest)) + .param("resource", community.getID().toString()) + .contentType(contentType)) + .andExpect(status().isBadRequest()); + + getClient(authToken).perform(get("/api/authz/resourcepolicies/search/resource") + .param("uuid", community.getID().toString()) + .param("action", "ADMIN")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("api/authz/resourcepolicies/search/resource"))) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } @Test public void createOneUnAuthenticatedTest() throws Exception { diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java index 9c69e4715d77..c403ec4236a8 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java @@ -6719,7 +6719,9 @@ public void patchAccesConditionDiscoverableTest() throws Exception { .build(); witem.getItem().setDiscoverable(false); -ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) + ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup).withDspaceObject(witem.getItem()) + .withPolicyType(TYPE_CUSTOM) + .withName("administrator") .build(); ResourcePolicyBuilder.createResourcePolicy(context, null, anonymousGroup) @@ -7116,7 +7118,10 @@ public void patchRemoveSpecificAccesConditionsTest() throws Exception { .build(); ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) - .build(); + .withDspaceObject(witem.getItem()) + .withPolicyType(TYPE_CUSTOM) + .withName("administrator") + .build(); Calendar calendar = Calendar.getInstance(); @@ -7195,7 +7200,10 @@ public void patchRemoveFirstAccesConditionsTest() throws Exception { .build(); ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) - .build(); + .withDspaceObject(witem.getItem()) + .withPolicyType(TYPE_CUSTOM) + .withName("administrator") + .build(); context.restoreAuthSystemState(); @@ -7255,7 +7263,10 @@ public void patchRemoveAccesConditionsIdxNotSupportedTest() throws Exception { .build(); ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) - .build(); + .withDspaceObject(witem.getItem()) + .withPolicyType(TYPE_CUSTOM) + .withName("administrator") + .build(); context.restoreAuthSystemState(); @@ -7317,7 +7328,10 @@ public void patchRemoveAccesConditionsUnprocessableEntityTest() throws Exception .build(); ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) - .build(); + .withDspaceObject(witem.getItem()) + .withPolicyType(TYPE_CUSTOM) + .withName("administrator") + .build(); context.restoreAuthSystemState(); @@ -7379,7 +7393,10 @@ public void patchReplaceAccesConditionTest() throws Exception { .build(); ResourcePolicyBuilder.createResourcePolicy(context, null, adminGroup) - .build(); + .withDspaceObject(witem.getItem()) + .withPolicyType(TYPE_CUSTOM) + .withName("administrator") + .build(); context.restoreAuthSystemState(); From 1cf13e3bfef7e3d1f5d09ae3086c7245fabd00df Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Fri, 29 Sep 2023 11:44:29 +0200 Subject: [PATCH 003/230] 106812: Fix old rest resource policy creations --- .../src/main/java/org/dspace/rest/BitstreamResource.java | 5 +++-- dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java b/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java index 3a6ad859603e..b71bfad592cf 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java @@ -729,9 +729,10 @@ static String getMimeType(String name) { private void addPolicyToBitstream(org.dspace.core.Context context, ResourcePolicy policy, org.dspace.content.Bitstream dspaceBitstream) throws SQLException, AuthorizeException { - org.dspace.authorize.ResourcePolicy dspacePolicy = resourcePolicyService.create(context); + org.dspace.authorize.ResourcePolicy dspacePolicy = + resourcePolicyService.create(context, null, + groupService.findByIdOrLegacyId(context, policy.getGroupId())); dspacePolicy.setAction(policy.getActionInt()); - dspacePolicy.setGroup(groupService.findByIdOrLegacyId(context, policy.getGroupId())); dspacePolicy.setdSpaceObject(dspaceBitstream); dspacePolicy.setStartDate(policy.getStartDate()); dspacePolicy.setEndDate(policy.getEndDate()); diff --git a/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java b/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java index 615aacac21cc..761d4dfc8ae3 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java @@ -516,9 +516,10 @@ public Bitstream addItemBitstream(@PathParam("item_id") String itemId, InputStre bitstreamsPolicies.remove(policy); } - org.dspace.authorize.ResourcePolicy dspacePolicy = resourcePolicyService.create(context); + org.dspace.authorize.ResourcePolicy dspacePolicy = + resourcePolicyService.create(context, + null, groupService.findByIdOrLegacyId(context, groupId)); dspacePolicy.setAction(org.dspace.core.Constants.READ); - dspacePolicy.setGroup(groupService.findByIdOrLegacyId(context, groupId)); dspacePolicy.setdSpaceObject(dspaceBitstream); if ((year != null) || (month != null) || (day != null)) { Date date = new Date(); From 9880e697b65c2284aea9d626008a96010af664de Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Fri, 29 Sep 2023 15:36:53 +0200 Subject: [PATCH 004/230] 106812: Add h2 sql file --- ...28__enforce_group_or_eperson_for_resourcepolicy.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql new file mode 100644 index 000000000000..de40d0415dc6 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql @@ -0,0 +1,10 @@ +-- +-- 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/ +-- + +ALTER TABLE ResourcePolicy ADD CONSTRAINT resourcepolicy_eperson_and_epersongroup_not_nullobject_chk + CHECK (eperson_id is not null or epersongroup_id is not null) ; From 9b1234fc85728e3def4940d5b25b9e49e3db422a Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Fri, 10 Nov 2023 14:05:38 +0100 Subject: [PATCH 005/230] 106812: Remove stray settting of group for an rp --- .../java/org/dspace/app/itemimport/ItemImportServiceImpl.java | 1 - 1 file changed, 1 deletion(-) 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 a77d854ade26..9532ecdb4708 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 @@ -1814,7 +1814,6 @@ protected void setPermission(Context c, Group g, int actionID, Bitstream bs) rp.setdSpaceObject(bs); rp.setAction(actionID); - rp.setGroup(g); resourcePolicyService.update(c, rp); } else { From 76658e7c967813e789dd0b5a60ef3c6e9d3d7b0f Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 15 Nov 2023 14:16:40 -0600 Subject: [PATCH 006/230] [maven-release-plugin] prepare for next development iteration --- dspace-api/pom.xml | 2 +- dspace-iiif/pom.xml | 2 +- dspace-oai/pom.xml | 2 +- dspace-rdf/pom.xml | 2 +- dspace-rest/pom.xml | 4 ++-- dspace-server-webapp/pom.xml | 2 +- dspace-services/pom.xml | 2 +- dspace-sword/pom.xml | 2 +- dspace-swordv2/pom.xml | 2 +- dspace/modules/additions/pom.xml | 2 +- dspace/modules/pom.xml | 2 +- dspace/modules/rest/pom.xml | 2 +- dspace/modules/server/pom.xml | 2 +- dspace/pom.xml | 2 +- pom.xml | 32 ++++++++++++++++---------------- 15 files changed, 31 insertions(+), 31 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 97ff29e5c583..2fddacc7e4b5 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace-iiif/pom.xml b/dspace-iiif/pom.xml index eff53478ed9d..c8db035d864e 100644 --- a/dspace-iiif/pom.xml +++ b/dspace-iiif/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index 8aaad80861f3..c9d8285559c1 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -8,7 +8,7 @@ dspace-parent org.dspace - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index f425ea7d9086..f118ebddb378 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml index c1ac8ac2302c..5688424a1c26 100644 --- a/dspace-rest/pom.xml +++ b/dspace-rest/pom.xml @@ -3,7 +3,7 @@ org.dspace dspace-rest war - 7.6.1 + 7.6.2-SNAPSHOT DSpace (Deprecated) REST Webapp DSpace RESTful Web Services API. NOTE: this REST API is DEPRECATED. Please consider using the REST API in the dspace-server-webapp instead! @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index b23db1960cee..b3e903a47b4e 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace-services/pom.xml b/dspace-services/pom.xml index c539dac94f5c..98e0253a498d 100644 --- a/dspace-services/pom.xml +++ b/dspace-services/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 244a661f0c56..900ede5fc507 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 4879d7a29136..8d618bdf5f81 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -13,7 +13,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace/modules/additions/pom.xml b/dspace/modules/additions/pom.xml index fa7d75f82d88..84b53171bf37 100644 --- a/dspace/modules/additions/pom.xml +++ b/dspace/modules/additions/pom.xml @@ -17,7 +17,7 @@ org.dspace modules - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace/modules/pom.xml b/dspace/modules/pom.xml index eaf25a568b68..5819158505fd 100644 --- a/dspace/modules/pom.xml +++ b/dspace/modules/pom.xml @@ -11,7 +11,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT ../../pom.xml diff --git a/dspace/modules/rest/pom.xml b/dspace/modules/rest/pom.xml index 66c5ea86f301..7797346c51db 100644 --- a/dspace/modules/rest/pom.xml +++ b/dspace/modules/rest/pom.xml @@ -13,7 +13,7 @@ org.dspace modules - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace/modules/server/pom.xml b/dspace/modules/server/pom.xml index 195623f72dad..564f81593777 100644 --- a/dspace/modules/server/pom.xml +++ b/dspace/modules/server/pom.xml @@ -13,7 +13,7 @@ just adding new jar in the classloader modules org.dspace - 7.6.1 + 7.6.2-SNAPSHOT .. diff --git a/dspace/pom.xml b/dspace/pom.xml index f61b27c1c9a0..f9dc6126e60b 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -16,7 +16,7 @@ org.dspace dspace-parent - 7.6.1 + 7.6.2-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 614bb39a1fe7..1c3479fc0f51 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.dspace dspace-parent pom - 7.6.1 + 7.6.2-SNAPSHOT DSpace Parent Project DSpace open source software is a turnkey institutional repository application. @@ -872,14 +872,14 @@ org.dspace dspace-rest - 7.6.1 + 7.6.2-SNAPSHOT jar classes org.dspace dspace-rest - 7.6.1 + 7.6.2-SNAPSHOT war @@ -1030,69 +1030,69 @@ org.dspace dspace-api - 7.6.1 + 7.6.2-SNAPSHOT org.dspace dspace-api test-jar - 7.6.1 + 7.6.2-SNAPSHOT test org.dspace.modules additions - 7.6.1 + 7.6.2-SNAPSHOT org.dspace dspace-sword - 7.6.1 + 7.6.2-SNAPSHOT org.dspace dspace-swordv2 - 7.6.1 + 7.6.2-SNAPSHOT org.dspace dspace-oai - 7.6.1 + 7.6.2-SNAPSHOT org.dspace dspace-services - 7.6.1 + 7.6.2-SNAPSHOT org.dspace dspace-server-webapp test-jar - 7.6.1 + 7.6.2-SNAPSHOT test org.dspace dspace-rdf - 7.6.1 + 7.6.2-SNAPSHOT org.dspace dspace-iiif - 7.6.1 + 7.6.2-SNAPSHOT org.dspace dspace-server-webapp - 7.6.1 + 7.6.2-SNAPSHOT jar classes org.dspace dspace-server-webapp - 7.6.1 + 7.6.2-SNAPSHOT war @@ -1927,7 +1927,7 @@ scm:git:git@github.com:DSpace/DSpace.git scm:git:git@github.com:DSpace/DSpace.git git@github.com:DSpace/DSpace.git - dspace-7.6.1 + dspace-7_x From 722ad0275757b1859b1ebeb95d41b4c2792652ce Mon Sep 17 00:00:00 2001 From: Philipp Rumpf Date: Tue, 14 Nov 2023 09:38:35 +0000 Subject: [PATCH 007/230] CrossRefImport: ignore empty responses rather than generating empty phantom ImportRecords Fixes https://github.com/DSpace/DSpace/issues/9202 . --- .../CrossRefImportMetadataSourceServiceImpl.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java index 7dde330b27ec..71b088ff162b 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java @@ -162,7 +162,9 @@ public List call() throws Exception { Iterator nodes = jsonNode.at("/message/items").iterator(); while (nodes.hasNext()) { JsonNode node = nodes.next(); - results.add(transformSourceRecords(node.toString())); + if (!node.isMissingNode()) { + results.add(transformSourceRecords(node.toString())); + } } return results; } @@ -196,7 +198,9 @@ public List call() throws Exception { String responseString = liveImportClient.executeHttpGetRequest(1000, uriBuilder.toString(), params); JsonNode jsonNode = convertStringJsonToJsonNode(responseString); JsonNode messageNode = jsonNode.at("/message"); - results.add(transformSourceRecords(messageNode.toString())); + if (!messageNode.isMissingNode()) { + results.add(transformSourceRecords(messageNode.toString())); + } return results; } } @@ -250,7 +254,9 @@ public List call() throws Exception { Iterator nodes = jsonNode.at("/message/items").iterator(); while (nodes.hasNext()) { JsonNode node = nodes.next(); - results.add(transformSourceRecords(node.toString())); + if (!node.isMissingNode()) { + results.add(transformSourceRecords(node.toString())); + } } return results; } @@ -333,4 +339,4 @@ public void setUrl(String url) { this.url = url; } -} \ No newline at end of file +} From 21a7f251186f8f450f7bf9187dc6670514d0a51f Mon Sep 17 00:00:00 2001 From: Philipp Rumpf Date: Thu, 16 Nov 2023 14:15:32 +0000 Subject: [PATCH 008/230] CrossRefImportMetadataSourceServiceIT: Test empty responses don't result in ... results. --- .../CrossRefImportMetadataSourceServiceIT.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CrossRefImportMetadataSourceServiceIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CrossRefImportMetadataSourceServiceIT.java index 72524709ec65..31c22692f008 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CrossRefImportMetadataSourceServiceIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CrossRefImportMetadataSourceServiceIT.java @@ -48,6 +48,24 @@ public class CrossRefImportMetadataSourceServiceIT extends AbstractLiveImportInt @Autowired private CrossRefImportMetadataSourceServiceImpl crossRefServiceImpl; + @Test + public void crossRefImportMetadataGetNoRecordsTest() throws Exception { + context.turnOffAuthorisationSystem(); + CloseableHttpClient originalHttpClient = liveImportClientImpl.getHttpClient(); + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + try { + liveImportClientImpl.setHttpClient(httpClient); + CloseableHttpResponse response = mockResponse("" , 404, "Not Found"); + when(httpClient.execute(ArgumentMatchers.any())).thenReturn(response); + + context.restoreAuthSystemState(); + Collection recordsImported = crossRefServiceImpl.getRecords("test query", 0, 2); + assertEquals(0, recordsImported.size()); + } finally { + liveImportClientImpl.setHttpClient(originalHttpClient); + } + } + @Test public void crossRefImportMetadataGetRecordsTest() throws Exception { context.turnOffAuthorisationSystem(); From c9c57faa21b165784c4c0d99c932b1dc56e30b7d Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 22 Nov 2023 14:06:05 -0600 Subject: [PATCH 009/230] Update GitHub action plugin versions. Minor fixes including using built-in Maven caching & fix to CodeCov action (cherry picked from commit 2aae4cd78de318e816591932187049eb135fa60d) --- .github/workflows/build.yml | 22 ++--- .github/workflows/codescan.yml | 2 +- .github/workflows/docker.yml | 84 +++++++++---------- .../workflows/port_merged_pull_request.yml | 4 +- .github/workflows/pull_request_opened.yml | 2 +- 5 files changed, 54 insertions(+), 60 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 99c9efe0190f..d6913078e471 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/actions/setup-java - name: Install JDK ${{ matrix.java }} @@ -53,16 +53,7 @@ jobs: with: java-version: ${{ matrix.java }} distribution: 'temurin' - - # https://github.com/actions/cache - - name: Cache Maven dependencies - uses: actions/cache@v3 - with: - # Cache entire ~/.m2/repository - path: ~/.m2/repository - # Cache key is hash of all pom.xml files. Therefore any changes to POMs will invalidate cache - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-maven- + cache: 'maven' # Run parallel Maven builds based on the above 'strategy.matrix' - name: Run Maven ${{ matrix.type }} @@ -96,7 +87,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Download artifacts from previous 'tests' job - name: Download coverage artifacts @@ -108,10 +99,13 @@ jobs: # Retry action: https://github.com/marketplace/actions/retry-action # Codecov action: https://github.com/codecov/codecov-action - name: Upload coverage to Codecov.io - uses: Wandalen/wretry.action@v1.0.36 + uses: Wandalen/wretry.action@v1.3.0 with: action: codecov/codecov-action@v3 - # Try upload 5 times max + # Ensure codecov-action throws an error when it fails to upload + with: | + fail_ci_if_error: true + # Try re-running action 5 times max attempt_limit: 5 # Run again in 30 seconds attempt_delay: 30000 diff --git a/.github/workflows/codescan.yml b/.github/workflows/codescan.yml index 9e6dcc0b23af..13bb0d2278ad 100644 --- a/.github/workflows/codescan.yml +++ b/.github/workflows/codescan.yml @@ -35,7 +35,7 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/actions/setup-java - name: Install JDK diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f1ae184fd5c0..c538d324cdea 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -39,7 +39,7 @@ env: jobs: #################################################### # Build/Push the 'dspace/dspace-dependencies' image. - # This image is used by all other jobs. + # This image is used by all other DSpace build jobs. #################################################### dspace-dependencies: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace' @@ -49,21 +49,21 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -72,7 +72,7 @@ jobs: # Get Metadata for docker_build_deps step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-dependencies' image id: meta_build_deps - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: dspace/dspace-dependencies tags: ${{ env.IMAGE_TAGS }} @@ -81,7 +81,7 @@ jobs: # https://github.com/docker/build-push-action - name: Build and push 'dspace-dependencies' image id: docker_build_deps - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.dependencies @@ -106,21 +106,21 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -128,7 +128,7 @@ jobs: # Get Metadata for docker_build step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace' image id: meta_build - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: dspace/dspace tags: ${{ env.IMAGE_TAGS }} @@ -136,7 +136,7 @@ jobs: - name: Build and push 'dspace' image id: docker_build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile @@ -161,21 +161,21 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -183,7 +183,7 @@ jobs: # Get Metadata for docker_build_test step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-test' image id: meta_build_test - uses: docker/metadata-action@v4 + uses: docker/metadata-action@5 with: images: dspace/dspace tags: ${{ env.IMAGE_TAGS }} @@ -194,7 +194,7 @@ jobs: - name: Build and push 'dspace-test' image id: docker_build_test - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.test @@ -219,21 +219,21 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -241,7 +241,7 @@ jobs: # Get Metadata for docker_build_test step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-cli' image id: meta_build_cli - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: dspace/dspace-cli tags: ${{ env.IMAGE_TAGS }} @@ -249,7 +249,7 @@ jobs: - name: Build and push 'dspace-cli' image id: docker_build_cli - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.cli @@ -276,17 +276,17 @@ jobs: # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -294,7 +294,7 @@ jobs: # Get Metadata for docker_build_solr step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-solr' image id: meta_build_solr - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: dspace/dspace-solr tags: ${{ env.IMAGE_TAGS }} @@ -302,7 +302,7 @@ jobs: - name: Build and push 'dspace-solr' image id: docker_build_solr - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./dspace/src/main/docker/dspace-solr/Dockerfile @@ -325,21 +325,21 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -347,7 +347,7 @@ jobs: # Get Metadata for docker_build_postgres step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-postgres-pgcrypto' image id: meta_build_postgres - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: dspace/dspace-postgres-pgcrypto tags: ${{ env.IMAGE_TAGS }} @@ -355,7 +355,7 @@ jobs: - name: Build and push 'dspace-postgres-pgcrypto' image id: docker_build_postgres - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: # Must build out of subdirectory to have access to install script for pgcrypto context: ./dspace/src/main/docker/dspace-postgres-pgcrypto/ @@ -379,21 +379,21 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -401,7 +401,7 @@ jobs: # Get Metadata for docker_build_postgres_loadsql step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-postgres-pgcrypto-loadsql' image id: meta_build_postgres_loadsql - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: dspace/dspace-postgres-pgcrypto tags: ${{ env.IMAGE_TAGS }} @@ -412,7 +412,7 @@ jobs: - name: Build and push 'dspace-postgres-pgcrypto-loadsql' image id: docker_build_postgres_loadsql - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: # Must build out of subdirectory to have access to install script for pgcrypto context: ./dspace/src/main/docker/dspace-postgres-pgcrypto-curl/ diff --git a/.github/workflows/port_merged_pull_request.yml b/.github/workflows/port_merged_pull_request.yml index 109835d14d3c..857f22755e49 100644 --- a/.github/workflows/port_merged_pull_request.yml +++ b/.github/workflows/port_merged_pull_request.yml @@ -23,11 +23,11 @@ jobs: if: github.event.pull_request.merged steps: # Checkout code - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Port PR to other branch (ONLY if labeled with "port to") # See https://github.com/korthout/backport-action - name: Create backport pull requests - uses: korthout/backport-action@v1 + uses: korthout/backport-action@v2 with: # Trigger based on a "port to [branch]" label on PR # (This label must specify the branch name to port to) diff --git a/.github/workflows/pull_request_opened.yml b/.github/workflows/pull_request_opened.yml index 9b61af72d187..f16e81c9fd25 100644 --- a/.github/workflows/pull_request_opened.yml +++ b/.github/workflows/pull_request_opened.yml @@ -21,4 +21,4 @@ jobs: # Assign the PR to whomever created it. This is useful for visualizing assignments on project boards # See https://github.com/toshimaru/auto-author-assign - name: Assign PR to creator - uses: toshimaru/auto-author-assign@v1.6.2 + uses: toshimaru/auto-author-assign@v2.0.1 From 68f29c45b6cfadc3ad11e078d4fe7340d5c6f04c Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 22 Nov 2023 14:07:05 -0600 Subject: [PATCH 010/230] Minor fixes to Dockerfiles. No longer need 'git'. Use Maven flags to slightly speed up build/install steps. (cherry picked from commit 538833f8a8573e55b49cb28ee6bfbc5330ad6bc4) --- .github/workflows/docker.yml | 2 +- Dockerfile | 5 ++++- Dockerfile.dependencies | 10 ++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c538d324cdea..8be8ac13fe6b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -183,7 +183,7 @@ jobs: # Get Metadata for docker_build_test step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-test' image id: meta_build_test - uses: docker/metadata-action@5 + uses: docker/metadata-action@v5 with: images: dspace/dspace tags: ${{ env.IMAGE_TAGS }} diff --git a/Dockerfile b/Dockerfile index 9c32ecb50cd4..3c536b317629 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,10 @@ USER dspace ADD --chown=dspace . /app/ # Build DSpace (note: this build doesn't include the optional, deprecated "dspace-rest" webapp) # Copy the dspace-installer directory to /install. Clean up the build to keep the docker image small -RUN mvn --no-transfer-progress package && \ +# Maven flags here ensure that we skip building test environment and skip all code verification checks. +# These flags speed up this compilation as much as reasonably possible. +ENV MAVEN_FLAGS="-P-test-environment -Denforcer.skip=true -Dcheckstyle.skip=true -Dlicense.skip=true -Dxml.skip=true" +RUN mvn --no-transfer-progress package ${MAVEN_FLAGS} && \ mv /app/dspace/target/${TARGET_DIR}/* /install && \ mvn clean diff --git a/Dockerfile.dependencies b/Dockerfile.dependencies index a55b323339dc..6f72ab058536 100644 --- a/Dockerfile.dependencies +++ b/Dockerfile.dependencies @@ -15,11 +15,6 @@ RUN useradd dspace \ && mkdir -p /home/dspace \ && chown -Rv dspace: /home/dspace RUN chown -Rv dspace: /app -# Need git to support buildnumber-maven-plugin, which lets us know what version of DSpace is being run. -RUN apt-get update \ - && apt-get install -y --no-install-recommends git \ - && apt-get purge -y --auto-remove \ - && rm -rf /var/lib/apt/lists/* # Switch to dspace user & run below commands as that user USER dspace @@ -28,7 +23,10 @@ USER dspace ADD --chown=dspace . /app/ # Trigger the installation of all maven dependencies (hide download progress messages) -RUN mvn --no-transfer-progress package +# Maven flags here ensure that we skip final assembly, skip building test environment and skip all code verification checks. +# These flags speed up this installation as much as reasonably possible. +ENV MAVEN_FLAGS="-P-assembly -P-test-environment -Denforcer.skip=true -Dcheckstyle.skip=true -Dlicense.skip=true -Dxml.skip=true" +RUN mvn --no-transfer-progress install ${MAVEN_FLAGS} # Clear the contents of the /app directory (including all maven builds), so no artifacts remain. # This ensures when dspace:dspace is built, it will use the Maven local cache (~/.m2) for dependencies From 93fc3ce8d09e4fa03055000447f6957c655ecb12 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 22 Nov 2023 15:54:28 -0600 Subject: [PATCH 011/230] Refactor docker.yml to use a separate reusable-docker-build.yml script for each image build. (cherry picked from commit 0e88bfdae7844ea2313238a96975b3d8c36f0a68) --- .github/workflows/docker.yml | 408 ++++---------------- .github/workflows/reusable-docker-build.yml | 217 +++++++++++ 2 files changed, 288 insertions(+), 337 deletions(-) create mode 100644 .github/workflows/reusable-docker-build.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8be8ac13fe6b..2adceaa4d3c3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -3,6 +3,7 @@ name: Docker images # Run this Build for all pushes to 'main' or maintenance branches, or tagged releases. # Also run for PRs to ensure PR doesn't break Docker build process +# NOTE: uses "reusable-docker-build.yml" to actually build each of the Docker images. on: push: branches: @@ -30,11 +31,6 @@ env: # We manage the 'latest' tag ourselves to the 'main' branch (see settings above) TAGS_FLAVOR: | latest=false - # Architectures / Platforms for which we will build Docker images - # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. - # If this is NOT a PR (e.g. a tag or merge commit), also build for ARM64. NOTE: The ARM64 build takes MUCH - # longer (around 45mins or so) which is why we only run it when pushing a new Docker image. - PLATFORMS: linux/amd64${{ github.event_name != 'pull_request' && ', linux/arm64' || '' }} jobs: #################################################### @@ -44,54 +40,14 @@ jobs: dspace-dependencies: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace' if: github.repository == 'dspace/dspace' - runs-on: ubuntu-latest - - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v4 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # https://github.com/docker/metadata-action - # Get Metadata for docker_build_deps step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-dependencies' image - id: meta_build_deps - uses: docker/metadata-action@v5 - with: - images: dspace/dspace-dependencies - tags: ${{ env.IMAGE_TAGS }} - flavor: ${{ env.TAGS_FLAVOR }} - - # https://github.com/docker/build-push-action - - name: Build and push 'dspace-dependencies' image - id: docker_build_deps - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile.dependencies - platforms: ${{ env.PLATFORMS }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build_deps.outputs.tags }} - labels: ${{ steps.meta_build_deps.outputs.labels }} + uses: ./.github/workflows/reusable-docker-build.yml + with: + build_id: dspace-dependencies + image_name: dspace/dspace-dependencies + dockerfile_path: ./Dockerfile.dependencies + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} ####################################### # Build/Push the 'dspace/dspace' image @@ -101,52 +57,18 @@ jobs: if: github.repository == 'dspace/dspace' # Must run after 'dspace-dependencies' job above needs: dspace-dependencies - runs-on: ubuntu-latest - - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v4 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # Get Metadata for docker_build step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace' image - id: meta_build - uses: docker/metadata-action@v5 - with: - images: dspace/dspace - tags: ${{ env.IMAGE_TAGS }} - flavor: ${{ env.TAGS_FLAVOR }} - - - name: Build and push 'dspace' image - id: docker_build - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile - platforms: ${{ env.PLATFORMS }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build.outputs.tags }} - labels: ${{ steps.meta_build.outputs.labels }} + uses: ./.github/workflows/reusable-docker-build.yml + with: + build_id: dspace + image_name: dspace/dspace + dockerfile_path: ./Dockerfile + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} + # Enable redeploy of sandbox & demo if the branch for this image matches the deployment branch of + # these sites as specified in reusable-docker-build.xml + REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }} + REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }} ############################################################# # Build/Push the 'dspace/dspace' image ('-test' tag) @@ -156,55 +78,17 @@ jobs: if: github.repository == 'dspace/dspace' # Must run after 'dspace-dependencies' job above needs: dspace-dependencies - runs-on: ubuntu-latest - - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v4 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # Get Metadata for docker_build_test step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-test' image - id: meta_build_test - uses: docker/metadata-action@v5 - with: - images: dspace/dspace - tags: ${{ env.IMAGE_TAGS }} - # As this is a test/development image, its tags are all suffixed with "-test". Otherwise, it uses the same - # tagging logic as the primary 'dspace/dspace' image above. - flavor: ${{ env.TAGS_FLAVOR }} - suffix=-test - - - name: Build and push 'dspace-test' image - id: docker_build_test - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile.test - platforms: ${{ env.PLATFORMS }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build_test.outputs.tags }} - labels: ${{ steps.meta_build_test.outputs.labels }} + uses: ./.github/workflows/reusable-docker-build.yml + with: + build_id: dspace-test + image_name: dspace/dspace + dockerfile_path: ./Dockerfile.test + # As this is a test/development image, its tags are all suffixed with "-test". Otherwise, it uses the same + # tagging logic as the primary 'dspace/dspace' image above. + tags_flavor: suffix=-test + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} ########################################### # Build/Push the 'dspace/dspace-cli' image @@ -214,52 +98,14 @@ jobs: if: github.repository == 'dspace/dspace' # Must run after 'dspace-dependencies' job above needs: dspace-dependencies - runs-on: ubuntu-latest - - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v4 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # Get Metadata for docker_build_test step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-cli' image - id: meta_build_cli - uses: docker/metadata-action@v5 - with: - images: dspace/dspace-cli - tags: ${{ env.IMAGE_TAGS }} - flavor: ${{ env.TAGS_FLAVOR }} - - - name: Build and push 'dspace-cli' image - id: docker_build_cli - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile.cli - platforms: ${{ env.PLATFORMS }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build_cli.outputs.tags }} - labels: ${{ steps.meta_build_cli.outputs.labels }} + uses: ./.github/workflows/reusable-docker-build.yml + with: + build_id: dspace-cli + image_name: dspace/dspace-cli + dockerfile_path: ./Dockerfile.cli + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} ########################################### # Build/Push the 'dspace/dspace-solr' image @@ -267,52 +113,14 @@ jobs: dspace-solr: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace' if: github.repository == 'dspace/dspace' - runs-on: ubuntu-latest - - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v3 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # Get Metadata for docker_build_solr step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-solr' image - id: meta_build_solr - uses: docker/metadata-action@v5 - with: - images: dspace/dspace-solr - tags: ${{ env.IMAGE_TAGS }} - flavor: ${{ env.TAGS_FLAVOR }} - - - name: Build and push 'dspace-solr' image - id: docker_build_solr - uses: docker/build-push-action@v5 - with: - context: . - file: ./dspace/src/main/docker/dspace-solr/Dockerfile - platforms: ${{ env.PLATFORMS }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build_solr.outputs.tags }} - labels: ${{ steps.meta_build_solr.outputs.labels }} + uses: ./.github/workflows/reusable-docker-build.yml + with: + build_id: dspace-solr + image_name: dspace/dspace-solr + dockerfile_path: ./dspace/src/main/docker/dspace-solr/Dockerfile + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} ########################################################### # Build/Push the 'dspace/dspace-postgres-pgcrypto' image @@ -320,53 +128,16 @@ jobs: dspace-postgres-pgcrypto: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace' if: github.repository == 'dspace/dspace' - runs-on: ubuntu-latest - - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v4 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # Get Metadata for docker_build_postgres step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-postgres-pgcrypto' image - id: meta_build_postgres - uses: docker/metadata-action@v5 - with: - images: dspace/dspace-postgres-pgcrypto - tags: ${{ env.IMAGE_TAGS }} - flavor: ${{ env.TAGS_FLAVOR }} - - - name: Build and push 'dspace-postgres-pgcrypto' image - id: docker_build_postgres - uses: docker/build-push-action@v5 - with: - # Must build out of subdirectory to have access to install script for pgcrypto - context: ./dspace/src/main/docker/dspace-postgres-pgcrypto/ - dockerfile: Dockerfile - platforms: ${{ env.PLATFORMS }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build_postgres.outputs.tags }} - labels: ${{ steps.meta_build_postgres.outputs.labels }} + uses: ./.github/workflows/reusable-docker-build.yml + with: + build_id: dspace-postgres-pgcrypto + image_name: dspace/dspace-postgres-pgcrypto + # Must build out of subdirectory to have access to install script for pgcrypto. + # NOTE: this context will build the image based on the Dockerfile in the specified directory + dockerfile_context: ./dspace/src/main/docker/dspace-postgres-pgcrypto/ + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} ######################################################################## # Build/Push the 'dspace/dspace-postgres-pgcrypto' image (-loadsql tag) @@ -374,53 +145,16 @@ jobs: dspace-postgres-pgcrypto-loadsql: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace' if: github.repository == 'dspace/dspace' - runs-on: ubuntu-latest - - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v4 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # Get Metadata for docker_build_postgres_loadsql step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-postgres-pgcrypto-loadsql' image - id: meta_build_postgres_loadsql - uses: docker/metadata-action@v5 - with: - images: dspace/dspace-postgres-pgcrypto - tags: ${{ env.IMAGE_TAGS }} - # Suffix all tags with "-loadsql". Otherwise, it uses the same - # tagging logic as the primary 'dspace/dspace-postgres-pgcrypto' image above. - flavor: ${{ env.TAGS_FLAVOR }} - suffix=-loadsql - - - name: Build and push 'dspace-postgres-pgcrypto-loadsql' image - id: docker_build_postgres_loadsql - uses: docker/build-push-action@v5 - with: - # Must build out of subdirectory to have access to install script for pgcrypto - context: ./dspace/src/main/docker/dspace-postgres-pgcrypto-curl/ - dockerfile: Dockerfile - platforms: ${{ env.PLATFORMS }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build_postgres_loadsql.outputs.tags }} - labels: ${{ steps.meta_build_postgres_loadsql.outputs.labels }} \ No newline at end of file + uses: ./.github/workflows/reusable-docker-build.yml + with: + build_id: dspace-postgres-pgcrypto-loadsql + image_name: dspace/dspace-postgres-pgcrypto + # Must build out of subdirectory to have access to install script for pgcrypto. + # NOTE: this context will build the image based on the Dockerfile in the specified directory + dockerfile_context: ./dspace/src/main/docker/dspace-postgres-pgcrypto-curl/ + # Suffix all tags with "-loadsql". Otherwise, it uses the same + # tagging logic as the primary 'dspace/dspace-postgres-pgcrypto' image above. + tags_flavor: suffix=-loadsql + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml new file mode 100644 index 000000000000..46bdab3b6827 --- /dev/null +++ b/.github/workflows/reusable-docker-build.yml @@ -0,0 +1,217 @@ +# +# DSpace's reusable Docker build/push workflow. +# +# This is used by docker.yml for all Docker image builds +name: Reusable DSpace Docker Build + +on: + workflow_call: + # Possible Inputs to this reusable job + inputs: + # Build name/id for this Docker build. Used for digest storage to avoid digest overlap between builds. + build_id: + required: true + type: string + # Requires the image name to build (e.g dspace/dspace-test) + image_name: + required: true + type: string + # Optionally the path to the Dockerfile to use for the build. (Default is [dockerfile_context]/Dockerfile) + dockerfile_path: + required: false + type: string + # Optionally the context directory to build the Dockerfile within. Defaults to "." (current directory) + dockerfile_context: + required: false + type: string + # If Docker image should have additional tag flavor details (e.g. a suffix), it may be passed in. + tags_flavor: + required: false + type: string + secrets: + # Requires that Docker login info be passed in as secrets. + DOCKER_USERNAME: + required: true + DOCKER_ACCESS_TOKEN: + required: true + # These URL secrets are optional. When specified & branch checks match, the redeployment code below will trigger. + # Therefore builds which need to trigger redeployment MUST specify these URLs. All others should leave them empty. + REDEPLOY_SANDBOX_URL: + required: false + REDEPLOY_DEMO_URL: + required: false + +# Define shared default settings as environment variables +env: + IMAGE_NAME: ${{ inputs.image_name }} + # Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action) + # For a new commit on default branch (main), use the literal tag 'latest' on Docker image. + # For a new commit on other branches, use the branch name as the tag for Docker image. + # For a new tag, copy that tag name as the tag for Docker image. + IMAGE_TAGS: | + type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch }} + type=ref,event=branch,enable=${{ github.ref_name != github.event.repository.default_branch }} + type=ref,event=tag + # Define default tag "flavor" for docker/metadata-action per + # https://github.com/docker/metadata-action#flavor-input + # We manage the 'latest' tag ourselves to the 'main' branch (see settings above) + TAGS_FLAVOR: | + latest=false + ${{ inputs.tags_flavor }} + # When these URL variables are specified & required branch matches, then the sandbox or demo site will be redeployed. + # See "Redeploy" steps below for more details. + REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }} + REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }} + # Current DSpace maintenance branch (and architecture) which is deployed to demo.dspace.org / sandbox.dspace.org + # (NOTE: No deployment branch specified for sandbox.dspace.org as it uses the default_branch) + DEPLOY_DEMO_BRANCH: 'dspace-7_x' + DEPLOY_ARCH: 'linux/amd64' + +jobs: + docker-build: + + strategy: + matrix: + # Architectures / Platforms for which we will build Docker images + arch: [ 'linux/amd64', 'linux/arm64' ] + os: [ ubuntu-latest ] + isPr: + - ${{ github.event_name == 'pull_request' }} + # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. + # The below exclude therefore ensures we do NOT build ARM64 for PRs. + exclude: + - isPr: true + os: ubuntu-latest + arch: linux/arm64 + + runs-on: ${{ matrix.os }} + + steps: + # https://github.com/actions/checkout + - name: Checkout codebase + uses: actions/checkout@v4 + + # https://github.com/docker/setup-buildx-action + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + # https://github.com/docker/setup-qemu-action + - name: Set up QEMU emulation to build for multiple architectures + uses: docker/setup-qemu-action@v3 + + # https://github.com/docker/login-action + - name: Login to DockerHub + # Only login if not a PR, as PRs only trigger a Docker build and not a push + if: ${{ ! matrix.isPr }} + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + + # https://github.com/docker/metadata-action + # Get Metadata for docker_build_deps step below + - name: Sync metadata (tags, labels) from GitHub to Docker for image + id: meta_build + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: ${{ env.IMAGE_TAGS }} + flavor: ${{ env.TAGS_FLAVOR }} + + # https://github.com/docker/build-push-action + - name: Build and push image + id: docker_build + uses: docker/build-push-action@v5 + with: + context: ${{ inputs.dockerfile_context || '.' }} + file: ${{ inputs.dockerfile_path }} + platforms: ${{ matrix.arch }} + # For pull requests, we run the Docker build (to ensure no PR changes break the build), + # but we ONLY do an image push to DockerHub if it's NOT a PR + push: ${{ ! matrix.isPr }} + # Use tags / labels provided by 'docker/metadata-action' above + tags: ${{ steps.meta_build.outputs.tags }} + labels: ${{ steps.meta_build.outputs.labels }} + + # Export the digest of Docker build locally (for non PRs only) + - name: Export Docker build digest + if: ${{ ! matrix.isPr }} + run: | + mkdir -p /tmp/digests + digest="${{ steps.docker_build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + # Upload digest to an artifact, so that it can be used in manifest below + - name: Upload Docker build digest to artifact + if: ${{ ! matrix.isPr }} + uses: actions/upload-artifact@v3 + with: + name: digests-${{ inputs.build_id }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + # If this build is NOT a PR and passed in a REDEPLOY_SANDBOX_URL secret, + # Then redeploy https://sandbox.dspace.org if this build is for our deployment architecture and 'main' branch. + - name: Redeploy sandbox.dspace.org (based on main branch) + if: | + !matrix.isPR && + env.REDEPLOY_SANDBOX_URL != '' && + matrix.arch == env.DEPLOY_ARCH && + github.ref_name == github.event.repository.default_branch + run: | + curl -X POST $REDEPLOY_SANDBOX_URL + + # If this build is NOT a PR and passed in a REDEPLOY_DEMO_URL secret, + # Then redeploy https://demo.dspace.org if this build is for our deployment architecture and demo branch. + - name: Redeploy demo.dspace.org (based on maintenace branch) + if: | + !matrix.isPR && + env.REDEPLOY_DEMO_URL != '' && + matrix.arch == env.DEPLOY_ARCH && + github.ref_name == env.DEPLOY_DEMO_BRANCH + run: | + curl -X POST $REDEPLOY_DEMO_URL + + # Merge Docker digests (from various architectures) into a manifest. + # This runs after all Docker builds complete above, and it tells hub.docker.com + # that these builds should be all included in the manifest for this tag. + # (e.g. AMD64 and ARM64 should be listed as options under the same tagged Docker image) + docker-build_manifest: + if: ${{ github.event_name != 'pull_request' }} + runs-on: ubuntu-latest + needs: + - docker-build + steps: + - name: Download Docker build digests + uses: actions/download-artifact@v3 + with: + name: digests-${{ inputs.build_id }} + path: /tmp/digests + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Add Docker metadata for image + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: ${{ env.IMAGE_TAGS }} + flavor: ${{ env.TAGS_FLAVOR }} + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + + - name: Create manifest list from digests and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} From af1550d415c72540bb79c80344c706797f27fd2d Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 28 Nov 2023 14:28:14 -0600 Subject: [PATCH 012/230] Ensure dspace-solr redeploys the Solr instances for Demo/Sandbox --- .github/workflows/docker.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2adceaa4d3c3..dd44e92f0470 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -121,6 +121,10 @@ jobs: secrets: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} + # Enable redeploy of sandbox & demo SOLR instance whenever dspace-solr image changes for deployed branch. + # These URLs MUST use different secrets than 'dspace/dspace' image build above as they are deployed separately. + REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_SOLR_URL }} + REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_SOLR_URL }} ########################################################### # Build/Push the 'dspace/dspace-postgres-pgcrypto' image From 7524d169f5782eab26967b3eba90c3247576ab72 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 28 Nov 2023 16:59:41 -0600 Subject: [PATCH 013/230] Remove unused env variables from docker.yml build script --- .github/workflows/docker.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index dd44e92f0470..338c7371f61a 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -16,22 +16,6 @@ on: permissions: contents: read # to fetch code (actions/checkout) -# Define shared environment variables for all jobs below -env: - # Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action) - # For a new commit on default branch (main), use the literal tag 'latest' on Docker image. - # For a new commit on other branches, use the branch name as the tag for Docker image. - # For a new tag, copy that tag name as the tag for Docker image. - IMAGE_TAGS: | - type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} - type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }} - type=ref,event=tag - # Define default tag "flavor" for docker/metadata-action per - # https://github.com/docker/metadata-action#flavor-input - # We manage the 'latest' tag ourselves to the 'main' branch (see settings above) - TAGS_FLAVOR: | - latest=false - jobs: #################################################### # Build/Push the 'dspace/dspace-dependencies' image. From 16112a44d8f8ba5c097c2f0f383da53b644553c1 Mon Sep 17 00:00:00 2001 From: Shankeerthan Kasilingam Date: Tue, 5 Dec 2023 16:22:01 +0530 Subject: [PATCH 014/230] fix: Failure of org.dspace.app.rest.SitemapRestControllerIT when running locally (cherry picked from commit 44fc15f74baf6aa23c70f3b73975f3c82401e499) --- .../dspace/app/rest/SitemapRestControllerIT.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SitemapRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SitemapRestControllerIT.java index 175fb34e6cac..04d22718e846 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SitemapRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SitemapRestControllerIT.java @@ -216,7 +216,12 @@ public void testSitemap_sitemapIndexXml() throws Exception { //** THEN ** .andExpect(status().isOk()) //We expect the content type to match - .andExpect(content().contentType("application/xml;charset=UTF-8")) + .andExpect(res -> { + String actual = res.getResponse().getContentType(); + assertTrue("Content Type", + "text/xml;charset=UTF-8".equals(actual) || + "application/xml;charset=UTF-8".equals(actual)); + }) .andReturn(); String response = result.getResponse().getContentAsString(); @@ -232,7 +237,12 @@ public void testSitemap_sitemap0Xml() throws Exception { //** THEN ** .andExpect(status().isOk()) //We expect the content type to match - .andExpect(content().contentType("application/xml;charset=UTF-8")) + .andExpect(res -> { + String actual = res.getResponse().getContentType(); + assertTrue("Content Type", + "text/xml;charset=UTF-8".equals(actual) || + "application/xml;charset=UTF-8".equals(actual)); + }) .andReturn(); String response = result.getResponse().getContentAsString(); From c7113e5d2450f7d7d8f4c8a26e83c43a0477aa4e Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Fri, 27 Oct 2023 14:10:49 +0200 Subject: [PATCH 015/230] Correct response of byMetadataAndCollection operation of Controlled Vocabularies Endpoint when no controlled vocabulary is available for the specified metadata and collection (cherry picked from commit eb2e4f1155864d190a3458210419c02978519ec0) --- .../dspace/app/rest/repository/VocabularyRestRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/VocabularyRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/VocabularyRestRepository.java index fcc37d13160d..783ed418233d 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/VocabularyRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/VocabularyRestRepository.java @@ -100,6 +100,9 @@ public VocabularyRest findByMetadataAndCollection( } String authorityName = cas.getChoiceAuthorityName(tokens[0], tokens[1], tokens[2], collection); + if (authorityName == null) { + return null; + } ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(authorityName); return authorityUtils.convertAuthority(source, authorityName, utils.obtainProjection()); } From 14c6ccce21d0cb563b9d9ba88a73309d910e28ce Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Fri, 27 Oct 2023 14:26:37 +0200 Subject: [PATCH 016/230] Add missing test for byMetadataAndCollection operation of Controlled Vocabularies endpoint (cherry picked from commit a294f996cf8c6169d6414609363997e118bc41d0) --- .../app/rest/VocabularyRestRepositoryIT.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyRestRepositoryIT.java index f9b31fb06de9..81d2dba67911 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyRestRepositoryIT.java @@ -394,6 +394,20 @@ public void findByMetadataAndCollectionTest() throws Exception { ))); } + @Test + public void findByMetadataAndCollectionWithMetadataWithoutVocabularyTest() throws Exception { + context.turnOffAuthorisationSystem(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Test collection") + .build(); + context.restoreAuthSystemState(); + String token = getAuthToken(admin.getEmail(), password); + getClient(token).perform(get("/api/submission/vocabularies/search/byMetadataAndCollection") + .param("metadata", "dc.title") + .param("collection", collection.getID().toString())) + .andExpect(status().isNoContent()); + } + @Test public void findByMetadataAndCollectionUnprocessableEntityTest() throws Exception { context.turnOffAuthorisationSystem(); From 37ed65850fcba45ddf9dbbe615bd5f2792e406ac Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Tue, 9 Jan 2024 11:34:52 +0300 Subject: [PATCH 017/230] dspace-api: fix typo in AuthorizeServiceImpl log (cherry picked from commit 127b1ae868534b318f8fc5c0c21d300502183961) --- .../main/java/org/dspace/authorize/AuthorizeServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java index 5dffe5fdfc1f..beff6fdc48e8 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java @@ -895,7 +895,7 @@ private boolean performCheck(Context context, String query) throws SQLException return true; } } catch (SearchServiceException e) { - log.error("Failed getting getting community/collection admin status for " + log.error("Failed getting community/collection admin status for " + context.getCurrentUser().getEmail() + " The search error is: " + e.getMessage() + " The search resourceType filter was: " + query); } From b8d00afd121404446a5021020e9f834951b9dfc3 Mon Sep 17 00:00:00 2001 From: William Welling Date: Mon, 8 Jan 2024 10:22:52 -0600 Subject: [PATCH 018/230] Return headers for HEAD request (cherry picked from commit 64ae49a29ff4edb87053e8319b23a6a60696f65a) --- .../dspace/app/rest/BitstreamRestController.java | 6 ++++++ .../app/rest/utils/HttpHeadersInitializer.java | 15 ++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java index ebd84270f285..063e4760fa40 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java @@ -167,6 +167,12 @@ public ResponseEntity retrieve(@PathVariable UUID uuid, HttpServletResponse resp //Send the data if (httpHeadersInitializer.isValid()) { HttpHeaders httpHeaders = httpHeadersInitializer.initialiseHeaders(); + + if (RequestMethod.HEAD.name().equals(request.getMethod())) { + log.debug("HEAD request - no response body"); + return ResponseEntity.ok().headers(httpHeaders).build(); + } + return ResponseEntity.ok().headers(httpHeaders).body(bitstreamResource); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java index a69da4c5e86b..854aec8868a3 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java @@ -33,7 +33,6 @@ public class HttpHeadersInitializer { protected final Logger log = LoggerFactory.getLogger(this.getClass()); - private static final String METHOD_HEAD = "HEAD"; private static final String MULTIPART_BOUNDARY = "MULTIPART_BYTERANGES"; private static final String CONTENT_TYPE_MULTITYPE_WITH_BOUNDARY = "multipart/byteranges; boundary=" + MULTIPART_BOUNDARY; @@ -165,16 +164,14 @@ public HttpHeaders initialiseHeaders() throws IOException { httpHeaders.put(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, Collections.singletonList(HttpHeaders.ACCEPT_RANGES)); - httpHeaders.put(CONTENT_DISPOSITION, Collections.singletonList(String.format(CONTENT_DISPOSITION_FORMAT, - disposition, - encodeText(fileName)))); - log.debug("Content-Disposition : {}", disposition); - // Content phase - if (METHOD_HEAD.equals(request.getMethod())) { - log.debug("HEAD request - skipping content"); - return null; + // distposition may be null here if contentType is null + if (!isNullOrEmpty(disposition)) { + httpHeaders.put(CONTENT_DISPOSITION, Collections.singletonList(String.format(CONTENT_DISPOSITION_FORMAT, + disposition, + encodeText(fileName)))); } + log.debug("Content-Disposition : {}", disposition); return httpHeaders; From ebbae391d74775fb6c406d56ee0038e115ec069a Mon Sep 17 00:00:00 2001 From: William Welling Date: Wed, 10 Jan 2024 13:51:11 -0600 Subject: [PATCH 019/230] Add content-length to bitstream (cherry picked from commit 6be7e4e37047c3f33d4aec371240a3bf2f02a3ef) --- .../dspace/app/rest/BitstreamRestController.java | 1 + .../app/rest/utils/HttpHeadersInitializer.java | 4 ++++ .../dspace/app/rest/BitstreamRestControllerIT.java | 14 +++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java index 063e4760fa40..9b5ede37c85f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java @@ -138,6 +138,7 @@ public ResponseEntity retrieve(@PathVariable UUID uuid, HttpServletResponse resp .withBufferSize(BUFFER_SIZE) .withFileName(name) .withChecksum(bit.getChecksum()) + .withLength(bit.getSizeBytes()) .withMimetype(mimetype) .with(request) .with(response); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java index 854aec8868a3..d68c710a3c7a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collections; +import java.util.Objects; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -143,6 +144,9 @@ public HttpHeaders initialiseHeaders() throws IOException { if (checksum != null) { httpHeaders.put(ETAG, Collections.singletonList(checksum)); } + if (Objects.nonNull((Long.valueOf(this.length)))) { + httpHeaders.put(HttpHeaders.CONTENT_LENGTH, Collections.singletonList(String.valueOf(this.length))); + } httpHeaders.put(LAST_MODIFIED, Collections.singletonList(FastHttpDateFormat.formatDate(lastModified))); httpHeaders.put(EXPIRES, Collections.singletonList(FastHttpDateFormat.formatDate( System.currentTimeMillis() + DEFAULT_EXPIRE_TIME))); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java index 4813cc659694..47c48846ad26 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java @@ -205,6 +205,18 @@ public void retrieveFullBitstream() throws Exception { } context.restoreAuthSystemState(); + //** WHEN ** + // we want to know what we are downloading before we download it + getClient().perform(head("/api/core/bitstreams/" + bitstream.getID() + "/content")) + //** THEN ** + .andExpect(status().isOk()) + + //The Content Length must match the full length + .andExpect(header().longValue("Content-Length", bitstreamContent.getBytes().length)) + .andExpect(header().string("Content-Type", "text/plain;charset=UTF-8")) + .andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\"")) + .andExpect(content().bytes(new byte[] {})); + //** WHEN ** //We download the bitstream getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content")) @@ -231,7 +243,7 @@ public void retrieveFullBitstream() throws Exception { .andExpect(status().isNotModified()); //The download and head request should also be logged as a statistics record - checkNumberOfStatsRecords(bitstream, 2); + checkNumberOfStatsRecords(bitstream, 3); } @Test From 9a0db2a642025423dcc8d3c890350057b79c821e Mon Sep 17 00:00:00 2001 From: Agustina Martinez Date: Wed, 10 Jan 2024 13:08:02 +0000 Subject: [PATCH 020/230] Skip recording usage event if administrator (cherry picked from commit 73e5c43f7c565166a7b4b920a8958be0cc0c6c01) --- .../dspace/statistics/SolrLoggerServiceImpl.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java index 97585f5a47cb..5f976bbfd94b 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java @@ -81,6 +81,7 @@ import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.ShardParams; import org.apache.solr.common.util.NamedList; +import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; import org.dspace.content.Collection; @@ -146,6 +147,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea private SolrStatisticsCore solrStatisticsCore; @Autowired private GeoIpService geoIpService; + @Autowired + private AuthorizeService authorizeService; /** URL to the current-year statistics core. Prior-year shards will have a year suffixed. */ private String statisticsCoreURL; @@ -219,6 +222,16 @@ public void postView(DSpaceObject dspaceObject, HttpServletRequest request, @Override public void postView(DSpaceObject dspaceObject, HttpServletRequest request, EPerson currentUser, String referrer) { + Context context = new Context(); + // Do not record statistics for Admin users + try { + if (authorizeService.isAdmin(context, currentUser)) { + return; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + if (solr == null) { return; } From dc57aceeaf74204326862a4d0efb781789c2b9aa Mon Sep 17 00:00:00 2001 From: nwoodward Date: Tue, 16 Jan 2024 13:28:40 -0600 Subject: [PATCH 021/230] catch exceptions stemming from invalid id's (cherry picked from commit 848df25984b8d6cabb8b6b0c831070ffed66919a) --- .../org/dspace/content/BitstreamServiceImpl.java | 13 +++++++++---- .../java/org/dspace/content/BundleServiceImpl.java | 13 +++++++++---- .../org/dspace/content/CollectionServiceImpl.java | 13 +++++++++---- .../org/dspace/content/CommunityServiceImpl.java | 13 +++++++++---- .../java/org/dspace/content/ItemServiceImpl.java | 13 +++++++++---- .../java/org/dspace/eperson/EPersonServiceImpl.java | 13 +++++++++---- .../java/org/dspace/eperson/GroupServiceImpl.java | 13 +++++++++---- 7 files changed, 63 insertions(+), 28 deletions(-) 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 691d38f03039..e23e5ce2c825 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java @@ -458,10 +458,15 @@ public int countTotal(Context context) throws SQLException { @Override public Bitstream findByIdOrLegacyId(Context context, String id) throws SQLException { - if (StringUtils.isNumeric(id)) { - return findByLegacyId(context, Integer.parseInt(id)); - } else { - return find(context, UUID.fromString(id)); + try { + if (StringUtils.isNumeric(id)) { + return findByLegacyId(context, Integer.parseInt(id)); + } else { + return find(context, UUID.fromString(id)); + } + } catch (IllegalArgumentException e) { + // Not a valid legacy ID or valid UUID + return null; } } 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 546d48d4306b..3ba90c8cc2ae 100644 --- a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java @@ -562,10 +562,15 @@ public int getSupportsTypeConstant() { @Override public Bundle findByIdOrLegacyId(Context context, String id) throws SQLException { - if (StringUtils.isNumeric(id)) { - return findByLegacyId(context, Integer.parseInt(id)); - } else { - return find(context, UUID.fromString(id)); + try { + if (StringUtils.isNumeric(id)) { + return findByLegacyId(context, Integer.parseInt(id)); + } else { + return find(context, UUID.fromString(id)); + } + } catch (IllegalArgumentException e) { + // Not a valid legacy ID or valid UUID + return null; } } diff --git a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java index 84ca1692ccf2..0d9507e3aa35 100644 --- a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java @@ -895,10 +895,15 @@ public void updateLastModified(Context context, Collection collection) throws SQ @Override public Collection findByIdOrLegacyId(Context context, String id) throws SQLException { - if (StringUtils.isNumeric(id)) { - return findByLegacyId(context, Integer.parseInt(id)); - } else { - return find(context, UUID.fromString(id)); + try { + if (StringUtils.isNumeric(id)) { + return findByLegacyId(context, Integer.parseInt(id)); + } else { + return find(context, UUID.fromString(id)); + } + } catch (IllegalArgumentException e) { + // Not a valid legacy ID or valid UUID + return null; } } diff --git a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java index 15ac1c58a690..045adc229e79 100644 --- a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java @@ -694,10 +694,15 @@ public void updateLastModified(Context context, Community community) { @Override public Community findByIdOrLegacyId(Context context, String id) throws SQLException { - if (StringUtils.isNumeric(id)) { - return findByLegacyId(context, Integer.parseInt(id)); - } else { - return find(context, UUID.fromString(id)); + try { + if (StringUtils.isNumeric(id)) { + return findByLegacyId(context, Integer.parseInt(id)); + } else { + return find(context, UUID.fromString(id)); + } + } catch (IllegalArgumentException e) { + // Not a valid legacy ID or valid UUID + return null; } } diff --git a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java index ebea2aa5b820..26a61877fe7f 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1609,10 +1609,15 @@ protected void getAuthoritiesAndConfidences(String fieldKey, Collection collecti @Override public Item findByIdOrLegacyId(Context context, String id) throws SQLException { - if (StringUtils.isNumeric(id)) { - return findByLegacyId(context, Integer.parseInt(id)); - } else { - return find(context, UUID.fromString(id)); + try { + if (StringUtils.isNumeric(id)) { + return findByLegacyId(context, Integer.parseInt(id)); + } else { + return find(context, UUID.fromString(id)); + } + } catch (IllegalArgumentException e) { + // Not a valid legacy ID or valid UUID + return null; } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java index 66fe6562ea25..453d5d0726be 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java @@ -142,10 +142,15 @@ public EPerson getSystemEPerson(Context c) @Override public EPerson findByIdOrLegacyId(Context context, String id) throws SQLException { - if (StringUtils.isNumeric(id)) { - return findByLegacyId(context, Integer.parseInt(id)); - } else { - return find(context, UUID.fromString(id)); + try { + if (StringUtils.isNumeric(id)) { + return findByLegacyId(context, Integer.parseInt(id)); + } else { + return find(context, UUID.fromString(id)); + } + } catch (IllegalArgumentException e) { + // Not a valid legacy ID or valid UUID + return null; } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java index b8d8c75d0f2e..730053e42ce2 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java @@ -872,10 +872,15 @@ protected Set getChildren(Map> parents, UUID parent) { @Override public Group findByIdOrLegacyId(Context context, String id) throws SQLException { - if (org.apache.commons.lang3.StringUtils.isNumeric(id)) { - return findByLegacyId(context, Integer.parseInt(id)); - } else { - return find(context, UUIDUtils.fromString(id)); + try { + if (StringUtils.isNumeric(id)) { + return findByLegacyId(context, Integer.parseInt(id)); + } else { + return find(context, UUID.fromString(id)); + } + } catch (IllegalArgumentException e) { + // Not a valid legacy ID or valid UUID + return null; } } From a22a01aa5c26dc49316523c089326d9c7a3568eb Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Mon, 22 Jan 2024 15:14:54 +0100 Subject: [PATCH 022/230] search on labels, not values on DCInputs (cherry picked from commit 5ebe1a9402d8d0be85284d722f65bc71836113df) --- .../java/org/dspace/content/authority/DCInputAuthority.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java index b1d8cf36a5d3..902bded33ef7 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java @@ -156,7 +156,8 @@ public Choices getMatches(String query, int start, int limit, String locale) { int found = 0; List v = new ArrayList(); for (int i = 0; i < valuesLocale.length; ++i) { - if (query == null || StringUtils.containsIgnoreCase(valuesLocale[i], query)) { + // In a DCInputAuthority context, a user will want to query the labels, not the values + if (query == null || StringUtils.containsIgnoreCase(labelsLocale[i], query)) { if (found >= start && v.size() < limit) { v.add(new Choice(null, valuesLocale[i], labelsLocale[i])); if (valuesLocale[i].equalsIgnoreCase(query)) { From 25496630810e535c17588a965adc33740d8b6384 Mon Sep 17 00:00:00 2001 From: milanmajchrak Date: Sat, 27 Jan 2024 13:38:22 +0100 Subject: [PATCH 023/230] The cas.init() method is called in the VocabularyRestRepositoryIT#setup() method (cherry picked from commit 85b5e06fb0946a15f71abaa1d27ef5914f7b8df2) --- .../java/org/dspace/app/rest/VocabularyRestRepositoryIT.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyRestRepositoryIT.java index 81d2dba67911..30890d7ef838 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyRestRepositoryIT.java @@ -92,6 +92,11 @@ public void setup() throws Exception { // the properties that we're altering above and this is only used within the tests DCInputAuthority.reset(); pluginService.clearNamedPluginClasses(); + + // The following line is needed to call init() method in the ChoiceAuthorityServiceImpl class, without it + // the `submissionConfigService` will be null what will cause a NPE in the clearCache() method + // https://github.com/DSpace/DSpace/issues/9292 + cas.getChoiceAuthoritiesNames(); cas.clearCache(); context.turnOffAuthorisationSystem(); From a0ba470197613873bc18031daad9d760a689b107 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 2 Feb 2024 09:02:19 -0600 Subject: [PATCH 024/230] Fix "cannot override networks.dspacenet" by updating all compose files to reference 'dspacenet' network --- docker-compose-cli.yml | 12 ++++++------ docker-compose.yml | 2 +- dspace/src/main/docker-compose/README.md | 1 + .../main/docker-compose/docker-compose-angular.yml | 8 +++++--- .../src/main/docker-compose/docker-compose-iiif.yml | 8 +++++--- .../docker-compose/docker-compose-shibboleth.yml | 8 +++++--- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/docker-compose-cli.yml b/docker-compose-cli.yml index 9c66fed6835b..4f4d4a189161 100644 --- a/docker-compose-cli.yml +++ b/docker-compose-cli.yml @@ -1,5 +1,10 @@ version: "3.7" - +networks: + # Default to using network named 'dspacenet' from docker-compose.yml. + # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") + default: + name: ${COMPOSE_PROJECT_NAME}_dspacenet + external: true services: dspace-cli: image: "${DOCKER_OWNER:-dspace}/dspace-cli:${DSPACE_VER:-dspace-7_x}" @@ -26,13 +31,8 @@ services: - ./dspace/config:/dspace/config entrypoint: /dspace/bin/dspace command: help - networks: - - dspacenet tty: true stdin_open: true volumes: assetstore: - -networks: - dspacenet: diff --git a/docker-compose.yml b/docker-compose.yml index 6c1615040722..7801a681031a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,7 @@ services: depends_on: - dspacedb networks: - dspacenet: + - dspacenet ports: - published: 8080 target: 8080 diff --git a/dspace/src/main/docker-compose/README.md b/dspace/src/main/docker-compose/README.md index 35a6e6055433..1c9acea30cc5 100644 --- a/dspace/src/main/docker-compose/README.md +++ b/dspace/src/main/docker-compose/README.md @@ -78,6 +78,7 @@ docker-compose -p d7 up -d ``` docker-compose -p d7 -f docker-compose.yml -f dspace/src/main/docker-compose/docker-compose-angular.yml up -d ``` +NOTE: This starts the UI in development mode. It will take a few minutes to see the UI as the Angular code needs to be compiled. ## Run DSpace REST and DSpace Angular from local branches diff --git a/dspace/src/main/docker-compose/docker-compose-angular.yml b/dspace/src/main/docker-compose/docker-compose-angular.yml index 00dde2e83187..8f9bdf94b38b 100644 --- a/dspace/src/main/docker-compose/docker-compose-angular.yml +++ b/dspace/src/main/docker-compose/docker-compose-angular.yml @@ -8,7 +8,11 @@ version: '3.7' networks: - dspacenet: + # Default to using network named 'dspacenet' from docker-compose.yml. + # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") + default: + name: ${COMPOSE_PROJECT_NAME}_dspacenet + external: true services: dspace-angular: container_name: dspace-angular @@ -24,8 +28,6 @@ services: DSPACE_REST_PORT: 8080 DSPACE_REST_NAMESPACE: /server image: dspace/dspace-angular:dspace-7_x - networks: - dspacenet: ports: - published: 4000 target: 4000 diff --git a/dspace/src/main/docker-compose/docker-compose-iiif.yml b/dspace/src/main/docker-compose/docker-compose-iiif.yml index 2ab58d9014f0..d795192f13c4 100644 --- a/dspace/src/main/docker-compose/docker-compose-iiif.yml +++ b/dspace/src/main/docker-compose/docker-compose-iiif.yml @@ -12,7 +12,11 @@ # version: '3.7' networks: - dspacenet: + # Default to using network named 'dspacenet' from docker-compose.yml. + # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") + default: + name: ${COMPOSE_PROJECT_NAME}_dspacenet + external: true services: dspace-iiif: container_name: dspace-iiif @@ -21,8 +25,6 @@ services: # Using UCLA Library image as it seems to be most maintained at this time. There is no official image. # https://hub.docker.com/r/uclalibrary/cantaloupe image: uclalibrary/cantaloupe:5.0.4-0 - networks: - dspacenet: ports: - '8182:8182' # For a guide of environment variables that can be used, see diff --git a/dspace/src/main/docker-compose/docker-compose-shibboleth.yml b/dspace/src/main/docker-compose/docker-compose-shibboleth.yml index 58f1527d6ccb..33eadcb142d7 100644 --- a/dspace/src/main/docker-compose/docker-compose-shibboleth.yml +++ b/dspace/src/main/docker-compose/docker-compose-shibboleth.yml @@ -12,7 +12,11 @@ # version: '3.7' networks: - dspacenet: + # Default to using network named 'dspacenet' from docker-compose.yml. + # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") + default: + name: ${COMPOSE_PROJECT_NAME}_dspacenet + external: true services: dspace-shibboleth: container_name: dspace-shibboleth @@ -22,8 +26,6 @@ services: build: # Must be relative to root, so that it can be built alongside [src]/docker-compose.yml context: ./dspace/src/main/docker/dspace-shibboleth - networks: - dspacenet: ports: - published: 80 target: 80 From 250e82af9d2b1c812341dc4af2294010a603f36d Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 2 Feb 2024 09:13:16 -0600 Subject: [PATCH 025/230] Fix build issues with dockersolr by using "additional_contexts" to pass solr config path to Dockerfile. --- docker-compose.yml | 6 ++++-- dspace/src/main/docker/dspace-solr/Dockerfile | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7801a681031a..a7894135c6ab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,8 +89,10 @@ services: container_name: dspacesolr image: "${DOCKER_OWNER:-dspace}/dspace-solr:${DSPACE_VER:-dspace-7_x}" build: - context: . - dockerfile: ./dspace/src/main/docker/dspace-solr/Dockerfile + context: ./dspace/src/main/docker/dspace-solr/ + # Provide path to Solr configs necessary to build Docker image + additional_contexts: + solrconfigs: ./dspace/solr/ args: SOLR_VERSION: "${SOLR_VER:-8.11}" networks: diff --git a/dspace/src/main/docker/dspace-solr/Dockerfile b/dspace/src/main/docker/dspace-solr/Dockerfile index 9fe9adf9440f..eb8e93493fa8 100644 --- a/dspace/src/main/docker/dspace-solr/Dockerfile +++ b/dspace/src/main/docker/dspace-solr/Dockerfile @@ -26,10 +26,12 @@ RUN mkdir -p $AUTHORITY_CONFIGSET_PATH && \ mkdir -p $SEARCH_CONFIGSET_PATH && \ mkdir -p $STATISTICS_CONFIGSET_PATH -COPY dspace/solr/authority/conf/* $AUTHORITY_CONFIGSET_PATH/ -COPY dspace/solr/oai/conf/* $OAI_CONFIGSET_PATH/ -COPY dspace/solr/search/conf/* $SEARCH_CONFIGSET_PATH/ -COPY dspace/solr/statistics/conf/* $STATISTICS_CONFIGSET_PATH/ +# NOTE: "solrconfigs" MUST be passed in by docker-compose via "additional_contexts" +# OR via "docker build --build-context solrconfigs=[path-to-dspace/solr]" +COPY --from=solrconfigs authority/conf/* $AUTHORITY_CONFIGSET_PATH/ +COPY --from=solrconfigs oai/conf/* $OAI_CONFIGSET_PATH/ +COPY --from=solrconfigs search/conf/* $SEARCH_CONFIGSET_PATH/ +COPY --from=solrconfigs statistics/conf/* $STATISTICS_CONFIGSET_PATH/ RUN chown -R solr:solr /opt/solr/server/solr/configsets From 414837a12a2634eb2d5217d11776f2cdf241bd42 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 2 Feb 2024 10:09:08 -0600 Subject: [PATCH 026/230] Fix 'dspacesolr' build issues in GitHub actions by adding 'solrconfig' as an additional_context --- .github/workflows/docker.yml | 2 ++ .github/workflows/reusable-docker-build.yml | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 338c7371f61a..9f1e407cff4b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -102,6 +102,8 @@ jobs: build_id: dspace-solr image_name: dspace/dspace-solr dockerfile_path: ./dspace/src/main/docker/dspace-solr/Dockerfile + # Must pass solrconfigs to the Dockerfile so that it can find the required Solr config files + dockerfile_additional_contexts: 'solrconfigs=./dspace/solr/' secrets: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml index 46bdab3b6827..aa8327f4d11b 100644 --- a/.github/workflows/reusable-docker-build.yml +++ b/.github/workflows/reusable-docker-build.yml @@ -24,6 +24,12 @@ on: dockerfile_context: required: false type: string + default: '.' + # Optionally a list of "additional_contexts" to pass to Dockerfile. Defaults to empty + dockerfile_additional_contexts: + required: false + type: string + default: '' # If Docker image should have additional tag flavor details (e.g. a suffix), it may be passed in. tags_flavor: required: false @@ -123,7 +129,9 @@ jobs: id: docker_build uses: docker/build-push-action@v5 with: - context: ${{ inputs.dockerfile_context || '.' }} + build-contexts: | + ${{ inputs.dockerfile_additional_contexts }} + context: ${{ inputs.dockerfile_context }} file: ${{ inputs.dockerfile_path }} platforms: ${{ matrix.arch }} # For pull requests, we run the Docker build (to ensure no PR changes break the build), From 3bfcf829772b535c6bb90007d211f853869e5145 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 16:45:54 +0000 Subject: [PATCH 027/230] Update dependency com.flipkart.zjsonpatch:zjsonpatch to v0.4.14 --- dspace-server-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index b3e903a47b4e..3df2f2d5e221 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -288,7 +288,7 @@ com.flipkart.zjsonpatch zjsonpatch - 0.4.6 + 0.4.14 From 774f3bbcd5c490b1619c6e9fdd5a837949eb5913 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 10:08:29 +0000 Subject: [PATCH 028/230] Update dependency de.digitalcollections.iiif:iiif-apis to v0.3.10 --- dspace-iiif/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-iiif/pom.xml b/dspace-iiif/pom.xml index c8db035d864e..8cba90552481 100644 --- a/dspace-iiif/pom.xml +++ b/dspace-iiif/pom.xml @@ -93,7 +93,7 @@ de.digitalcollections.iiif iiif-apis - 0.3.9 + 0.3.10 org.javassist From 5893c7768e22ad784cdb07698ad3624d71d8f1b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 10:08:34 +0000 Subject: [PATCH 029/230] Update dependency dnsjava:dnsjava to v2.1.9 --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 2fddacc7e4b5..7b4cc0b6f596 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -635,7 +635,7 @@ dnsjava dnsjava - 2.1.7 + 2.1.9 From bd7214ad1f515c266355be7a646174d3c14cca92 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Fri, 2 Jun 2023 19:36:59 +0300 Subject: [PATCH 030/230] pom.xml: bump com.google.code.findbugs:jsr305 Closes: https://github.com/alanorth/DSpace/pull/12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1c3479fc0f51..08fd32f7202d 100644 --- a/pom.xml +++ b/pom.xml @@ -1738,7 +1738,7 @@ com.google.code.findbugs jsr305 - 3.0.1 + 3.0.2 provided From aeb5300c6ff81d26cb48d3f9ee8f103288f79b18 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 18:40:03 +0000 Subject: [PATCH 031/230] Update dependency javax.cache:cache-api to v1.1.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 08fd32f7202d..e1b7afc8cad6 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.3.2 2.3.1 2.3.1 - 1.1.0 + 1.1.1 9.4.53.v20231009 2.20.0 From 84452a97d8c477a04407f8abeb4f05d68cbacdc5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:54:30 +0000 Subject: [PATCH 032/230] Update dependency net.handle:handle to v9.3.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e1b7afc8cad6..711d9e439b8f 100644 --- a/pom.xml +++ b/pom.xml @@ -1358,7 +1358,7 @@ net.handle handle - 9.3.0 + 9.3.1 From be7bdcf3980784fa820355e0ee4cfc0930fcd38a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:57:30 +0000 Subject: [PATCH 033/230] Update dependency org.apache.ant:ant to v1.10.13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 711d9e439b8f..52308f07784c 100644 --- a/pom.xml +++ b/pom.xml @@ -1336,7 +1336,7 @@ org.apache.ant ant - 1.10.11 + 1.10.13 org.apache.jena From 969bee48715c9870aedb9e401078f22ef6ee5e0a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 15:00:31 +0000 Subject: [PATCH 034/230] Update dependency junit:junit to v4.13.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 52308f07784c..1f6f108f7b88 100644 --- a/pom.xml +++ b/pom.xml @@ -1669,7 +1669,7 @@ junit junit - 4.13.1 + 4.13.2 test From 95ac7dea42e5494e3214d9590f85cb6ab129cd2d Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Fri, 2 Jun 2023 22:25:29 +0300 Subject: [PATCH 035/230] pom.xml: bump org.apache.httpcomponents Closes: https://github.com/alanorth/DSpace/pull/21 Closes: https://github.com/alanorth/DSpace/pull/22 Closes: https://github.com/alanorth/DSpace/pull/23 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 1f6f108f7b88..233a70e43c72 100644 --- a/pom.xml +++ b/pom.xml @@ -1626,17 +1626,17 @@ org.apache.httpcomponents httpcore - 4.4.15 + 4.4.16 org.apache.httpcomponents httpclient - 4.5.13 + 4.5.14 org.apache.httpcomponents httpmime - 4.5.13 + 4.5.14 org.slf4j From bbe05833a98f844d98e69e6295f766b042b83b64 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 19:52:57 +0000 Subject: [PATCH 036/230] Update dependency org.ehcache:ehcache to v3.10.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 233a70e43c72..5da3aef26215 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 42.6.0 8.11.2 - 3.4.0 + 3.10.8 2.10.0 2.13.4 From e2d809ffb4fadae00a42c46ca7fc6ca042ee4a7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 19:37:49 +0000 Subject: [PATCH 037/230] Update dependency org.flywaydb:flyway-core to v8.5.13 --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 7b4cc0b6f596..17479e3c1410 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -671,7 +671,7 @@ org.flywaydb flyway-core - 8.4.4 + 8.5.13 From 91f9d8c4dd7c67e7cb3595431354fbe26c5d30cc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 20:33:06 +0000 Subject: [PATCH 038/230] Update dependency com.opencsv:opencsv to v5.7.1 --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 17479e3c1410..62964053961a 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -794,7 +794,7 @@ com.opencsv opencsv - 5.6 + 5.7.1 From ba95c1852f199dc6d95855e399dd820aa6e5b54f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 20:32:55 +0000 Subject: [PATCH 039/230] Update dependency org.glassfish.jaxb:jaxb-runtime to v2.3.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5da3aef26215..e51bc02cf577 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 2.13.4.2 1.3.2 2.3.1 - 2.3.1 + 2.3.8 1.1.1 9.4.53.v20231009 From e14f267229371eaac186ad66ee21561f684c1e47 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 19:32:15 +0000 Subject: [PATCH 040/230] Update dependency org.apache.james:apache-mime4j-core to v0.8.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e51bc02cf577..8af14a95e277 100644 --- a/pom.xml +++ b/pom.xml @@ -1302,7 +1302,7 @@ org.apache.james apache-mime4j-core - 0.8.4 + 0.8.9 From 53c4e18159db21bdac2d32d1ab56a4bc4d11560f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 14:47:00 +0000 Subject: [PATCH 041/230] Update dependency commons-io:commons-io to v2.12.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8af14a95e277..ac9985276455 100644 --- a/pom.xml +++ b/pom.xml @@ -1489,7 +1489,7 @@ commons-io commons-io - 2.7 + 2.12.0 org.apache.commons From 8895aca3eb2f1c3ea645595b3ef9d14fd8b272fb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 14:55:45 +0000 Subject: [PATCH 042/230] Update dependency commons-validator:commons-validator to v1.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ac9985276455..93ad8008e668 100644 --- a/pom.xml +++ b/pom.xml @@ -1516,7 +1516,7 @@ commons-validator commons-validator - 1.5.0 + 1.7 joda-time From 167033d8305bb521c71ab8192451875a0462ee0e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 14:55:40 +0000 Subject: [PATCH 043/230] Update dependency commons-codec:commons-codec to v1.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 93ad8008e668..44e032e2462d 100644 --- a/pom.xml +++ b/pom.xml @@ -1456,7 +1456,7 @@ commons-codec commons-codec - 1.10 + 1.15 org.apache.commons From a9a8021cf658c151aa38579a211658219248a561 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 15:27:30 +0000 Subject: [PATCH 044/230] Update dependency commons-cli:commons-cli to v1.5.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 44e032e2462d..7b0edc065c5d 100644 --- a/pom.xml +++ b/pom.xml @@ -1451,7 +1451,7 @@ commons-cli commons-cli - 1.4 + 1.5.0 commons-codec From b5a59c76e8fc6e202d0362a0c46858a6070334c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 19:33:38 +0000 Subject: [PATCH 045/230] Update dependency joda-time:joda-time to v2.12.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7b0edc065c5d..6e47dc59ecfc 100644 --- a/pom.xml +++ b/pom.xml @@ -1521,7 +1521,7 @@ joda-time joda-time - 2.9.2 + 2.12.5 com.sun.mail From 8e66812dbbd85eddc51bfc5036bd249ddd67cf96 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Sun, 4 Jun 2023 22:25:40 +0300 Subject: [PATCH 046/230] pom.xml: bump Jersey Bump jersey due to jersey-media-json-jackson pulling in a conflicting jakarta.xml.bind-api via transitive dependency in dspace-rest, which is the legacy DSpace 6 REST API. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6e47dc59ecfc..054a04dbd741 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ https://jena.apache.org/documentation/migrate_jena2_jena3.html --> 2.13.0 - 2.35 + 2.39.1 UTF-8 From f9469c9b6f97c2031d76b4671f357fb93ec5b4c5 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Sun, 4 Jun 2023 22:26:54 +0300 Subject: [PATCH 047/230] dspace-api/pom.xml: add exclusion for javassist Add an exclusion for org.javassist:javassist due to a dependency convergence error caused by eu.openaire:funders-model pulling in a version conflicting with Jersey's transitive dependency. --- dspace-api/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 62964053961a..a90dc0e1d92b 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -821,6 +821,13 @@ eu.openaire funders-model 2.0.0 + + + + org.javassist + javassist + + From 36c042bc98fc932f21bdd938e205f99fa30e4dc9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 06:03:24 +0000 Subject: [PATCH 048/230] Update dependency org.webjars.bowergithub.medialize:uri.js to v1.19.11 --- dspace-server-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 3df2f2d5e221..4b3e79431e97 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -322,7 +322,7 @@ org.webjars.bowergithub.medialize uri.js - 1.19.10 + 1.19.11 From fe8c3ef38843a576c5e75accbf51b1e4c0616943 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 06:01:11 +0000 Subject: [PATCH 049/230] Update dependency com.fasterxml:classmate to v1.5.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 054a04dbd741..1ff8a92524cf 100644 --- a/pom.xml +++ b/pom.xml @@ -1752,7 +1752,7 @@ com.fasterxml classmate - 1.3.0 + 1.5.1 com.fasterxml.jackson.core From 7b0b21f84de121713fcb080171feac6064117e95 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 06:03:29 +0000 Subject: [PATCH 050/230] Update dependency org.webjars.bowergithub.jquery:jquery-dist to v3.7.0 --- dspace-server-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 4b3e79431e97..40b61139ee72 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -308,7 +308,7 @@ org.webjars.bowergithub.jquery jquery-dist - 3.6.0 + 3.7.0 From 69e1ff98a0de01995ac10a1d69d33ceca064e39b Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Mon, 5 Jun 2023 10:33:46 +0300 Subject: [PATCH 051/230] Bump xom:xom dependency No breaking changes, but some bug fixes, performance improvements, and compatibility fixes with Java 17+. See: https://xom.nu/history.html --- dspace-sword/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 900ede5fc507..52783e3ec571 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -104,7 +104,7 @@ xom xom - 1.3.7 + 1.3.9 commons-io diff --git a/pom.xml b/pom.xml index 1ff8a92524cf..31fcf8f75a57 100644 --- a/pom.xml +++ b/pom.xml @@ -1784,7 +1784,7 @@ xom xom - 1.2.5 + 1.3.9 From 096fb3fb74e29b8c6eee8155c6940084a00f8039 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Mon, 5 Jun 2023 10:36:44 +0300 Subject: [PATCH 052/230] Bump jaxen:jaxen dependency to 2.0.0 Should be mostly drop-in API compatible with Jaxen 1.1.x, but more importantly it makes the xom dependency optional so we can remove the exclusions in our various pom.xml files. See: http://cafeconleche.org/jaxen/releases.html --- dspace-api/pom.xml | 6 ------ pom.xml | 8 +------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index a90dc0e1d92b..0fdf045c10a6 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -495,12 +495,6 @@ jaxen jaxen - - - xom - xom - - org.jdom diff --git a/pom.xml b/pom.xml index 31fcf8f75a57..2d7edd8763d9 100644 --- a/pom.xml +++ b/pom.xml @@ -1538,13 +1538,7 @@ jaxen jaxen - 1.1.6 - - - xom - xom - - + 2.0.0 org.jdom From 6b4e5ed9c8236490157bde819d570c64b3a2aca1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 25 Jun 2023 16:37:20 +0000 Subject: [PATCH 053/230] Update dependency org.apache.bcel:bcel to v6.7.0 --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 0fdf045c10a6..bb9bf675584a 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -806,7 +806,7 @@ org.apache.bcel bcel - 6.6.0 + 6.7.0 test From e92e5ee6d847974da9f2f530393af9a7a52818b6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 04:40:30 +0000 Subject: [PATCH 054/230] Update dependency org.scala-lang:scala-library to v2.13.11 --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index bb9bf675584a..57362fa75390 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -926,7 +926,7 @@ org.scala-lang scala-library - 2.13.9 + 2.13.11 test From af29486965dafd017bcc471d45898c4a1e9330c9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 04:53:45 +0000 Subject: [PATCH 055/230] Update dependency commons-io:commons-io to v2.13.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2d7edd8763d9..8b53afa9e5c1 100644 --- a/pom.xml +++ b/pom.xml @@ -1489,7 +1489,7 @@ commons-io commons-io - 2.12.0 + 2.13.0 org.apache.commons From 5152e99bda9f3ef9ac531f9bd460d60d9c8ba6fb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 04:56:57 +0000 Subject: [PATCH 056/230] Update dependency org.exparity:hamcrest-date to v2.0.8 --- dspace-server-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 40b61139ee72..7f48c5dde2a4 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -541,7 +541,7 @@ org.exparity hamcrest-date - 2.0.7 + 2.0.8 test From 972c2d69c8ba890b13d9365f5809d1e14d20be17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 10:49:50 +0000 Subject: [PATCH 057/230] Update dependency commons-codec:commons-codec to v1.16.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8b53afa9e5c1..1d3fed2d51fb 100644 --- a/pom.xml +++ b/pom.xml @@ -1456,7 +1456,7 @@ commons-codec commons-codec - 1.15 + 1.16.0 org.apache.commons From ad061c962ba7c5ac27e9649f9dac6b0750daeada Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Fri, 30 Jun 2023 21:38:32 +0300 Subject: [PATCH 058/230] pom.xml: update spring boot to v2.7.13 Minor update. Also bump the spring security version to 5.7.9 as is used by spring boot. See: https://github.com/spring-projects/spring-boot/releases/tag/v2.7.13 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1d3fed2d51fb..15039783cee9 100644 --- a/pom.xml +++ b/pom.xml @@ -20,8 +20,8 @@ 11 5.3.27 - 2.7.12 - 5.7.8 + 2.7.13 + 5.7.9 5.6.15.Final 6.2.5.Final 42.6.0 From 16b1104b0164eb397e2b2f8915282adb2a59ab50 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Fri, 30 Jun 2023 21:41:41 +0300 Subject: [PATCH 059/230] pom.xml: bump spring core version to v5.3.28 Minor version bump with some bug fixes. See: https://github.com/spring-projects/spring-framework/releases/tag/v5.3.28 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 15039783cee9..a071ae2c7a00 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 11 - 5.3.27 + 5.3.28 2.7.13 5.7.9 5.6.15.Final From 79178e3b62cf83e4dcfca1bdab8c483da89561a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jul 2023 15:18:28 +0000 Subject: [PATCH 060/230] Update pdfbox-version to v2.0.29 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a071ae2c7a00..36f6a880e9cf 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 9.4.53.v20231009 2.20.0 - 2.0.28 + 2.0.29 1.19.0 1.7.36 2.5.0 From 0d1dd13c842d625bd8ab6661281905963cde2cc0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 05:24:34 +0000 Subject: [PATCH 061/230] Update dependency com.h2database:h2 to v2.2.224 (cherry picked from commit 0d4c1ea63ab7cdd5ea79511228a5486a46c2a515) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 36f6a880e9cf..5f349232886d 100644 --- a/pom.xml +++ b/pom.xml @@ -1688,7 +1688,7 @@ com.h2database h2 - 2.2.220 + 2.2.224 test From 7a38f0097d57907555b434f83492e80bcc065cc5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 05:38:10 +0000 Subject: [PATCH 062/230] Update dependency org.glassfish.jaxb:jaxb-runtime to v2.3.9 (cherry picked from commit 8d6f6e37b3beed98b9d20327cbb67ce683da9b3c) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f349232886d..df57ea816569 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 2.13.4.2 1.3.2 2.3.1 - 2.3.8 + 2.3.9 1.1.1 9.4.53.v20231009 From a50534d617a3f14264a1750cc5d7ebbe3d737557 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 05:44:02 +0000 Subject: [PATCH 063/230] Update pdfbox-version to v2.0.30 (cherry picked from commit fe7800ab5a7d9b77e9783d09b000aff19be38c96) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index df57ea816569..f63ac3d053cd 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 9.4.53.v20231009 2.20.0 - 2.0.29 + 2.0.30 1.19.0 1.7.36 2.5.0 From 602e9e854f23932a60be6be9ddafa0f6362738f7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 05:51:40 +0000 Subject: [PATCH 064/230] Update dependency commons-cli:commons-cli to v1.6.0 (cherry picked from commit f67e0f65091b85d191d3694ea80339d42833ed9f) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f63ac3d053cd..be0c732165e5 100644 --- a/pom.xml +++ b/pom.xml @@ -1451,7 +1451,7 @@ commons-cli commons-cli - 1.5.0 + 1.6.0 commons-codec From f7c7abc36201a38154b2d3ec3246aa8bb9e9bf22 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 05:52:16 +0000 Subject: [PATCH 065/230] Update dependency com.opencsv:opencsv to v5.9 (cherry picked from commit ab9279cbb88e8511f28fa01f7d2a005b61eca1d2) --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 57362fa75390..b79a088dc90c 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -788,7 +788,7 @@ com.opencsv opencsv - 5.7.1 + 5.9 From ed74d3198cf277b73fc1516e26f99b0e9ac74690 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 05:52:20 +0000 Subject: [PATCH 066/230] Update dependency commons-io:commons-io to v2.15.1 (cherry picked from commit 70646a30de182a23b3f7ee675ff74a9a79c76b1f) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index be0c732165e5..e3b05649ef6c 100644 --- a/pom.xml +++ b/pom.xml @@ -1489,7 +1489,7 @@ commons-io commons-io - 2.13.0 + 2.15.1 org.apache.commons From 279a315301c7bf4df56bb95fde959c3256bd1506 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 06:24:36 +0000 Subject: [PATCH 067/230] Update log4j.version to v2.22.1 (cherry picked from commit a6978137203c6c8112b9d31c095bf8c7823fe8db) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e3b05649ef6c..66f243304b1c 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 1.1.1 9.4.53.v20231009 - 2.20.0 + 2.22.1 2.0.30 1.19.0 1.7.36 From 8edd8bc09bfe002f9e2840854a15bde7aab9d8ec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 06:33:06 +0000 Subject: [PATCH 068/230] Update dependency com.fasterxml:classmate to v1.6.0 (cherry picked from commit 07ec54832a7a8380a0d1c7b361e57938ed88360f) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 66f243304b1c..b69554a72d8d 100644 --- a/pom.xml +++ b/pom.xml @@ -1746,7 +1746,7 @@ com.fasterxml classmate - 1.5.1 + 1.6.0 com.fasterxml.jackson.core From 28d051e88d7f03a2b51261622d6b0b0fb4d49758 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 08:13:14 +0000 Subject: [PATCH 069/230] Update dependency org.xmlunit:xmlunit-core to v2.9.1 (cherry picked from commit 0958a98b1f4d339cfdca50ff65081ae0730b0d74) --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index b79a088dc90c..1b539a5cc394 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -900,7 +900,7 @@ org.xmlunit xmlunit-core - 2.8.0 + 2.9.1 test From a77628bd1e2e55b47492938ab68b0be7fb2b2ef9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 08:16:05 +0000 Subject: [PATCH 070/230] Update dependency com.maxmind.geoip2:geoip2 to v2.17.0 (cherry picked from commit 68caa1dcf8e7c5687fc250ed62704832d93aa362) --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 1b539a5cc394..920cdfcf4627 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -620,7 +620,7 @@ com.maxmind.geoip2 geoip2 - 2.11.0 + 2.17.0 org.apache.ant From 4840b1de834a00d8eebe7f3e2461ff77c2839482 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 09:06:03 +0000 Subject: [PATCH 071/230] Update netty monorepo to v4.1.106.Final (cherry picked from commit 71ea2a752665bd6eaeb27575bd3fdf3ac05eacd4) --- dspace-api/pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 920cdfcf4627..b1aa3f246cfa 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -865,32 +865,32 @@ io.netty netty-buffer - 4.1.94.Final + 4.1.106.Final io.netty netty-transport - 4.1.94.Final + 4.1.106.Final io.netty netty-transport-native-unix-common - 4.1.94.Final + 4.1.106.Final io.netty netty-common - 4.1.94.Final + 4.1.106.Final io.netty netty-handler - 4.1.94.Final + 4.1.106.Final io.netty netty-codec - 4.1.94.Final + 4.1.106.Final org.apache.velocity From b603776a08c7367c15eef94f03e7eee3a34de79f Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Wed, 29 Nov 2023 08:33:39 +0300 Subject: [PATCH 072/230] pom.xml: update Spring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to keep Spring Framework, Spring Boot, and Spring Security versions updated together: - Spring Framework: 5.3.28→5.3.31 - Spring Boot: 2.7.13→2.7.18 - Spring Security: 5.7.9→5.7.11 (cherry picked from commit f42a981d1bfc588c5a42d918036110f2b92b1b8a) --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b69554a72d8d..1502c0f7c509 100644 --- a/pom.xml +++ b/pom.xml @@ -19,9 +19,9 @@ 11 - 5.3.28 - 2.7.13 - 5.7.9 + 5.3.31 + 2.7.18 + 5.7.11 5.6.15.Final 6.2.5.Final 42.6.0 From 487202e246d7afe10e614da12e4afbb998cd4e50 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Wed, 29 Nov 2023 10:01:27 +0300 Subject: [PATCH 073/230] pom.xml: update spotbugs and spotbugs-maven-plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update to latest versions: - spotbugs v4.1.2→v4.8.2 - spotbugs-maven-plugin v4.0.4→v4.8.2.0 These are not run in CI and seem to only run manually when asked, ie via maven: $ mvn spotbugs:spotbugs (cherry picked from commit fc6a9ca5cb2dec321c2ad67f722dcc6a2e894bc1) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1502c0f7c509..fc20c0059ac4 100644 --- a/pom.xml +++ b/pom.xml @@ -294,7 +294,7 @@ com.github.spotbugs spotbugs-maven-plugin - 4.0.4 + 4.8.2.0 Max Low @@ -304,7 +304,7 @@ com.github.spotbugs spotbugs - 4.1.2 + 4.8.2 From 5342d540751c6a0837fcf2636222d40adeea3b4c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 07:07:13 +0000 Subject: [PATCH 074/230] Update dependency org.apache.ant:ant to v1.10.14 (cherry picked from commit 4e071b2428d66d7350abc451598f75ba647e3394) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fc20c0059ac4..e89b5c9dae2a 100644 --- a/pom.xml +++ b/pom.xml @@ -1336,7 +1336,7 @@ org.apache.ant ant - 1.10.13 + 1.10.14 org.apache.jena From b2494c6be2a942f1b89d4b80b5b934db633cda34 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 07:24:40 +0000 Subject: [PATCH 075/230] Update json-path.version to v2.8.0 (cherry picked from commit 8809e98a18ba1980e99584b21ffb427ed70e028e) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e89b5c9dae2a..da087bdc9feb 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ - 2.6.0 + 2.8.0 7.9 From c7c8062f014fbf8cbc4609b676c31f6cc8c07e68 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Wed, 29 Nov 2023 12:46:35 +0300 Subject: [PATCH 076/230] Update hamcrest to v2.2 Due to changes in hamcrest packaging we only need the main artifact now, but we add hamcrest-core (which is an empty pom) so it doesn't get pulled in by other deps. Last, the hamcrest docs recommend that we put hamcrest first so that we don't have dependency convergence issues from junit. See: https://hamcrest.org/JavaHamcrest/distributables (cherry picked from commit 710feb798d2ad2192f2941fd5beeede30b7d8498) --- dspace-api/pom.xml | 2 +- dspace-oai/pom.xml | 2 +- dspace-server-webapp/pom.xml | 2 +- dspace/modules/additions/pom.xml | 2 +- pom.xml | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index b1aa3f246cfa..5b578fa49d5a 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -528,7 +528,7 @@ org.hamcrest - hamcrest-all + hamcrest test diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index c9d8285559c1..748f6ad2deef 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -156,7 +156,7 @@ org.hamcrest - hamcrest-all + hamcrest compile diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 7f48c5dde2a4..05a24cf7d167 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -502,7 +502,7 @@ org.hamcrest - hamcrest-all + hamcrest test diff --git a/dspace/modules/additions/pom.xml b/dspace/modules/additions/pom.xml index 84b53171bf37..7e60e982ec45 100644 --- a/dspace/modules/additions/pom.xml +++ b/dspace/modules/additions/pom.xml @@ -273,7 +273,7 @@ org.hamcrest - hamcrest-core + hamcrest test diff --git a/pom.xml b/pom.xml index da087bdc9feb..7e078fa21f90 100644 --- a/pom.xml +++ b/pom.xml @@ -1661,21 +1661,21 @@ - junit - junit - 4.13.2 + org.hamcrest + hamcrest + 2.2 test org.hamcrest - hamcrest-all - 1.3 + hamcrest-core + 2.2 test - org.hamcrest - hamcrest-core - 1.3 + junit + junit + 4.13.2 test From 752d94efb4a32d4da6d019261f8ce25779843bd8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 07:37:42 +0000 Subject: [PATCH 077/230] Update dependency org.apache.maven.plugins:maven-checkstyle-plugin to v3.3.1 (cherry picked from commit ae12f1865fd18b5ba642bdd1852934c57dfbb49d) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7e078fa21f90..9770e2085e53 100644 --- a/pom.xml +++ b/pom.xml @@ -257,7 +257,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 3.1.0 + 3.3.1 verify-style From 88edfbbfdfde82498a4e492e274bd5c0eabab485 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 09:53:22 +0000 Subject: [PATCH 078/230] Update dependency org.apache.maven.plugins:maven-assembly-plugin to v3.6.0 (cherry picked from commit 275757e6d46b9175b81748722114fcef9a62e1b4) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9770e2085e53..fe6a9fd93630 100644 --- a/pom.xml +++ b/pom.xml @@ -334,7 +334,7 @@ maven-assembly-plugin - 3.2.0 + 3.6.0 org.apache.maven.plugins From 9cb4eac8027c9cddbf8c3c3a7f6573b15fa4da87 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 06:31:33 +0000 Subject: [PATCH 079/230] Update dependency org.webjars.bowergithub.twbs:bootstrap to v4.6.2 (cherry picked from commit 2c1a45bc8840614690bacfbeb8fa4dfbe5b42d70) --- dspace-server-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 05a24cf7d167..5f2a256f3e0a 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -354,7 +354,7 @@ org.webjars.bowergithub.twbs bootstrap - 4.6.1 + 4.6.2 From 4dcbe16e24fa7903a90bea99517ab5c63c226091 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 06:32:41 +0000 Subject: [PATCH 080/230] Update dependency org.webjars.bowergithub.jquery:jquery-dist to v3.7.1 (cherry picked from commit 6d0b5deb8e2553be8afc1f4892f5e74353b5fdc2) --- dspace-server-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 5f2a256f3e0a..2165d546caf4 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -308,7 +308,7 @@ org.webjars.bowergithub.jquery jquery-dist - 3.7.0 + 3.7.1 From 4682db506ec5e7c89cfb2c8cdf8ba30dc3192f9a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 06:31:39 +0000 Subject: [PATCH 081/230] Update dependency org.apache.commons:commons-lang3 to v3.14.0 (cherry picked from commit 3f675d9cd5bddea7d31de39db44183b36941492c) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fe6a9fd93630..50a76f9cd0ea 100644 --- a/pom.xml +++ b/pom.xml @@ -1494,7 +1494,7 @@ org.apache.commons commons-lang3 - 3.12.0 + 3.14.0 From 186453eb3f472951fbfe7a6e869bd8ebe04f2482 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 06:30:59 +0000 Subject: [PATCH 082/230] Update dependency commons-logging:commons-logging to v1.3.0 (cherry picked from commit e76132b4d8c1984994bfb150e3a3abdcff6f69a8) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 50a76f9cd0ea..44cde8d4c640 100644 --- a/pom.xml +++ b/pom.xml @@ -1501,7 +1501,7 @@ commons-logging commons-logging - 1.2 + 1.3.0 org.apache.commons From 1f67a2bffeaade8813a9f5b9b41d9c30235ffc75 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:42:09 +0000 Subject: [PATCH 083/230] Update dependency org.apache.commons:commons-configuration2 to v2.9.0 (cherry picked from commit b583029a7d1e3b6a56f31ef2e086147ff005bab6) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 44cde8d4c640..af6df1ae9330 100644 --- a/pom.xml +++ b/pom.xml @@ -1474,7 +1474,7 @@ org.apache.commons commons-configuration2 - 2.8.0 + 2.9.0 org.apache.commons From bdb19787bb3a1e6042a018b5c0b9ab7d20ce83c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:42:44 +0000 Subject: [PATCH 084/230] Update dependency org.apache.commons:commons-collections4 to v4.4 (cherry picked from commit 6de85adeb7afa0d91ee0bf3273b8494d5b5d33c1) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index af6df1ae9330..63e130b08105 100644 --- a/pom.xml +++ b/pom.xml @@ -1461,7 +1461,7 @@ org.apache.commons commons-collections4 - 4.1 + 4.4 - 2.13.4 - 2.13.4.2 + 2.16.0 + 2.16.0 1.3.2 2.3.1 2.3.9 From 762c0397fe252061b382adf5e3304f8eb29d1dd8 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Mon, 5 Feb 2024 17:41:40 +0300 Subject: [PATCH 086/230] pom.xml: update commons-dbcp2 and commons-pool2 Update commons-dbcp2 and commons-pool2 to latest stable versions. (cherry picked from commit bafb1b56570df3b4bfea045ccc913af0f0994cce) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8626865f2dc8..d3a0128ce341 100644 --- a/pom.xml +++ b/pom.xml @@ -1479,7 +1479,7 @@ org.apache.commons commons-dbcp2 - 2.9.0 + 2.11.0 commons-fileupload @@ -1506,7 +1506,7 @@ org.apache.commons commons-pool2 - 2.11.1 + 2.12.0 org.apache.commons From 9274a117597d85ad4e485091a6452e935d31b0de Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Mon, 5 Feb 2024 22:21:50 +0300 Subject: [PATCH 087/230] dspace-server-webapp/pom.xml: upgrade zjsonpatch Upgrade zjsonpatch from v0.4.6 to v0.4.16. (cherry picked from commit 20fc8e4fb7c5deb81f66d926712da7fdbe25a687) --- dspace-server-webapp/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 2165d546caf4..5395169950bc 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -288,7 +288,7 @@ com.flipkart.zjsonpatch zjsonpatch - 0.4.14 + 0.4.16 From 6d5949729d0c7c68d01dfe277d5aadc51005cf77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:30:28 +0000 Subject: [PATCH 088/230] Bump com.jayway.jsonpath:json-path from 2.6.0 to 2.9.0 Bumps [com.jayway.jsonpath:json-path](https://github.com/jayway/JsonPath) from 2.6.0 to 2.9.0. - [Release notes](https://github.com/jayway/JsonPath/releases) - [Changelog](https://github.com/json-path/JsonPath/blob/master/changelog.md) - [Commits](https://github.com/jayway/JsonPath/compare/json-path-2.6.0...json-path-2.9.0) --- updated-dependencies: - dependency-name: com.jayway.jsonpath:json-path dependency-type: direct:development ... Signed-off-by: dependabot[bot] (cherry picked from commit db56de3887109404bb849413f5a02023ebb9bcae) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d3a0128ce341..f940dfb97a37 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ - 2.8.0 + 2.9.0 7.9 From 6624248c7affed8f8b801f113d70c0912f26f074 Mon Sep 17 00:00:00 2001 From: Kim Shepherd Date: Wed, 7 Feb 2024 12:11:06 +1300 Subject: [PATCH 089/230] Improve default identifiers.cfg properties (Related to dspace-angular#2765) (cherry picked from commit 40b7427d884002a0916ec4a3e687280e9426d081) --- dspace/config/modules/identifiers.cfg | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dspace/config/modules/identifiers.cfg b/dspace/config/modules/identifiers.cfg index 63a9cda30f17..2660646af394 100644 --- a/dspace/config/modules/identifiers.cfg +++ b/dspace/config/modules/identifiers.cfg @@ -41,9 +41,7 @@ # Show Register DOI button in item status page? # Default: false -# This configuration property is exposed over rest. For dspace-angular to work, -# this property must always have a true or false value. Do not comment it out! -identifiers.item-status.register-doi = false +#identifiers.item-status.register-doi = true # Which identifier types to show in submission step? # Default: handle, doi (currently the only supported identifier 'types') From 09357b133e033f9ba9da3593ad650830a7d81143 Mon Sep 17 00:00:00 2001 From: MajoBerger Date: Fri, 9 Jun 2023 11:22:50 +0200 Subject: [PATCH 090/230] added failsafe while creating admin when db is not connected (cherry picked from commit efcf9dba20ac4c49516d8486a33e14f06db86080) --- .../org/dspace/administer/CreateAdministrator.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java index 81250e9c8259..58b85493915a 100644 --- a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java +++ b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java @@ -116,6 +116,17 @@ public static void main(String[] argv) protected CreateAdministrator() throws Exception { context = new Context(); + try { + context.getDBConfig(); + } catch (NullPointerException npr) { + // if database is null, there is no point in continuing. Prior to this exception and catch, + // NullPointerException was thrown, that wasn't very helpful. + throw new IllegalStateException("Problem connecting to database. This " + + "indicates issue with either network or version (or possibly some other). " + + "If you are running this in docker-compose, please make sure dspace-cli was " + + "built from the same sources as running dspace container AND that they are in " + + "the same project/network."); + } groupService = EPersonServiceFactory.getInstance().getGroupService(); ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); } From 4942fd272ce2259e3199f07f821236c05f9dae36 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Thu, 15 Feb 2024 10:31:04 +0100 Subject: [PATCH 091/230] 106812: Fix compile issue due to new test --- .../test/java/org/dspace/app/rest/ItemRestRepositoryIT.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 73bae1219d56..714ad0b419a1 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 @@ -2936,7 +2936,7 @@ public void specificEmbedTestMultipleLevelOfLinksWithData() throws Exception { BitstreamMatcher.matchBitstreamEntryWithoutEmbed(bitstream2.getID(), bitstream2.getSizeBytes()) ))) .andExpect(jsonPath("$._embedded.owningCollection._embedded.mappedItems." + - "_embedded.mappedItems[0]_embedded.relationships").doesNotExist()) + "_embedded.mappedItems[0]._embedded.relationships").doesNotExist()) .andExpect(jsonPath("$._embedded.owningCollection._embedded.mappedItems" + "._embedded.mappedItems[0]._embedded.bundles._embedded.bundles[0]." + "_embedded.primaryBitstream").doesNotExist()) @@ -3045,8 +3045,7 @@ public void testHiddenMetadataForUserWithReadRights() throws Exception { context.restoreAuthSystemState(); - ResourcePolicyBuilder.createResourcePolicy(context) - .withUser(eperson) + ResourcePolicyBuilder.createResourcePolicy(context, eperson, null) .withAction(READ) .withDspaceObject(item) .build(); From b97b093d6c97d47599ea7ed00a6b93fd2d3fd1b6 Mon Sep 17 00:00:00 2001 From: mohamed eskander Date: Wed, 17 Jan 2024 10:39:18 +0200 Subject: [PATCH 092/230] [DURACOM-143] Fix indexing errors & further improvements (cherry picked from commit d645939baf07d10d0f9f0b5e7b2722556400ff97) --- .../indexobject/IndexFactoryImpl.java | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java index 55c99b168e7a..4b012a072f33 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java @@ -2,7 +2,7 @@ * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at - * + *

* http://www.dspace.org/license/ */ package org.dspace.discovery.indexobject; @@ -64,7 +64,14 @@ public SolrInputDocument buildDocument(Context context, T indexableObject) throw //Do any additional indexing, depends on the plugins for (SolrServiceIndexPlugin solrServiceIndexPlugin : ListUtils.emptyIfNull(solrServiceIndexPlugins)) { - solrServiceIndexPlugin.additionalIndex(context, indexableObject, doc); + try { + solrServiceIndexPlugin.additionalIndex(context, indexableObject, doc); + } catch (Exception e) { + log.error("An error occurred while indexing additional fields. " + + "Could not fully index item with UUID: {}. Plugin: {}", + indexableObject.getUniqueIndexID(), solrServiceIndexPlugin.getClass().getSimpleName()); + + } } return doc; @@ -82,7 +89,7 @@ public void writeDocument(Context context, T indexableObject, SolrInputDocument writeDocument(solrInputDocument, null); } catch (Exception e) { log.error("Error occurred while writing SOLR document for {} object {}", - indexableObject.getType(), indexableObject.getID(), e); + indexableObject.getType(), indexableObject.getID(), e); } } @@ -101,8 +108,8 @@ protected void writeDocument(SolrInputDocument doc, FullTextContentStreams strea if (streams != null && !streams.isEmpty()) { // limit full text indexing to first 100,000 characters unless configured otherwise final int charLimit = DSpaceServicesFactory.getInstance().getConfigurationService() - .getIntProperty("discovery.solr.fulltext.charLimit", - 100000); + .getIntProperty("discovery.solr.fulltext.charLimit", + 100000); // Use Tika's Text parser as the streams are always from the TEXT bundle (i.e. already extracted text) TextAndCSVParser tikaParser = new TextAndCSVParser(); @@ -113,6 +120,18 @@ protected void writeDocument(SolrInputDocument doc, FullTextContentStreams strea // Use Apache Tika to parse the full text stream(s) try (InputStream fullTextStreams = streams.getStream()) { tikaParser.parse(fullTextStreams, tikaHandler, tikaMetadata, tikaContext); + + // Write Tika metadata to "tika_meta_*" fields. + // This metadata is not very useful right now, + // but we'll keep it just in case it becomes more useful. + for (String name : tikaMetadata.names()) { + for (String value : tikaMetadata.getValues(name)) { + doc.addField("tika_meta_" + name, value); + } + } + + // Save (parsed) full text to "fulltext" field + doc.addField("fulltext", tikaHandler.toString()); } catch (SAXException saxe) { // Check if this SAXException is just a notice that this file was longer than the character limit. // Unfortunately there is not a unique, public exception type to catch here. This error is thrown @@ -121,30 +140,23 @@ protected void writeDocument(SolrInputDocument doc, FullTextContentStreams strea if (saxe.getMessage().contains("limit has been reached")) { // log that we only indexed up to that configured limit log.info("Full text is larger than the configured limit (discovery.solr.fulltext.charLimit)." - + " Only the first {} characters were indexed.", charLimit); + + " Only the first {} characters were indexed.", charLimit); } else { log.error("Tika parsing error. Could not index full text.", saxe); throw new IOException("Tika parsing error. Could not index full text.", saxe); } - } catch (TikaException ex) { + } catch (TikaException | IOException ex) { log.error("Tika parsing error. Could not index full text.", ex); throw new IOException("Tika parsing error. Could not index full text.", ex); + } finally { + // Add document to index + solr.add(doc); } - - // Write Tika metadata to "tika_meta_*" fields. - // This metadata is not very useful right now, but we'll keep it just in case it becomes more useful. - for (String name : tikaMetadata.names()) { - for (String value : tikaMetadata.getValues(name)) { - doc.addField("tika_meta_" + name, value); - } - } - - // Save (parsed) full text to "fulltext" field - doc.addField("fulltext", tikaHandler.toString()); + return; } - // Add document to index solr.add(doc); + } } From 14f593e097d8947549b446e0f21923ec0c13e79c Mon Sep 17 00:00:00 2001 From: mohamed eskander Date: Wed, 17 Jan 2024 10:56:08 +0200 Subject: [PATCH 093/230] [DURACOM-143] Fix license (cherry picked from commit 324d2e3184dd35d2980e599f173adf18a7e31d64) --- .../java/org/dspace/discovery/indexobject/IndexFactoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java index 4b012a072f33..f1ae137b9163 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java @@ -2,7 +2,7 @@ * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at - *

+ * * http://www.dspace.org/license/ */ package org.dspace.discovery.indexobject; From adec8e2e608f7e290c504c8d675cadf84a3102e6 Mon Sep 17 00:00:00 2001 From: haoueclf Date: Fri, 16 Feb 2024 16:51:41 +0100 Subject: [PATCH 094/230] [DS-9345] Correct the package name of the IIIF search plugin (cherry picked from commit 03fe58668114db529413d13d98af57c6e045e9df) --- dspace/config/modules/iiif.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace/config/modules/iiif.cfg b/dspace/config/modules/iiif.cfg index fc1e9bdf9f8d..9a2a3bb0d13a 100644 --- a/dspace/config/modules/iiif.cfg +++ b/dspace/config/modules/iiif.cfg @@ -15,7 +15,7 @@ iiif.image.server = http://localhost:8182/iiif/2/ # The search plugin used to support (experimental) IIIF Search. # This is the class used with https://dbmdz.github.io/solr-ocrhighlighting/ # It is currently the only supported option. -# iiif.search.plugin = org.dspace.app.rest.iiif.service.WordHighlightSolrSearch +# iiif.search.plugin = org.dspace.app.iiif.service.WordHighlightSolrSearch # Sets the viewing hint. Possible values: "paged" or "individuals". # Typically "paged" is preferred for multi-age documents. Use "individuals" From dddd500bd19de851aa82773b685afe4967f8e6cd Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Mon, 19 Feb 2024 10:06:33 +0100 Subject: [PATCH 095/230] 106812: Add flyway migration to remove faulty rp entries --- ..._2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql | 2 ++ ..._2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql index de40d0415dc6..2e352e2ee7cf 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql @@ -8,3 +8,5 @@ ALTER TABLE ResourcePolicy ADD CONSTRAINT resourcepolicy_eperson_and_epersongroup_not_nullobject_chk CHECK (eperson_id is not null or epersongroup_id is not null) ; + +DELETE FROM ResourcePolicy WHERE eperson_id is null and epersongroup_id is null; diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql index de40d0415dc6..2e352e2ee7cf 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql @@ -8,3 +8,5 @@ ALTER TABLE ResourcePolicy ADD CONSTRAINT resourcepolicy_eperson_and_epersongroup_not_nullobject_chk CHECK (eperson_id is not null or epersongroup_id is not null) ; + +DELETE FROM ResourcePolicy WHERE eperson_id is null and epersongroup_id is null; From d172865f520d3ad38dffb95372a2cf7a80f2dfd1 Mon Sep 17 00:00:00 2001 From: eskander Date: Fri, 9 Feb 2024 18:27:43 +0200 Subject: [PATCH 096/230] [DURACOM-232] solved Community/Collection admins can't edit logo for communities/collections (cherry picked from commit d1812866a6593c9efea88d555d64b057f7db3cad) --- .../java/org/dspace/content/Bitstream.java | 8 +++ .../java/org/dspace/content/Collection.java | 3 + .../java/org/dspace/content/Community.java | 3 + .../app/rest/CollectionLogoControllerIT.java | 67 +++++++++++++++++++ .../app/rest/CommunityLogoControllerIT.java | 58 ++++++++++++++++ 5 files changed, 139 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/Bitstream.java b/dspace-api/src/main/java/org/dspace/content/Bitstream.java index 451a3b75784d..5485735a2816 100644 --- a/dspace-api/src/main/java/org/dspace/content/Bitstream.java +++ b/dspace-api/src/main/java/org/dspace/content/Bitstream.java @@ -307,10 +307,18 @@ public Collection getCollection() { return collection; } + public void setCollection(Collection collection) { + this.collection = collection; + } + public Community getCommunity() { return community; } + public void setCommunity(Community community) { + this.community = community; + } + /** * Get the asset store number where this bitstream is stored * diff --git a/dspace-api/src/main/java/org/dspace/content/Collection.java b/dspace-api/src/main/java/org/dspace/content/Collection.java index 53b63dbef1fa..a13c19d46cf8 100644 --- a/dspace-api/src/main/java/org/dspace/content/Collection.java +++ b/dspace-api/src/main/java/org/dspace/content/Collection.java @@ -135,6 +135,9 @@ public Bitstream getLogo() { protected void setLogo(Bitstream logo) { this.logo = logo; + if (logo != null) { + logo.setCollection(this); + } setModified(); } diff --git a/dspace-api/src/main/java/org/dspace/content/Community.java b/dspace-api/src/main/java/org/dspace/content/Community.java index dd6d978936df..d82e08bab72e 100644 --- a/dspace-api/src/main/java/org/dspace/content/Community.java +++ b/dspace-api/src/main/java/org/dspace/content/Community.java @@ -123,6 +123,9 @@ public Bitstream getLogo() { void setLogo(Bitstream logo) { this.logo = logo; + if (logo != null) { + logo.setCommunity(this); + } setModified(); } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionLogoControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionLogoControllerIT.java index fa0732f6b774..8fd7f58d9cd6 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionLogoControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionLogoControllerIT.java @@ -17,7 +17,10 @@ import org.dspace.app.rest.test.AbstractControllerIntegrationTest; import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.EPersonBuilder; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.eperson.EPerson; import org.junit.Before; import org.junit.Test; import org.springframework.http.MediaType; @@ -93,6 +96,34 @@ public void createLogoNoRights() throws Exception { .andExpect(status().isForbidden()); } + @Test + public void createLogoByCollectionAdmin() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson collectionAdmin = EPersonBuilder.createEPerson(context) + .withEmail("test4@mail.com") + .withPassword(password) + .withCanLogin(true) + .build(); + + Community community = CommunityBuilder.createCommunity(context) + .withName("New Community") + .build(); + + childCollection = CollectionBuilder.createCollection(context, community) + .withName("name of collection") + .withAdminGroup(collectionAdmin) + .build(); + + context.restoreAuthSystemState(); + + String userToken = getAuthToken(collectionAdmin.getEmail(), password); + getClient(userToken).perform( + MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString())) + .file(bitstreamFile)) + .andExpect(status().isCreated()); + } + @Test public void createDuplicateLogo() throws Exception { getClient(adminAuthToken).perform( @@ -142,6 +173,42 @@ public void deleteLogoNoRights() throws Exception { .andExpect(status().isForbidden()); } + @Test + public void deleteLogoByCollectionAdmin() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson collectionAdmin = EPersonBuilder.createEPerson(context) + .withEmail("test4@mail.com") + .withPassword(password) + .withCanLogin(true) + .build(); + + Community community = CommunityBuilder.createCommunity(context) + .withName("New Community") + .build(); + + childCollection = CollectionBuilder.createCollection(context, community) + .withName("name of collection") + .withAdminGroup(collectionAdmin) + .build(); + + context.restoreAuthSystemState(); + + String userToken = getAuthToken(collectionAdmin.getEmail(), password); + MvcResult mvcPostResult = getClient(userToken).perform( + MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString())) + .file(bitstreamFile)) + .andExpect(status().isCreated()) + .andReturn(); + + String postContent = mvcPostResult.getResponse().getContentAsString(); + Map mapPostResult = mapper.readValue(postContent, Map.class); + + getClient(userToken) + .perform(delete(getBitstreamUrlTemplate(String.valueOf(mapPostResult.get("uuid"))))) + .andExpect(status().isNoContent()); + } + private String getLogoUrlTemplate(String uuid) { return "/api/core/collections/" + uuid + "/logo"; } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityLogoControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityLogoControllerIT.java index 3a0edc931049..f03e27b67749 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityLogoControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityLogoControllerIT.java @@ -16,6 +16,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.EPersonBuilder; +import org.dspace.content.Community; +import org.dspace.eperson.EPerson; import org.junit.Before; import org.junit.Test; import org.springframework.http.MediaType; @@ -88,6 +91,29 @@ public void createLogoNoRights() throws Exception { .andExpect(status().isForbidden()); } + @Test + public void createLogoBYCommunityAdmin() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson communityAdmin = EPersonBuilder.createEPerson(context) + .withEmail("test4@mail.com") + .withPassword(password) + .withCanLogin(true) + .build(); + + Community community = CommunityBuilder.createCommunity(context) + .withName("New Community") + .withAdminGroup(communityAdmin) + .build(); + + context.restoreAuthSystemState(); + String userToken = getAuthToken(communityAdmin.getEmail(), password); + getClient(userToken).perform( + MockMvcRequestBuilders.multipart(getLogoUrlTemplate(community.getID().toString())) + .file(bitstreamFile)) + .andExpect(status().isCreated()); + } + @Test public void createDuplicateLogo() throws Exception { getClient(adminAuthToken).perform( @@ -137,6 +163,38 @@ public void deleteLogoNoRights() throws Exception { .andExpect(status().isForbidden()); } + @Test + public void deleteLogoByCommunityAdmin() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson communityAdmin = EPersonBuilder.createEPerson(context) + .withEmail("test4@mail.com") + .withPassword(password) + .withCanLogin(true) + .build(); + + Community community = CommunityBuilder.createCommunity(context) + .withName("New Community") + .withAdminGroup(communityAdmin) + .build(); + + context.restoreAuthSystemState(); + + String userToken = getAuthToken(communityAdmin.getEmail(), password); + MvcResult mvcPostResult = getClient(userToken).perform( + MockMvcRequestBuilders.multipart(getLogoUrlTemplate(community.getID().toString())) + .file(bitstreamFile)) + .andExpect(status().isCreated()) + .andReturn(); + + String postContent = mvcPostResult.getResponse().getContentAsString(); + Map mapPostResult = mapper.readValue(postContent, Map.class); + + getClient(userToken) + .perform(delete(getBitstreamUrlTemplate(String.valueOf(mapPostResult.get("uuid"))))) + .andExpect(status().isNoContent()); + } + private String getLogoUrlTemplate(String uuid) { return "/api/core/communities/" + uuid + "/logo"; } From 61053cab8df8a05881a4290b2fcbd5b4539fecf5 Mon Sep 17 00:00:00 2001 From: Yannick Paulsen Date: Fri, 16 Feb 2024 12:08:00 +0100 Subject: [PATCH 097/230] Update of DataCite crosswalk to metadata schema 4.5 (cherry picked from commit 5db110a19f30f49a2e22c48d0a19044adfc008e1) --- dspace/config/crosswalks/DIM2DataCite.xsl | 111 ++++++++++++++-------- dspace/config/dspace.cfg | 6 +- 2 files changed, 75 insertions(+), 42 deletions(-) diff --git a/dspace/config/crosswalks/DIM2DataCite.xsl b/dspace/config/crosswalks/DIM2DataCite.xsl index e92c371d6a77..5cc3eecdda77 100644 --- a/dspace/config/crosswalks/DIM2DataCite.xsl +++ b/dspace/config/crosswalks/DIM2DataCite.xsl @@ -3,15 +3,14 @@ @@ -46,9 +45,9 @@ properties are in the metadata of the item to export. The classe named above respects this. --> - + - + - + + + + + + + + Other + Other + + + - + - + + + @@ -246,7 +264,7 @@ - @@ -255,6 +273,13 @@ + + - + + @@ -295,9 +328,14 @@ company as well. We have to ensure to use URIs of our prefix as primary identifiers only. --> - + - + + + + + + @@ -313,16 +351,20 @@ + + AlternativeTitle + Subtitle + TranslatedTitle @@ -341,6 +383,7 @@ --> + @@ -436,7 +479,7 @@ dissertations. DataCite uses submitted for the "date the creator submits the resource to the publisher". --> - Issued + Submitted Updated @@ -473,9 +516,9 @@ Audiovisual - Text - Text - Text + JournalArticle + Book + BookChapter Dataset InteractiveResource Image @@ -483,14 +526,14 @@ Model Other Model - Text - Text + Preprint + Other Sound Sound Sound Software - Text - Text + Report + Dissertation Audiovisual Text Other @@ -512,7 +555,7 @@ resolveUrlToHandle(context, altId) until one is recognized or all have been tested. --> - + @@ -561,20 +604,9 @@ Adds Rights information --> - - - - - - - - - - - - - - + + + + Abstract diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index d38ffd64339a..b7cc13e508dc 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 From ab56ad09ab78966b4572121c88dc66d0ce75233b Mon Sep 17 00:00:00 2001 From: Pascal-Nicolas Becker Date: Tue, 20 Feb 2024 12:38:08 +0100 Subject: [PATCH 098/230] Changing a comment on DIM2DataCite.xsl (cherry picked from commit 1a567827df61cff9931d84e8732886457304a7d5) --- dspace/config/crosswalks/DIM2DataCite.xsl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dspace/config/crosswalks/DIM2DataCite.xsl b/dspace/config/crosswalks/DIM2DataCite.xsl index 5cc3eecdda77..a97d127694ef 100644 --- a/dspace/config/crosswalks/DIM2DataCite.xsl +++ b/dspace/config/crosswalks/DIM2DataCite.xsl @@ -16,10 +16,15 @@ - + 10.5072/dspace- From 2c57c68a8129970b4abdaab50b750b63a34018e0 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 20 Dec 2023 12:25:02 -0600 Subject: [PATCH 099/230] Add more ITs to SWORDv2 to verify basic upload, edit, delete functionality. These all pass prior to any SWORDv2 refactoring (cherry picked from commit eeee0295107ccb2a84e0b2f9adf92536155efb5e) --- .../AbstractWebClientIntegrationTest.java | 14 +- .../java/org/dspace/app/sword2/Swordv2IT.java | 333 +++++++++++++++--- .../org/dspace/app/sword2/example.zip | Bin 0 -> 33777 bytes dspace/config/modules/swordv2-server.cfg | 1 + 4 files changed, 304 insertions(+), 44 deletions(-) create mode 100644 dspace-server-webapp/src/test/resources/org/dspace/app/sword2/example.zip diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java index 6556624c6b11..75b0143e3e65 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java @@ -19,6 +19,7 @@ import org.springframework.boot.web.server.LocalServerPort; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpEntity; +import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; @@ -94,6 +95,15 @@ public ResponseEntity getResponseAsString(String path) { return getClient().getForEntity(getURL(path), String.class); } + /** + * Perform a request (defined by RequestEntity) and return response as a String + * @param request RequestEntity object which defines the GET request + * @return ResponseEntity with a String body + */ + public ResponseEntity responseAsString(RequestEntity request) { + return getClient().exchange(request, String.class); + } + /** * Perform an authenticated (via Basic Auth) GET request and return response as a String * @param path path to perform GET against @@ -107,10 +117,10 @@ public ResponseEntity getResponseAsString(String path, String username, /** * Perform an authenticated (via Basic Auth) POST request and return response as a String. - * @param path path to perform GET against + * @param path path to perform POST against * @param username Username (may be null to perform an unauthenticated POST) * @param password Password - * @param requestEntity unknown -- not used. + * @param requestEntity HttpEntity to specify content/headers to POST * @return ResponseEntity with a String body */ public ResponseEntity postResponseAsString(String path, String username, String password, diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/sword2/Swordv2IT.java b/dspace-server-webapp/src/test/java/org/dspace/app/sword2/Swordv2IT.java index 95ec76251415..64e3db7dfc1a 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/sword2/Swordv2IT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/sword2/Swordv2IT.java @@ -9,19 +9,36 @@ package org.dspace.app.sword2; import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.nio.file.Path; +import java.util.List; import org.dspace.app.rest.test.AbstractWebClientIntegrationTest; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.ItemBuilder; +import org.dspace.content.Collection; +import org.dspace.content.Item; import org.dspace.services.ConfigurationService; import org.junit.Assume; import org.junit.Before; -import org.junit.Ignore; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.ContentDisposition; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import org.springframework.test.context.TestPropertySource; +import org.springframework.util.LinkedMultiValueMap; /** * Integration test to verify the /swordv2 endpoint is responding as a valid SWORDv2 endpoint. @@ -41,11 +58,24 @@ public class Swordv2IT extends AbstractWebClientIntegrationTest { private ConfigurationService configurationService; // All SWORD v2 paths that we test against - private final String SERVICE_DOC_PATH = "/swordv2/servicedocument"; - private final String COLLECTION_PATH = "/swordv2/collection"; - private final String MEDIA_RESOURCE_PATH = "/swordv2/edit-media"; - private final String CONTAINER_PATH = "/swordv2/edit"; - private final String STATEMENT_PATH = "/swordv2/statement"; + private final String SWORD_PATH = "/swordv2"; + private final String SERVICE_DOC_PATH = SWORD_PATH + "/servicedocument"; + private final String COLLECTION_PATH = SWORD_PATH + "/collection"; + private final String MEDIA_RESOURCE_PATH = SWORD_PATH + "/edit-media"; + private final String EDIT_PATH = SWORD_PATH + "/edit"; + private final String STATEMENT_PATH = SWORD_PATH + "/statement"; + + // Content Types used + private final String ATOM_SERVICE_CONTENT_TYPE = "application/atomserv+xml;charset=UTF-8"; + private final String ATOM_FEED_CONTENT_TYPE = "application/atom+xml;type=feed;charset=UTF-8"; + private final String ATOM_ENTRY_CONTENT_TYPE = "application/atom+xml;type=entry;charset=UTF-8"; + + /** + * Create a global temporary upload folder which will be cleaned up automatically by JUnit. + * NOTE: As a ClassRule, this temp folder is shared by ALL tests below. + **/ + @ClassRule + public static final TemporaryFolder uploadTempFolder = new TemporaryFolder(); @Before public void onlyRunIfConfigExists() { @@ -60,7 +90,18 @@ public void onlyRunIfConfigExists() { // Ensure SWORDv2 URL configurations are set correctly (based on our integration test server's paths) // SWORDv2 validates requests against these configs, and throws a 404 if they don't match the request path + configurationService.setProperty("swordv2-server.url", getURL(SWORD_PATH)); configurationService.setProperty("swordv2-server.servicedocument.url", getURL(SERVICE_DOC_PATH)); + configurationService.setProperty("swordv2-server.collection.url", getURL(COLLECTION_PATH)); + + // Override default value of SWORD upload directory to point at our JUnit TemporaryFolder (see above). + // This ensures uploaded files are saved in a place where JUnit can clean them up automatically. + configurationService.setProperty("swordv2-server.upload.tempdir", + uploadTempFolder.getRoot().getAbsolutePath()); + + // MUST be set to allow DELETE requests on Items which are in the archive. (This isn't enabled by default) + configurationService.setProperty("plugin.single.org.dspace.sword2.WorkflowManager", + "org.dspace.sword2.WorkflowManagerUnrestricted"); } @Test @@ -68,22 +109,20 @@ public void serviceDocumentUnauthorizedTest() throws Exception { // Attempt to GET the ServiceDocument without first authenticating ResponseEntity response = getResponseAsString(SERVICE_DOC_PATH); // Expect a 401 response code - assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); } @Test public void serviceDocumentTest() throws Exception { - // Attempt to GET the ServiceDocument as an Admin user. + // Attempt to GET the ServiceDocument as any user account ResponseEntity response = getResponseAsString(SERVICE_DOC_PATH, - admin.getEmail(), password); - // Expect a 200 response code, and an ATOM UTF-8 document - assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); - assertThat(response.getHeaders().getContentType().toString(), - equalTo("application/atomserv+xml;charset=UTF-8")); + eperson.getEmail(), password); + // Expect a 200 response code, and an ATOM service document + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(ATOM_SERVICE_CONTENT_TYPE, response.getHeaders().getContentType().toString()); // Check for correct SWORD version in response body - assertThat(response.getBody(), - containsString("2.0")); + assertThat(response.getBody(), containsString("2.0")); } @Test @@ -91,44 +130,204 @@ public void collectionUnauthorizedTest() throws Exception { // Attempt to POST to /collection endpoint without sending authentication information ResponseEntity response = postResponseAsString(COLLECTION_PATH, null, null, null); // Expect a 401 response code - assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); } + /** + * In DSpace the /collections/[handle-prefix]/[handle-suffix] endpoint gives a list of all Items + * which were deposited BY THE AUTHENTICATED USER into the given collection + */ @Test - @Ignore public void collectionTest() throws Exception { - // TODO: Actually test collection endpoint via SWORDv2. - // Currently, we are just ensuring the /collection endpoint exists (see above) and isn't throwing a 404 + context.turnOffAuthorisationSystem(); + // Create all content as the SAME EPERSON we will use to authenticate on this endpoint. + // THIS IS REQUIRED as the /collections endpoint will only show YOUR ITEM SUBMISSIONS. + context.setCurrentUser(eperson); + // Create a top level community and one Collection + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Test SWORDv2 Collection") + .build(); + + // Add one Item into that Collection. + String itemTitle = "Test SWORDv2 Item"; + Item item = ItemBuilder.createItem(context, collection) + .withTitle(itemTitle) + .withAuthor("Smith, Sam") + .build(); + + // Above changes MUST be committed to the database for SWORDv2 to see them. + context.commit(); + context.restoreAuthSystemState(); + + // This Collection should exist on the /collection endpoint via its handle. + // Authenticate as the same user we used to create the test content above. + ResponseEntity response = getResponseAsString(COLLECTION_PATH + "/" + collection.getHandle(), + eperson.getEmail(), password); + + // Expect a 200 response code, and an ATOM feed document + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(ATOM_FEED_CONTENT_TYPE, response.getHeaders().getContentType().toString()); + + // Check for response body to include the Item edit link + // NOTE: This endpoint will only list items which were submitted by the authenticated EPerson. + assertThat(response.getBody(), containsString(EDIT_PATH + "/" + item.getID().toString())); + // Check for response body to include the Item title text + assertThat(response.getBody(), containsString("" + itemTitle + "")); } @Test public void mediaResourceUnauthorizedTest() throws Exception { - // Attempt to POST to /mediaresource endpoint without sending authentication information + // Attempt to POST to /edit-media endpoint without sending authentication information ResponseEntity response = postResponseAsString(MEDIA_RESOURCE_PATH, null, null, null); // Expect a 401 response code - assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + assertEquals(response.getStatusCode(), HttpStatus.UNAUTHORIZED); } + /** + * This tests four different SWORDv2 actions, as these all require starting with a new deposit. + * 1. Depositing a new item via SWORD (via POST /collections/[collection-uuid]) + * 2. Reading the deposited item (via GET /edit/[item-uuid]) + * 3. Updating the deposited item's metadata (via PUT /edit/[item-uuid]) + * 4. Deleting the deposited item (via DELETE /edit/[item-uuid]). + */ @Test - @Ignore - public void mediaResourceTest() throws Exception { - // TODO: Actually test this endpoint via SWORDv2. - // Currently, we are just ensuring the /mediaresource endpoint exists (see above) and isn't throwing a 404 - } + public void depositAndEditViaSwordTest() throws Exception { + context.turnOffAuthorisationSystem(); + // Create a top level community and one Collection + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + // Make sure our Collection allows the "eperson" user to submit into it + Collection collection = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Test SWORDv2 Collection") + .withSubmitterGroup(eperson) + .build(); + // Above changes MUST be committed to the database for SWORDv2 to see them. + context.commit(); + context.restoreAuthSystemState(); - @Test - public void containerUnauthorizedTest() throws Exception { - // Attempt to POST to /container endpoint without sending authentication information - ResponseEntity response = postResponseAsString(CONTAINER_PATH, null, null, null); - // Expect a 401 response code - assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + // Add file + LinkedMultiValueMap multipart = new LinkedMultiValueMap<>(); + multipart.add("file", new FileSystemResource(Path.of("src", "test", "resources", + "org", "dspace", "app", "sword2", "example.zip"))); + // Add required headers + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + headers.setContentDisposition(ContentDisposition.attachment().filename("example.zip").build()); + headers.set("Packaging", "http://purl.org/net/sword/package/METSDSpaceSIP"); + headers.setAccept(List.of(MediaType.APPLICATION_ATOM_XML)); + + //---- + // STEP 1: Verify upload/submit via SWORDv2 works + //---- + // Send POST to upload Zip file via SWORD + ResponseEntity response = postResponseAsString(COLLECTION_PATH + "/" + collection.getHandle(), + eperson.getEmail(), password, + new HttpEntity<>(multipart, headers)); + + // Expect a 201 CREATED response with ATOM "entry" content returned + assertEquals(HttpStatus.CREATED, response.getStatusCode()); + assertEquals(ATOM_ENTRY_CONTENT_TYPE, response.getHeaders().getContentType().toString()); + // MUST return a "Location" header which is the "/swordv2/edit/[uuid]" URI of the created item + assertNotNull(response.getHeaders().getLocation()); + + String editLink = response.getHeaders().getLocation().toString(); + + // Body should include that link as the rel="edit" URL + assertThat(response.getBody(), containsString("")); + + //---- + // STEP 2: Verify uploaded content can be read via SWORDv2 + //---- + // Edit URI should work when requested by the EPerson who did the deposit + HttpHeaders authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + RequestEntity request = RequestEntity.get(editLink) + .accept(MediaType.valueOf("application/atom+xml")) + .headers(authHeaders) + .build(); + response = responseAsString(request); + + // Expect a 200 response with ATOM feed content returned + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(ATOM_FEED_CONTENT_TYPE, response.getHeaders().getContentType().toString()); + // Body should include links to bitstreams from the zip. + // This just verifies at least one /swordv2/edit-media/bitstream/* link exists. + assertThat(response.getBody(), containsString(getURL(MEDIA_RESOURCE_PATH + "/bitstream"))); + // Verify Item title also is returned in the body + assertThat(response.getBody(), containsString("Attempts to detect retrotransposition")); + + //---- + // STEP 3: Verify uploaded content can be UPDATED via SWORDv2 (by an Admin ONLY) + //---- + // Edit URI can be used with PUT to update the metadata of the Item. + // Since we submitted to a collection WITHOUT a workflow, this item is in archive. That means DELETE + // must be done via a user with Admin privileges on the Item. + authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(admin.getEmail(), password); + // This example simply changes the title. + String newTitle = "This is a new title updated via PUT"; + String newTitleEntry = "" + newTitle + ""; + request = RequestEntity.put(editLink) + .headers(authHeaders) + .contentType(MediaType.APPLICATION_ATOM_XML) + .body(newTitleEntry); + response = responseAsString(request); + // Expect a 200 OK response + assertEquals(HttpStatus.OK, response.getStatusCode()); + + //---- + // STEP 4: Verify content was successfully updated by reading content again + //---- + // Edit URI should work when requested by the EPerson who did the deposit + authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + request = RequestEntity.get(editLink) + .accept(MediaType.valueOf("application/atom+xml")) + .headers(authHeaders) + .build(); + response = responseAsString(request); + assertEquals(HttpStatus.OK, response.getStatusCode()); + // Verify the new Item title is now included in the response body + assertThat(response.getBody(), containsString(newTitle)); + + //---- + // STEP 5: Verify uploaded content can be DELETED via SWORDv2 (by an Admin ONLY) + //---- + // Edit URI should also allow user to DELETE the uploaded content + // Since we submitted to a collection WITHOUT a workflow, this item is in archive. That means DELETE + // must be done via a user with Admin privileges on the Item. + authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(admin.getEmail(), password); + request = RequestEntity.delete(editLink) + .headers(authHeaders) + .build(); + response = responseAsString(request); + + // Expect a 204 No Content response + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + + // Verify that Edit URI now returns a 404 (using eperson login info) + authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + request = RequestEntity.get(editLink) + .accept(MediaType.valueOf("application/atom+xml")) + .headers(authHeaders) + .build(); + response = responseAsString(request); + // Expect a 404 response as content was deleted + assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); } @Test - @Ignore - public void containerTest() throws Exception { - // TODO: Actually test this endpoint via SWORDv2. - // Currently, we are just ensuring the /container endpoint exists (see above) and isn't throwing a 404 + public void editUnauthorizedTest() throws Exception { + // Attempt to POST to /edit endpoint without sending authentication information + ResponseEntity response = postResponseAsString(EDIT_PATH, null, null, null); + // Expect a 401 response code + assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); } @Test @@ -136,14 +335,64 @@ public void statementUnauthorizedTest() throws Exception { // Attempt to GET /statement endpoint without sending authentication information ResponseEntity response = getResponseAsString(STATEMENT_PATH); // Expect a 401 response code - assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); } + /** + * Statements exist for Items in DSpace (/statements/[item-uuid]) + * https://swordapp.github.io/SWORDv2-Profile/SWORDProfile.html#statement + */ @Test - @Ignore public void statementTest() throws Exception { - // TODO: Actually test this endpoint via SWORDv2. - // Currently, we are just ensuring the /statement endpoint exists (see above) and isn't throwing a 404 + context.turnOffAuthorisationSystem(); + // Create all content as the SAME EPERSON we will use to authenticate on this endpoint. + // THIS IS REQUIRED as the /statements endpoint will only show YOUR ITEM SUBMISSIONS. + context.setCurrentUser(eperson); + // Create a top level community and one Collection + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Test SWORDv2 Collection") + .build(); + + // Add one Item into that Collection. + String itemTitle = "Test SWORDv2 Item"; + String itemAuthor = "Smith, Samantha"; + Item item = ItemBuilder.createItem(context, collection) + .withTitle(itemTitle) + .withAuthor(itemAuthor) + .build(); + + // Above changes MUST be committed to the database for SWORDv2 to see them. + context.commit(); + context.restoreAuthSystemState(); + + HttpHeaders authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + // GET call to /statement MUST include an "Accept" header that matches one of the formats + // supported by 'SwordStatementDisseminator' (configured in swordv2-server.cfg) + RequestEntity request = RequestEntity.get(getURL(STATEMENT_PATH + "/" + item.getID().toString())) + .accept(MediaType.valueOf("application/atom+xml")) + .headers(authHeaders) + .build(); + ResponseEntity response = responseAsString(request); + + // Expect a 200 response with ATOM feed content returned + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(ATOM_FEED_CONTENT_TYPE, response.getHeaders().getContentType().toString()); + + + // Body should include the statement path of the Item, as well as the title & author information + assertThat(response.getBody(), + containsString(STATEMENT_PATH + "/" + item.getID().toString())); + assertThat(response.getBody(), + containsString("" + itemTitle + "")); + assertThat(response.getBody(), + containsString("" + itemAuthor + "")); + // Also verify Item is in "archived" state + assertThat(response.getBody(), + containsString("f%iAVQZtR0tNJk@EuW{=)X|)00nvm zegvk2 z{Ku}UO~ugt;_)@Zdw74v3aAkdOp~#sFLtiKQ0E;XCZ>u%In^^VJLcyrfs3O=XEr+3 zBke`FjmIWp!FJs|%}bj~x!yGY92X9bU$yffL!&Df?mZcoyWO&mHuXIt(I$fFuYJCVL{n4TSLqiaNPvO{x z&fB${ti9}8c_R4y^u+4WtgShVAh|-FYIRq+i<1ln%6KQ zu@D%!6d83f;5GVvznbNB8y_b%m#eN)xKi;i$7SQr`vy40{dmffSm4A9I2eA#2tE^>-Vtx1o1g@ z5EbXD(2wU2Z|6k}q1{!#PYsJrJHQj&rymC1)i|tH7HEqrJkZI*CYadVsB+LqYQ;Ro zvdF_`5{u=~jJa#uM^Gb&a{tV%@gNautLFHpM5i{bnj)~h`=wfVl+Kr1r>}#@OARr| zOnnUwJ<(+i>)eA1PhDnO1Zkzz`>S&@rW23O02NmiGSP-p8JPx)#gx6h_{O-K5-P(X z+C|~HI&giYQ~Tjrnikp3!O_mzq+?yiz!V5R4TPq#Gx=gicradIBGw@EyweQA$p&b? zCxe;|?h0M_g#}sB43kNMsklUu^Kavl&-i{Ra*k($P@;~O<=_=*63Y^5q?nsh7MOA< z=P|Z`wV0s!4C7T0ToBQac@Cij8SZ_plSUM}WCRJQxkgw`00D0#e?E223-=tWOept& zGMpaaiD{e-e*@Za3?VT|LN0k&U^2}6lGxGQdJ0SgJnJ^TPFyZ6IDAauJ3Tm^UZG6{g|@awcTfW^*+E z280@I2Gt(e1uT4CM$n;Jg_fr>z%$xFUL*t2kH`y5TiDkrrYy1pB38qO)xBhf=xk4J z_u*j-T;*-Ww%Qc(h4azrZEKD5Na0>!jg)&^0}i2h3I_mr%p_eu^G*S=COEv>EuaSQ)C zjsJrV?rb_@3kM6YxXu4vTgzeAEP;@HK=5Dxk1A~g)bIe?Odgw2w&CB{OuwJ0koDTG zzjBFKcE|)M{GAAd$&I<&{z*JdO|+u3uI6|&-e7;r04nRTYc~BIppKvW39EKoL%G<` zJk_f%!TR+cv$$YpUl~)X0vGaoI5$Ki3}8EFMXL2VIlSJ4nor5|TSUA3hHH90a(#g; z-Rcf-jbLbED0MC%1fcb!8fy5buLsuT3Ef`Re4T5PL@&)PI+fqhmP6DM_{ZVth@60q z2Wix@PcY%JB}i&saM9gMg^uvp36J78AHxErg85x=Z8bX}EEWA>6Y37VHLZugZc=^0 zrNLBBk&#T&>TE%|b&@0!pDcB+$!*>`3{x-LTh3IzeJc0E>GUl1_I2d*5L0-XX)NVW%o)gc{ zbLdlgT!h-s*FiBaVg}FspqkH&O&c`C)xJ1Q8-^y&>LP0VF|@uQKe`b%hafw9!u&*K z@dTk_+=knkt>1rvA^oB`LKkp!+_Y!)Hb_Hmv&D7A`dXkjzF+oVjH}3ONfF9^n|coK zQtGt&j)E{I+nJ(ch1%YII0<3Q1A@#`SNpX*uaBpG->izt!QK6J4>U;H!CmNomIZ^`x(t&!w>j@-bG`0-^IF@_ZmO=X%iSO9 ziPO-~|5%tANfO;pT-aS#T*^oSfe8az^RSRHFckhSOsx%q4m<@-{0Wt%!-c&L7((xY z4+{$WSOE{?<&}7WcMI!Elc1+M`p%Ka7r=C|)nhIsB4MplA@FM4Pzc6gVWvP>D{g|ZMM zIar;UO|Td>ff|?a%r3t(^C2eq#;(nE&3HsjU74lz_YE!K}U5lL~6wC4Ui~Qt{LLHola1X*18@#36`1lEdCGptEbfEPu|#j&G9$ zDxpbFatCN&w=^hB4+=_3Y9|HgO%0%49G9qi=50ul(WBX}2l?rz zM^b(@t144+2XE5QDft8n23 z>)z|%CI#FLyHakRx`jI9hnKz=D}?d~-rUt|71SF0xKFSSjY&oB3%Nk%-yQioZCU6d zZdCR@@B%M?vJO&SgF3hexJqIhq;NCJKT!;gb2?CDH`W{K+LV7!d@1#{?C}*jB^phL z$=TEkvFjw1T(k2T#Q_aA)u-}o5!=>h$Z@KGMeD>=S72Lgc?^3h#9ima>7?^}&X^Yc zxBGdNa?hyw1{{+;*Udb`O~Z7f=f8UzQZ~L3NEMOQb+hghvBXVL+7d+-z`x6<;{)aG z&Oa|V{7i8@yOzN4&Ou5OV)H?`2N??E-Q(46HO)sV327gGLY)Ts-6B4uf;?860E(6G z7^cFEosY1sLX;EGE~>Rd;E#vMQ=+&!@88QJ$M18wFZgp0TU7YUDEJ)k7%v_WDo9D~ zf((fL%st5jb7Qze-j@-lNJC3M2=O}h0@%stxAxCjak+d%K@INM%Dl*O_9i zcKJX?zMMAxmPehZ2VLXZmvl}HFR6f28H;C+;FUrgZ-mRh!_Xm|k!;{s zNwO)-?}%~z>CAIYzRhGsrE}fJL5M1*LEQ{JHgnntD5qPSJ28y^O*@x- z9@Bn|qzS4a?oHeQZS=Wvvukmy>v69hk);Dza+v5KJ-?>to8=;j;=0M9fW6mNhD2!+ zmpdy+<8j<&6Y^L8q3t50MyNc{by#M30!qou6n?lkk$i#nd&% zPr@I{24`Wq?%bjtwpg{e;54cRR3q?gAm;4Vdv$EB^cy{ox=HWhdi2+|Mmj@VzCS#( zKkwfMKD&L2y_caeiKd+#TC;9TAsQso9@nn$(8=UcsX}~!_mS0;eew*6-;s|kq#<`$ETCv7(DW!Aaim2(<@P6JQO?h59ttqb&ny>JVd;Ok-i;pe@D*5s% zM1kI)P8vPw!b?mk0Lv(azf)SE)^BbvV|m@-n?))iUeUII-~RZzZf(^4D$2j`N)XJj z$u?JFvP3-e!Y&=5p5iT9#p;xG@!PfFXBk_+G*7r7^i*S$oI0&+y|)fDb*#<5%oH>) zl6am$`L4`PP|ozdUarsRtFk_F7NUR1*Jiv8-w+tGmBzMjt7-_R3}7t(I>W|eV?~W8Q)9q{Hu-l`-xk-p*sFgBMx_~-av`31@+SkmhQ9_ zeFK&u+f&?MV9J1n->EPXG*wM!by3xB_DgCL=Y^Vzj4(F?g)apmVp7yeWVt@k#;7`f zhYo)e0|}Mx$f!~tvQYsYX3ij}-=JahPgk2*3(00ZIV_q<9!FDK+5OKm21avP!1UlC z2-!p%sh0q-3@%?BN9z1S(mPQ%)wYS)p~61e!?BRPq$k}$w+sz^a?Mvf-NAO($K9Uv zv%JS%GLzMkjqgd(`srDSsPyShR^PZZ(|RjvTeKi=YErysb!`Z$bJSZF$Xy-(15ubw zZrLH4uv?uvs|>r5QAFSfqc5tiVG-V#yz~e39F#hhIn?LfIRUiP+lUfusK8ky@nY1{ z3_l|VWmAo?!zrPr-~r=}?l%fk#$3{5W@)n}&waG{vb23m9P_sGiH&-jh&cj0lB&{eZpg?sP%+0k@zSbJ+RdJD zn^7xewlP`utK+kdk?>0>TFHY>+|j6Yx^bO!fA7&6W=qOa*mw?-2n)Deq3zz%OI1n5 z?LA@?b5rSqa%N6Y zkbbZ-E@=gM;!=gBD|c1lxI8(S4QlsLogCaG$!iApQCO(97% zrUtYYOKVa8^diV@c7yL7iK`RGTI%i}P$d<`+)jh*KY=Z`DD4tO>Ss@1FJC3)Qs`(c zzTj5N(7N?xTr7)R#c5`EQGB~w>&LB?7x?~dmTqgz4FwG&GP(ZwITf8U+3$hwM;0bY zCFRC|?SUV9n!fLw)-~s#N`j$cRSI9BlRGCO=?Dk(7j`B!~?g_I~h<3X79w^m36R5%~l^~OwNj~9@b5bOxe*$tXvg(f5Z3?TrW2PVa~ zGxpZ?+MV9)$8Fw@15&q$Rrq9nWN%ZeS zaA=5!9d$}-$;4TMn$GRbWnG__v%Sz!{k0FecV>A!s=Y{qeF~{tT-#O#3+uQ54eSnT z#3^D2zTPe;{ny3~c>Rja-y&`HGdqOHfBj=i*u0E4`WRHAp0^&vKm4vVB{DR44cVo; zqVS@SpM6|n6mbQ@Z za>SXo7E;3F0Z7)AsEE3)73eQ%hGGZo0v7J+rW>VjIND$6KQ%1?1Af4A_e90tziM7R zz`wNlN}uDdrS4S7EW=Wy)zkMbAC8MR;0P!uO=PamJxS31|I~kkL&b4a9_^J+F@>q?;vBbP!8 zPwy!LXWUNI(~w=g)~6R4S@8Xidchs{?5pmrxlA(j|1=an^_wS;eJhUCQEC#OXS7rF z3$V+Oe{;QESAq)N9BCI&|HHc2KD=J)CjE;)$w57L2j(5={^{*yRjjp0CC2syi@it{ z8wvj2<*5IBLU!E%NB8f6fsSj`1zju&L}&+0hDrTF^WS6hUHIN)*c5{OyPk#5SHYL) zNi1{x=a|pIqy@sI^Vj%dcy4fJOcK^t?1^iykaTbDNd4Hfp0*<$HVV-yMHSZ-5^pPY z%o|TCz6apjny3s-x9a3&!=AFcOVq;d2EhwK9HXVZ)mlq3n=zk7-i1%8rQMta(rXAC z4~Jn}aeFufj2Hb_+@*w6nG&SL7}J|1_VaVP?L`_=RAdBiZCk+yFRHq$2u~b8upGZa^?0vqPs{u};avfEf z1RQv_%q}2oEYPy;yEyS8x)^d7nYauqPgJ8S4UW#kIvYmMYWL^63zZkvc1v7fH`ZcE zn(0{dltgt~H(<*{G>hLY0gNeG`#P_*k}k={`nf*P8Un7TT)WoY%xAr~g(R-(o$rcX zX=Q#7oPpgCUOlmyuUxw0{n}-K+Bw6Tb8lNA&CYsNn35fKZTLC$zBcOH1rG8FBS9Y$!j7yPH3jc*GXLLLNuV z{&g{KaeyX0bhM{UI42c}?00Yu>X7_5Y;d+M`QEwAP}yqsM%8Hql!8Y@F!{;b+@d`S z*VS%0)^A9c8Y|6=Qqjki7@$*7SY!q0jw;rLRC0 z>D|_oy{BjykD!&P?I2gSMJJc$+hDifK(an?30xw^u}+_kiubd*cZO+4G`xvVUcMdS zyZTo0;cw5A%w%U`=}01PGIhm?z2^&iG952#(V`-W*PhG%E!A`EMIrZ9a-cd=SJ z(1SZ(Ka@2GuLKrg0zQZl^T*m{?xoGBymBY77Ho%2^`vG4|`Y z%5d1vTuoCZ0l_cnmll1zFnhanBBE@rtjPbfoosk#-W*7%XR!K}X;)sLbw! zmTg+T+eqw0dIFsQb}Rbd#Nex|$8F3KDsqcQnxjyLqOPN&d3KQd(^4%YBp%bT@Q{00@eZ7+h^Y5BOgrMc2x-m%0}u1 zu~)$eU5(wy&?rVqb{iL`6=1C=3(wO3&k{1bUQUva;)eRV7eOd1$O>N}SCTVsLnWJP zsS^p&Hf(1cGb9%5N8rW*Sq^-n;Gy7DC!(y_SyoiY1C8;ALq#)1SQ< z++kw`dU^pKnTvHWQsAj1t~X_cpTV7$ASRY2;H|^rx?Q}Bij0oerUg@OW;r4$Jp3<$ zkuuGp2sMo!FK)vNZ^P12ID2_H+h6h$oC|)`9A*}R;*knwjFLv5kc4kZ&7I>%6xxly~Dtrh9BaUPlLc0VkF-_kT*Cw{XGcTyMka- zRhPfbrc+;hESUy?K5aV(IAbAY(J>Jl$%wi8k>DIqG1Zz^!$$prBzR@NB_p=Xz=wkRgUoNbY)PGvO=r z{`J_&nNZ@y}@kq9Z> zRWy?ArZJh!!phU{I{UAr;-po5w_pN}+ENHE&+lav-T!N#^Vdbb(*E8T?!$qTPC|K? zMtw8V%eL*4CqH3~eNZ(Zwqg`(OL&@Ms5x7pa79xTe1h=)nn^%W&0dx>S5;|5-5&U< zx1*vXqprC^aQI-T7Kd%NTvyGF=?{AyoyYYVY-rYe8EpE9ep#1W=P5q0P}4mk7JTAMX(CiSodpT;!7}*$NM4;sH{HAwR0mdq0c0 zIN1!hsqk`TcW*E&wOyM0t7akQkEpU}6LAB@Yg!Y*ezv`|gir&bKUx%1Ni{Qvg z(;rp+EJ2}%_VUlq5-er0EEwlMq4c#CX%y>Y%;5@g zQV^whT-7^ZCwG?G{|gx(Ki&>oh=N%=B0A_o3TMK95L+DQtecSWxB&$?l%Vz8A#75h zVvRMFi@^6??_bl161B{~hi^akj-=YsuAx0$%-)?3d}_Y$zKs~?gRCX0++-vfgYaF% zhYVrh;^DLqe%+Y>0!cU7LEkmoaN!$5>+qg=JyF^XgntHwpxhi>%X0?cE^F?NePGqTG&N&`9*_Q6+B#C-tjZof#{S(;-1a#p5iF}>+JmC zyE&9pUhuvq_FD`wz)pJy3GX+n!PbKi6{(G+kbVc`^4@N38AB#Rf2flr8jXT~cz)12 zFj`>G;C#0i3&DiEFB#FvAmnbyLq0elog+<8U802LZptJ*@&qqVx zO@u;+^#u*h*MyhpgX4XI6h&D=1_N^X)1>1cMFR1%yHaX?w-}IERVsJ$-Y`%)1IndIN<7?x;JkEWpTB#`NMxhzcKc&JV{vL?MAID@V3^u zTOmQKO#W?KK(XhyGfD%`%j@vD@=qtJ6JbCsr1`5e1Y_C#5}HilMWr9<9T~ehiWro?ha) z{sluv4Nc)Nlgl&NW}tiv717)izaRwHNEEXbOqMiUsy%lqk=_Zd^<>lc#`p3>muiY$3EVV+3Quj z+AXT=ThF!#ckcPS+mvw6a>XkgmChrIcQ#Vr2^Ns0qan}KS$rw;va+~y9JD&LcwmEM zcPo0}?qMIqX|8e-wOi2GB1hTjW&E+(E7Tp9?**Rai<&x0SwywZ?(( z@DkSey8;xtRhzQTa|+VUZ@EaiFuA!ZjE6vBnD|kZf9Z&FR3o>p-jHz1%x2Jswf(g{+Wc&^#BPmO{3eb?nt=rilrBwGDA zjVlwftNrnGFXTl$$g@Y$!Fjs8AH3%yjDnLmJ)EmyB2y+ko>P)N z46oTV<0eU%s!$$%?7G;#jE=lUkt~QtXzPf6sApXbh6F=si!PtnV@!F#T~0H|K*FMGL?MbRazRg?QBt*@Rl9B&>4b6Y-+ppWq!M*GM@j7(Cj;XA=r#;a6d zrV{=W*}V4y{8V-ZCT13!KC&Bjb!PH4iD6dM1!CuVeTW{SCmBG0Ju~iKnNsVxDe2&1 zAz{r8M=x?-eeeI-8Cq3c>p<5g9}eAl-nN$ro?=q%wz@`uN+}kZ<*d$;7Ao_jJt~eX z7Bke<1xwGTp&fnmHX-il=c-}~UD4T?bXZ#_?l}yF3MU>j(v?KjAZ)OzoI$8UPPCh_ zNP9m}d@*C`Sf0>HXfhf2C8l?V6GwQ^jIyhWMH*CX#neignLjv*d z79=YGaI%xT*5!$K`qgDL(@7DI_+Mko#b_ynngr*t(1{Ut;QvCXv>D;}mQBKQ%f64< zu4)r7llT72+YV+wa2ZWjI31+j!qS+5=#MW|2=eOIEKx%v&;vs8E|Q(JefD;npcF}a z0>t2qh@t$S0MkEi;fU)D?$KH}AFS9Vs+3CrLB@Gdxq)o`BG^bSquPhC^la_5v3aU@ z@(x_AZnPS^Fj-4Z>Adpu0`z>5bpRjJY_GLAON~OI0a|NgYFaG*m=;{lW`CBw+y(H1 zW=Rj*ywhpk!$;5M$bCekN{$yRo$vLEdvv41)w(20Bk#QJMg0UFo3;z(xPVMc-sHw- zagy120UKzY`j*f18UXiQxjxCB#gtW5QbK55!%$Q{lu>-3L&NVW?)6v$Kcn4|coGmw zBTc=SCMy9qS2=%>;`s!%QjZt>W4`|BtJ#*(0F)pJH3(uk8Oi~UBkAGeU~22TK#~?b z#n()7%1CAiFr1=1T-*X|R!u9AJ0*0(ZI#ddW?pVb>g&Q^H2KU084 zH+O)+=N+Df^U(iE$0wNheR>O6%lL(B`YE42Ev}9wQdrxV5?ol&+nrk)8{D{Qr>wQM zggiR^d|vQlZDnmqXLm_!Z(C|jQcd`Xc&bL4Si>KPdD2eL-`x<+%|ikKUI@n01d1U< zqzTAHs)0gvUT9@pK5b@hV+0LI2=ICN2vdUxVs{fG-K)R$gJM8OBrOQ2i>)ZEY>XUc z;2|vt3N9=~4uE?q_cm095oX*|H&5b4nD3t-c!`%IV`Q2BE$^0MY1*zq2|@O_3VkY6 zEZ_|bVkxiR0gFc&S_WEMd~@BV4L^jnpPKp#K9+pF2Kl#dpcXe@bqn_xjqystiZj zEPg1~j6uhHt9J!Y3$D;#YYPR5N`51LJ-wqvuiA;vSL~`0$QQXi7d2t~Oi(VIS|+JV zz=kJBIKi%iZ?$4`2A}f807DQMpPW~LWb&aexbdo%*?OmGWK?Tw$}4YgGR0UkLi?UkOkcRGi;WzgwJJyyKXvx3+)tKK>O1 zQReZ607lX6)*nq>`d-ZegQ~Ex+A}b!pPQP3HZTkX(iq&^CCLB-H2@9-%98Lm#@)jp zI!+8As70%l@kfIjc)@v-?!*%Ojr$nQLK^r%02}+oy-ar>u#d(lZ*p7tfDVJd5YQAf z+!GhZfSB#q`liEZ>Kf|@xb;^|esw>}?kwzVEXwUJ;NN*ecow7-23FoMjQu{$56yuX z82c4=MdY>?&qiZ}ro&!nt#5ug72ZOlDtH)nC0F(p_CWG0!0z28>Eh!T3`qMh@T~nA z@F!t=^oJV9KPO-!{HA~$&@XyR)qqm|>JOcWIVs7Mf|LN_mY)vzmo}Vq1@aJoq z4krT-*2oA<*g`NSg%FYKSzpM#k%d(V1Q;_jQQ+4P2oW8f96bPOPd)}|1k$tc?=2e5 zK>su5ZzNMw;BOdHpUAWOmHJYQ|M*&_hT!kW+Hd9f(AWn;%s0W0-p%SSGR)!h?5BH7 z=6!zK46Q#`c5v>^^s&`zbsKbxQPM zeElo)-?eA&XIs-q`T+iAh0{`Ot$hZJF$&trRI%}Ohl$jTWHG9DRe@rY-tXTGJkreXko1MDrs~Hg`D0sS`VtVwbEjewA(+p;RYprpJ&n}s=gE?NZ={3i zWK@+N)pKysIJLK;1s{FE+?A%V5K-HLv_)b{edI(8p=-EL^?dx<4{N+82 zzJ-vlM;rYHJWhOphBqrw69kbZ6%IiCV-7po8;l!8Egil7&z=4UNcr<7QV)}S>4eQ~ z#rhV_0q=fT_+-hzD;p?Tqc%srl3<+*lK9LqS=DrgX zE`N&i#jh{+@#Kkr^gtbNRYR#`F9Ntx+ce`U9dpXz-=YxLmgTA!LnJQc-B-efoWp;) zi_M!f%=W{F+UJWNOTMX!xLMms9p-r`F1Go z6h5)7Wwqb;G#G33H@pGoYoTiZX&lLw1$A1(3+aw(+fKJ1{usjXU;Oiv>>*nJ&MXO9|I%>**5YP*yFtqM zL1CL{I2^Pp_;{wdI^2`=23!$`2Z<#}Ed}5-ot(s0%3Rn$@72&S@i4SDgzhhiNCJ3u z3AE71dLV1;T{YGZlTa3-b;76a-n@Q7ssbz0B4;NZE_pU~{nXyYa+b?*1y*(0h6Y6Z zPfq(h@x7J+5y5YE;?S{&19gw@n+uOzw!P}(xLb3De``^Xp`-d+|nx4+qhgi9zRR^ z$Tg~O1uyB2eRBrD08_FY1Hh*5;CYyhS?Jta^V{1ylhUJiYE|&p#s67yIg#W;x~;^X zcy&=b-lt)1yMJnhyDJ{Lb)RhOR?pJx(@5Pe;{dNR8eGYA|l`TSBk(o(s}OOd)8{w zaS?x`EN^aGs@sES{*h|{nX1v5O9x7pSilu?9!0(R-%Z4EVDL736sNNrC>UX*(7tnW zYD_glQW^_9$AIJ(P3sneg<*nAAO*l0$N^Rv*<25%t7mrF2*_=w9d%ap1J9p!-Y|)R z4g0pe&Lky5wQ>cPptZuqB79UWxl>!kLor>!ydUCSRmaB<-DMTX0C2UI2sVU6T=RoM z!o;p^(}i4qy;OoxGDA{ez%c!xvP}Bz9CDAE=a_J9EPvv)op+xIU1p!uIOwwD8iEk_ z@;67sT#K$X=ambmtV>Lbeg)3uSvJlYj@5Z4JcW~1tU8O+V>6`V9rN4I%*VqL2$nQN z5sE5Rc8hP$Tmk!_rZe)-&FrcIn-+<>ZJVzs{#KtcD+9RK7WQ0S!-AQO>F~n!sc^f7 z0JT6Km?Lgw%R)_&QF^M+k!vTfpr603<6&}|%{!hExb@$%CpUZM&(r1?zKWB%UD-p4 z^Q_riXM;33&F6fk&(zHBH?$%@9T`NQ2o+y=k#|arp1eVcGU{F!;OOMxTjl0TTb^1C*4Gn8h{a7$pr%BBtsS_WGy;S zFHIRO|Mti8rYWi2?OY=0;SEEc*)l#U+K_F(K*wc|MC(aNg2>~EDk6mf)SCm13{+pE z8RF(F7PkA^>DKj=VLi++KC*i187)dJE!DrZ(A7+Bvx z)7pXw+)?zpd1Q=gSswTjM{GRcP`@Qw2Mrpgv8{yWR5t`T)j^E4IMr!y{a9L!^-H~okD1 z#pah=Cp4HpZ4=|oA1gcQE&u&iYLSaiyqks}pzcFe`HFSnKs7LIp8Dz|ultjAQ5>7K zq<9nevSmCewDqY}9J&xw)e%>Et&K{p?o7=#(=Oa*wJJ)m8Np0X@v~d;5M%kK=iP@9 z*;@{n2X;F6j}K0KX;jr%6uN<`f}XTDrb7>e^N|*fF;G!14YCT=ECWz{$i(b0?oI8x zu?Qm%u_i6M+b?uZBf6rV5`edI=KC=#@_ZN|#+UZFU-B!}JfnF?QMjdnxLM}Do1Xq% zbgU-CONl794^1&e>av)ZwDl~jZ4r#}#3*EhKUO9SZ-B5oQco(xTADsUWV`D^8R|3f zf#F1{LKTsB3D6-yOoo4*@(CNM5Yq|KqKH4o$w|WLiBs>G?UIwe4gxPMbhcN+Tbi{)*6x`&doy$NQ24uX*x3zegsrG+ zPWhgGoFgUFqf3r~nGTbymSSSH0m-PgICAhWL0Ogu@>ilYFx=WU6p^1-QTQWHc5w`N zaDEkPA7m!p=pi2tyUQYGKK9F<4S3~TRh8qWG|AHqxR~<$7g6&ks#o*U$JJg}mOK25 zDaWc7EmM^F8rrke#K>%&-b$Ef)Ta`C?Y5h9c*5R$ z25JmU)=&4O4Cm7D>W*?-v@E8X1Zmsuvb;#@{GNT96s)CfJa;o^x>XYPmfw^m2UqqV zV%i(Z${N6vl(aIRoz8TlBrm#AIWc%HA+3QQO?&YZ(bTCPSxt#L`Ho`6ZKDpe&yf@+ zrW@=&HSlIY%T!<5<|qmek_shz_fp$cAX(8F# zycQWF_SRd3hO*<5lkwaPm1%*DMV?v%jXxRI%)|!Oor_gwyV8y>WAjN*+r49N^&#vP zaEtL;uI|cY73rEZ+*zra&abE~!t$(9Ij=w=VwzIIdV8~fpDG;#--;psNupP5XeqSN z!dYTspkO%v7|}5)!5Yz^Od9=JKi5g@?DwkSrX=bWMteu{&*n01wN_hu>@tc^`HFmSBj6Mu(?ZC3jL|C`ZUt4Ihr* za)LW_Qv~we?KuYRRujly9sV7s3+{g4E(NDjbIDriizk5XW;~aU{l_1~N=`Ri<>C4I zq}AE22TI$2>V+?Q9VNl($g(Ix}z21 zPVUAgdTD5AxKgb35lFWO$U|xJH+J#$MnP)Xt}vvg=ep}6#OzF6wnw}qR3BaGFN9X$ z7|TRq^=6f|5ITn>2Ogg#b*)SYzI!Q;*#b zq30%7H%3YuBe~v5yS?GKrE`NylVq8jJ!@ys!FL^fH8T(VWx@1De-zLqT!ZXjV0n`1 z5I!Ahmtke=^jvik2lr#Dd{HjB8g#7JxNXc+!vn(aD1p^Bb_tE{+YB5mTIrqYOQM^f zp3kWB{giu~1S5e-EcN`!hno|jEkg6@O*N)ojj9;2j+TO2v1hjhlU%+UHJTVsmLeR+*2NMz7x%Ioiojg?%7= zwm0aFj@EKJJ2dycXF$VEv3>u|ZDL~Cu6%84@#sWVNP5|w;6W1Va$M9$5tP+02Y7|= z#jVrf!KGEKkBR-N=k;Sb9=B&*s>YOqC%IKnGryt~A0}Oq{rWO$QvB)5>ak$&^h?vO zy_r{apIO{Y-;UHCQoKqp88{{_0KR4_>8;Y1XVeYy#E8jd=gcJW(+&d1$VV5K6LYRh z6HT`luTv3COQM`VB8ml}1g z)_QuiKRibcAc?*|Pn^i<5dM-^U0D7KnxSrn!$oF(!#&Egmy543`4#f&oz z*!S)9TYwoS9g$+7%pU5Kyqd^0>R`InP?DKMx-VTl8+VEd8&#=c<(Sq@Ptvt*7q|MR=fg5gq) z>7mlC=gOaYFW=@}DO-VU2}wq9KwsUzk#6kxJF4Q#7D9yU>_T6voN}9ItOjZorM#2G zzs%X)UO;VF_9|I;dEjTIJ3wc&DN`igbCs!3xY9vbDhLCln-RRFgDQ>%h3MUpC+5oS9)CEKV#Z2)&pl=l=~Y5gHSH6@;bz!-;aUhGw@SvQS56wo0m}c< zCX*p6Qz>CvdP4DzjEf{&p27aZPjN0Oi?~(nBB*%eD^aWBGz>PcL!PBmv(f(Rk>Lw+ zorPOZYS4hkA-#iwU1+zgT<(r#GUn>kXqHl{wI<7Cq%gNNYg0F0mY&0_ZFws@BP@Fw zOK*;JCZ4N0(x+DX&b-Y&)!a{u$d7>JBcAxfDl5vfTy zwWx6<+eE2VdiF&PBEi3#n@9w^_|oTN4^f6QXqV$Fl@+-TYf#eOKsr?>d>wV^?s$4NQHQ@dzMR4~`&SIGwjF5*^~hi@)EE>46-{FG}J zw=^!C4H($BtRE4wGb>A$y(;%0bGIn!GE1-{QpmQqicvpa$z4~lQLloJCjk8ikV|NV&sy?2LNqx`B;R$lHP{@TL2jqp2+%G{7^s-QxMh zP|4rVDy{cRF>@#y@hzKX?X<8Ep9RQCA1<a>2d`lE5o|Eq#_T}(_=?he)2R1+uH++ zxrOX>!vRs6yrfx?xdN}%3B9AC!Pm!CO$72cMV}27OhmPx6@kv*D3M3ZMVvbqCNZ|r ziwUQIerXL3i3xEp{_IsM3QE=(iH&GpT}>0QjSMdkNLmURUCQm-OLeMha@lS!JmW96 z&Ozoy8d+j>t6&{qzE@)9jlNc@q6SC!P^Lr_arYcuv^Dv{e>j1ZIW{YhztF#nu*46U zqkq5LU-a#lwHp|$4BmW`Dk{tEW{j3}H@rmDh5SmHhxhWm&=znKnkxq7c-t}Kb3m<8 zm6PSqRCHbBKLnc$5>iQW70^#d}wrjr@1%+ zzg(qC-MKNym`@pfXCQ(p>2cP@I<}dQrk1W1Zpw5Om1Z7jci3;r6s_}34%PT1C3bi$ z&s^u5J<|xM<_ft_aDiE|P8-rED>F#rZgZsJ?y{dWg`@Skch#oZ=7;4aZlR^sPV>!7 z1H%J~vmhrq`xDgbmRFQV7s1l4GcTAS{dAW!wC^>|SD7>Tm1N(T?*cy+mz0*Wb{7>X z*&lj!N2R}RS5sTu!fklO;HaB#-ADD5zfQJ0s)f$eBioyH@BO0+oSkPMh^HO_b3M%`(wj4tMW~?+p!GKB*I) z#~V8LwtWJTPIC-(eguKgdW;^e+b5ERtE)jN&snC1X7Tea+N}4(8WK2{Xb&s>o$PO8 z4D11Y+371N4buTVtVH}l>tI<|P;X{# zVTNTR)m-WW(qEf>E>?PKAh}8#{kYRt{Cos>^o@$}YEfl5#^3~}kxis1RNbU)7Z5Hf zYDr7#Cb-mY>OVWEN0^4fKWX-)P+dl?8fCP6kH{$eMEvE`_e{7S$+`~92dV1Ru!8zx zSiZUONS;I)6%g{ZmG}TU`^JF;RC#J`B-Er*jiEnwC4a1BT6aZBG!$y%AEEoiYio^% zjtWU|jnm+M+j&4_gFauxDGr__*Rduod)(et(7lF$YrOGWkSClf3&9OZutmW_bTq)kdX`y z2+ugV^bvX!`H{}^c}qL*9xl5vzLUk{!16Us;V&D`!9@6Mm3uh9NRtN%PrNrkurcr| zZlJK%bY;6*pNX!qsGy)eB!|5c+bG`$$hXc#0~lYfdqx8|3oO_kqj|(fKe)BtYY5#r z(@?ckgjBoN)>cCxF159YCkqB$uBB1K6cBI(jvWNTUxxTP1`p-$s+vv0AqC*^a6g~? z*fW;IjbEw6ju##|pY?EN`_et6rwygW1^R4~nncJWrO%v+hHddPyzA;BX)EJ(*un9sN+NG@ ze#wBuL#~?AztJwC!`XJIB@(4>$F*)j>Mu35C9(L;f7$G35Jt<;F*njKpat}7<6;*R zJl1Ltidq}*_<+etU65)HfsnJrm z);gqmbT^XGhKv*&p=r4`-#ChRKgg}~tX1#zUq}7lvHwQgv6z%_UYuFrCXn6ce)n^2 zCqI94ARRAspg4KLgO@Qwl7R7EBBflW?&0n{s?ZqawV4*A{KLok5QXJeYbb65>d!=d zhI7qM-3RDw(MSweov|se+s5@}wQmT0#GdS((hLt2&-2biM3fup-R2+qZfXcNjm8dUDR!~y1@%f`Y}DK>k9UPh^n zOKGScYL9(H2a2y#rggbwv@Y6 z+-ySeS+`NQ_mug9(2eP^=P~FbefztycbTB=z8jp+hrTELy%iAipB8fw(yyv~@S-EG zS;|kIqY|TcJT&)vsEB8N-gb0wsaJ4v@Wl7p%6;)3gQYE)0MedI49+U>56)Q zYYRz4!f*x*S|NaLG??bx7sL`FpYvhSMCpu}Fr>NV30>P%XJw`LZcpgogYM{LP^hj_p#jf?F^N%`M_LiMLc3LVw}{~&mFsZF@n>~ zoPM0L|DX_b7&~g$`tbk7NlIe-$>(^5h zdPb{y_K+q7aHmSy9q7Zr_*za&OCCNQQssYt^x-~ag@F2aRg@@ZgSp7E$4r_+R>7y`SI(0VJv9zbWp9st=YS19f$H}RjYr0 z*2k=mfDG4BZQS92DO?`$?UcU-kW%wz5kAd;-d( zZLTR-?-MIG)?Ul2EU(lj977sr7(+TKUGwxms@A?x=U})&^grr zSCGIheoLZ3bcuLrszJNK)~HbB%f>d+HR80;D_c}Pqu}k#?x}ur=H^MJi7=JOe)+hV zu6_x)@(zPxOy9KpT{bxXdV^T@gtAA)5`Vd;#z9}1zR+Q8x?WJj!Y*Z6nqNj|exCkU zv|R%;=A{q+8U3Qe9kNc?@KM8QPz&O-NGWvB;+nGiKM>RK~r~~!gJ{zJ3#8VVS(Om z%U>DVv%l^$tlSF~b7*Lcen(N4HcYV%t^Zi)O^m~tN;BT3LJ{uvl=CSL=Q^vTLGRd@ zGS{$j9C5^(6Kr^{+?MDlFb5?_N7V6kwV+La%_2dcb@fp_(^H%qak>QI3_bc7OBqf9 ze9{WTa6Whqy+YXgETw5Ze6tDt&OE$fWksE!G{^Ev-;$h^eaSvbm3MCfj5AlAyt*oG z5PplrcbJw)t=sxR`8#*%vM+l*6BKhIJRivBrdYz`K4lc&eaXuFJSre(Fh_M+zwQ`b zm&5#0!_C-yUOpdI2q#D#PBV&A32B5Yxb+RkE`ISn`Q~A<@TS=@W2yM%H9=PoTZK%+ zOna@O(&zE*0GBdIgD%C=Zsr>8Lb1b|?ZosrxG-dDDQbp&U;P;!_1Z`N-o<9YrLERj z)LwSy@A=4RtXI7{Z%Tz?Sxciy%f|{Qf+x@fgU03aW4HWS)bn}7Y6eoBQ-yO>$X-IF z^>HA5_Gf&8W{vV z-8CP7g-GY@D&Br@hxjj)McPp5xe?-8up3yft$(srcca2MP`X1S3PwnbbB#XDZFUJx zXf?wM}x`DzeyNzKokO;B%O5TcIf+V}}Toz>$4HoODSa6(k?B_WsEHsJ3_i?n7 zW>uzid-)mHaG_r52<420OOVr|NY_6f;+&R zRbcKK2nRDqHBDtL!0)XlYiC+Mz#mx&3516M7YG8O<>CQ>X+c0BKdk_W$B0|r#mpXV zA?|2x52FPFxW%0ptTaSL|D6N$A8S`Ue0=|(RWYNOcH1u6C&34zLB0EC<8|_?;;aV5$Sp_s zJUUQNK1infgXGs1!MWP8fFqpaJ6^HQktOF%d-JmKU1|cVQeJ%GRv8?ZSN(z-n6@P< z=Kz0^;^%s2XA7~WKNhzZ63Ra>8fYwTt@K}@P-8SoKN@ccqZS?U{d5Hm4gL~J@Jsi2-1vgrd zp5}+YcmZSD#7Rs-MH-Qa?qBQG$q*O7V^kknFXzW|ZD5OS7aCg(_5ai%tq-ih^&2Jg zVSVPaoO9-u@?R!G;J-AVThrCt)bcOvvCCr>*e>ne-8Gs|5T_kPHkiUDYWcIIn zFo0VZZs}sZ4j-%KLkMklh$wRw0|`2jjACL7Md^@18y}b8E!3@hl|nQwf>_PYG&5I zzmUHtlkd+Kp9ahs;fl0?In(~}puw#SvxJ-d9{At(!2)1fDBu00%OVl3PWM(c?<;8L z=tKl$!Y@NZi5PsJ@=Enxp!j_>}u7yZMBNdHAcApg4Vbs@Ze z@p$fe5Sf43yjQqCfV@0^;k=-GyMNrn5sp&#&o--+AkS~JP#ysuATK`{%mDZe_$XW7zFu; z91jrmpO^rcAN)^D;2*jI`~v^t~s zz14(!!R|}Nt${$?4-C&=Vr)P00T)X*G9GY5Jy#b1OW8`^#O%?by$?$ z*0+F!NQ!hz3pmWc07FWHbT=}-+N!z zJ^Nn2m3ytV_x!Wy6hy^Yfp0j_>Dsc}8rrJb($GOvY*f|;X6Sr;02!E-3H$>U`y-+R z5I41e!|VX!7Em}$6lQ2`1QQTIw};!opqA*)$#g$?(Y@GkkXtQ9G|*la2e| z_ps;oQAcOI@^EG|+2xRkNYYtwqmL{=0tE$;_NgdwD~(W;*E8zRi2-eWPogpUj3|VZ ztflhQ=w{ZmcCsR93n$gH9H=^@w!p&&`4=Potoyx%kBtJwb7j3K6(vM}b*gH)UZzL~Dq|Yjw1D_e^kFp7t zN1x0PqTKqnReNlvc_5^FzI=;Eb{dXp(U8T9@mVEw^#G$5rru+1C5I@<{wiW!BuImu z{cGF3*)AalW?+#^!i_A!dE?aJ>2>mPoS)8Gnj`;tbilg#?V^mEcFXwUnrW^bHx{!_vcQ#0Im* zgx53aH=ev}PeeV#)>&B&`gDlzG|I`d6D)^EZ(q@RXs|v}t3kpNMo6ZUUN+@^rrzp4 zgqC8%Ti~O7h(`N^=n5B&N{F5BiJAc-mKL?|hb1d#%%XrN4Vd3Dh-Q}6Y4NWryeLO9 zIIrJK?Aa)v5-D|v;JIOk;{m3htfLigybH!uUm)avMyx<~Cv~d2>;8O!9(hh**&oml=PPE8u(7@$(@a0ZEVAH<1ODt;Yv2#d91h}ip~iYG!+D$9L1gF$bf;m zK%>vm!(5ro{tU>7R%@qpHP7f$eWH_7tVhTYanYCUG*Cg|9te6gA>B#~xU8RwLKniO zZkG86I{Djn6tGAueyG*pH-*hOBQN-1OCoBDH;G}bp7C8}ZK%c+lDC#TH{8+w-gvW2 z%`F}qm7{|a=RMQo^@McL*=K+mRVnzx8kxE@T7+2}z5G9lt&1?=6hdw(^_d{J~ z(phy^^5&>Pv|bhwZo(N+NuBlOh5z7MhB#BKU*i9|L%L+v^qDNK1=y_)%MPPvT4%Ai zvi(4>LFe?vc5G#ILoK}KxV65-y9x>s=}~UQ=BVc|$*Rt8Yk-sqwLLTSByLe zJf~%<-vim)2rCaMX~|)X)U%SG8-k+_HYwJlooN6^y_e!mAqVT$E7qG2DG#|gI9SgG zCo4>i`k^U&?4T333jTNOm@4{clp}nnux0{LBprobseP1_DVb7 zIZWsI0sgMW*2cEYV>yrH#jr_)d*D47;i*uN+3O>%!s-0l_ct`UrB;<1?}#(K3d@s#2SsbWw4FzP|aPW@JJ#1HoPde2TH_XrzN zUy3v-+S34~3N0i}v6(|H>7rJ18oi`$;|8M<`G7+bhWejz-41K6cFb2K_4}=j^U@Tw z5zA-pc4WnIKS|fP)|}S(u~On!hm#6*aMcIKSLBjvRCQ3RDT;*#0^`!2+wcwxU)W33 z7|t=@zFO#sI|4QPHYYt$Ja9a`c;NEJd*^SLp|?eV;=kjk+$e+vf*Cj#?a^@P_ zh55ewezh>k_R0cXN2_4;fxSRe@Mu}Xb>?S!oo_CvUN^*Jwhy9mc7jXAtHmMr%wwil zpSd_tYc_>m%Grl3VTS%9t>v{Hk%wSc6T14D^-C-XH41*OMLBavcEZzaZKfsjs&)y! zVTVZXw-g-V+2ts-xTogR1p-%7X|8MncAp4dk#KjfuEiOVpt*Q8rxh%}7}mlacx!gJ zb@R-c9&mItBn_kW*CE+n8?Yn2VyGBA>P7p(a)h}1iZA!=Vz9fh{!^MI$09U)t>?zk zgi>@ytts&bi)k)C#uokgiH%z(iyP8Vew7x2eF=rY(j!hi{zKSzztt^YE+J$mLLJh1 zS)KTcNrU?}{X`32yC|<|5E6{E>*Q5Rx&E8EPx<%wClA=bo$6@8Rz_T4nVfLxTL~*% zEjIQu=>2?1-192^gCv`z^Y0sCTU5kPumZD|KlSba^7C~S%iS~`RM$s7*?rW^wUm;w zRm`Y-TNW>-?4f5R=cr~Ze!U`=%hb6>D`Ft*maO+}{PFrpuMjia!=v$c$IVdCYOD)A zrz6Ha<`aD{Dyp(0oES9K)!ptNgOyFj9Wj!jz+=o5tXL3uU8Ynj_JT&xG`8Ke>?)7K z&)PE9wWFIDr5JYTfkKMInPlrT6$Ke%5tmGxdSN;b;TRs74Be&2TS>~McXHEYlIdii ziuY2W6*-oV3S~w^stJv)lfpVhdHFhu6kq}hHlxf%-L{UdN#Vi+_np^{$LA!IW5{+AnD&7x1v;*kUbOh{h zN`M?2zd$C%HgaY8xdtfvml?D`{IB-pWab#fv2@4TJ;!8r7WCF|mkSEr@d|4WS--cQ zW4-(Oqvl%jc{PtZA6>>_?a5iat%CDajaU^IOQ;^ z4#LyrkAjSRra9~BuZ<3Y8r)4qvINFg+GH2NN8&TTJAjxpkzZh*AYAMc`4U0=XC?=K zeNhO`=7a|ZZM{^CqIh;u;iI;X&$g`NZFIR!$IZMV{L%T9t*kp-+_H9t7SxkE{ z_LDt8%2k_iXn{e6+A8W>p#%x?wM}FI#ViBzW?;x>?I*pT+9U zwd3S6w;6`di2D)>F#Xcsqm`i8Ol`kmBzH1E=V;})Sj*yT-(j?gc^j*j5Aj|lJIsE% z((QQc(p^C;SRkn0JaFl8H)DS`0+EntKtE zYHAA)BPPnBtA&Dp`_gQ_%qSd>XB0_CD=Djw`-5eAgTs6ZG9DU-TAhQ>^_X2NFE5a1bOK}4 z3*2E)`aLaf5DyAn&=ZnEs)3_z>H84x% zK_KH=??OMcKS57LTBPwv=AD`4RV;gMWo2$9XOg9<*l0XWbvi8#*Ql0`MwFt47`k2Q z>mDs7u>yz^{*=YjZHtfRZ?z}m+v2T(N!h(mrJJ0Im!N3v8rB8X-j>+YrO1v?C7)D% zX61}3LHp7~`T zq3)nfxcRcM@Rg_QuK!)}!_COs)v_}e5vQW2ru@9fA9iT`2mI9(twxUfn@$ zw(8N*;=;VW$<3>ZZ+?0l0p~JZo0ZDpgLG@OYwpvR;MHF7e!10w4la@dEx6N6Ib?97 z(P+%%YxbLg-c1M7wa(q7<648pi5Mi~kbxLOHfiDw7G+zdDDPh35HEr1CYmpA^MI-{ zg^~{0W=gZPQkmn)7)|e<0@A8-3Uwv zvIbd=Ls70--izy()wm_D@tPGBt=kIgxMe3d_d3pyId(QFe4)fj#zW ztaO^S%eCv}tL2L)JGxkx;T!Gkrb=6ETlR35ugMtYV&)s%pO}W%J^;~1`jwiPz74TV zzYAGC3-$?E4T|}|W)$PCg4WS#P~@EWaTv<_`t{lf`>9yfN?^L*TPd;NtoHY>VsYDDEhf5$go+KfnBS z*Y3Q5t!}Bg^Yj^1`Ftjs;*b{AUzW%(q^lLiVM+8vdZx{Om#O+>%BvrC8G6rg7wd(c%U-E~OqSH;jav?* z8Cgi43g+jT=_y8XeZf3vo!MI6y7ZY7bFxynN~r>0v^N8f2ldZ7sAXL;AJy3GCI z9jp4X^S+JQTYtQCPFCyl*_FHsD}2twq){uiW!e&xrr;#v7zZbe-il8ZP^YLd;c( zEMv@7A8D(4^sF$uG<9f2WRBz`E4KcTWfYvpHuHTA&3ARXDVCO<+j}1-h2@J!tQScg z`~!@^Inu~tYQV<7t{kV+vD6XT`E!Y*v#VWtQkgUd3UkT{cTEiy{x6CUmb=GELY_f2NdANRtRhVNaP$h=KW z)0$~)MHK<|TIFX+7bXvdZ(TFHHlMWzIlTOfZ#i#H)EkMPV&^H5s26xGkyNn=Iyq|xhYz$?_T@1U zdv+ehXmi`!(JPM#&9Iqvf5SGJ^Sz)frMrtgrdP3MZNB*d@oOp%ug;ldCD-e4>0T7d9gS@-*a84o5s;4n?w5M>X`QeZP1#~bPv*>g@G}Jk@xeN|S{y;?`_P!5 zzuFUzF@d3d&b37HBv2X|EHi47q!?q#oM#44PuaEi-bxPp#%&i-ew5pAvZ9|1n!)Nj z2~wo@C3I2NYhw`*eyz?hDuYvuKmc3eOX5i|UUPwnM6!Ox?J)C|kq0I1XzAZjX=@*` zL{4{gq_d4CCT*{ex@Sm^e-1pd83+mT5Wm~@$P{hyKTj%#ib>GqWz&>%CyKSQ>;#+9 z+qHpNeu>9dI)YLuz*zX?Ox%J=q@#H&V!WE?^AJ)zl}QALy_N$1s=@2ItD~H)UZ8B}>-`HmB%ZwRT#UKGVfWcno6c+6W zwiL#rUCpKbcj07)Q7+S=RI|D2XLZ!Z5}LYP=^MOt^;G3<&O)~erl##3M%fEgpkkF> zp^H7E+5uj3XmO&%O{sGN-0)X;8_VSDWbx^4oYjps>7NO5lkRcG)>5mv5s5jhL%sj0Z{LDlgpfrjHicj zbSZMoo39y9MlJh_932M&KR00=Q1&RIo|cst02gWY%qEyjPTRU0$#!shpQ^l>dETnl zsU6HiCx~J^D0#En_b`nwkw9kvv9-2^XYH*q1Qrl8&=3>Fg?pdYmIG{!`-t)=2qim7rWO6D| z?p)7fzewLBHtc6s`{-cjfg1R@P(~l^F?+x37|XGy#hbh)qTW^ClZl+#whoTMWSSoS@V<&vC%!3lR8eXi+zkhw(5R*o6Ks=!_cnB%i4{P7bS^w_;<{T z>*{xgZ<5}eX2{PDCwo?uHopH*JEi%3ZW?)WPaI;J+?PkQIZb7g+O)|%dUrL|m@LgN zz2zQw?DwJx6&V>Yy=uiz z{&lC_Jd*^7)aHLC;(XrDJ+%2vTp?BE6BPLdGwp?+`QcA}WCLa#WpBc}uSPT#`7!w1 zbuT6IRBKSusLiGd)=Mzb7(ZmpJ(QO3H+zCQJ9`F47j|8yz#C53-E!5J=~Lh}g2`)f zH)_#f*(R?=!p|ZUi$Pl#JbMP^WKj=TiVzsR)uBt4>rPA3|j4Q+y63CKWgr7p8>K9#+RH`0fvDlkNE8xrW zbuR`SjNr1xgIHB!CWz&BRZQ3_#pI>9PE8i>#fKrl&Ahjg?Gtq(@?-8mQF%$SFTR<* z1cCh=bex--6I+lANp z{_rk|3#R8mvijOaWtZi%G=aiTQ>G4Qs>lA6^_|6*sGll8LTA6_N{dn0n-8HnnmE&Q z*DWO-!T91ETIh=~s!?2YWVhuX)D?@9q3LP)K3N+&nRw&mjsc$;$+Fpb=MkED zU&baB!(G=SKcnvLDvpIxKCuv$`31BKrD5~q!HzH^GRBhl-f)qC$W(5#7dK}q zj1Vz@;e5}Ow z7rw7MJ{}%cyeY|(=W*RZVnI+7UU(ue4&OrS;e`XW>(z3zK+zEVL=9JaoL z{qsAtVgV8Qfu6LZ1%IAm!~0WjRwRl7tG!)Dl}M9N^-A_wS^3EjT80;@?o-XIcr$n> z{XH!a9(tCM8h&{+Zfr+N8CRduCo+sWkrR{IjxeG~A|}I9-KEqqnIJjF5TWMTZ6U&1 zo6T2dk=K`0NzC;+6eL|l_Xv*kF-mZ+?b!9G6Tf5E0RFsh>^vlKKR!oA=WYVCtzY87 zYZiB&VGTQcj?3JK!lhy;W!EY3@VQjM6*kmgBdWY>`-d6ZjR=i;^@q6Uy>T5-5mc?j z$;giVff`8rDHMDP-?4RS+}{Pp!VQ!2N+q|AFMWKl8?r2u*rLQ&X1O zZzm4IfvpZ}3gmQCH5s_rUsmwP!E^@wBls}RQ2}jCJ1yMhg%O1-1hXTC^i9ou41SskaRd>u9>QXL>((^nR1! z%5z;_AJR#=Nm+Mlus#y zKTC0af|q>^Q;2v<_qFgW`zv68vYI!Xt25XZ-!{BvfIBRLa`WP-AsDbpdWq%1T$~V| znmjVDIxIM=kyDsIlV-z69c2Sru6-&i`cdg7`Ml!1K#j(XxdO}bTb2CI)o(Z^Oql%E-|Z5Yn6#uKx*%Z#R@RT9Sf^7)RgU2$WtaER>PUz4~DCPCWFOB z;lMHI9^-zE`iIXX1(+R}7wGFswUrGuw|YNl6AHc>j5fA5fg=har5j@;&>fP+#3Qg9 zX5xN#OkrkJB>}T#gd7Z}K0(W+H^A>RJN@ZQh{alenVQ%fFV>C)Q^QSzV~z&nhRuLd ze79}L8^%n4Ip7+9Z;LoV?-06zT?RxSwzc}f9g*buA+IPe%NFwjXN1ph44b-&YzKuU zM$4N5dWkmijkrl9N3i`crpJ$tQ{Kxc^?v(lp{xc;iABdsSEje}Exj|+bGxn?zmAA? zTo%M;;$qob`h92v#R|oWGYUEuHK2@BI*E*iI8ej#*HO}vzCX&MI^E^vWLCqKrI+3Z^Fj4w4xWwUCHyM z$wT@BniDWRIZ5x0INf?Jrl6cUR$ou-fB~3u25JmLiE}@GF>C5>NwN{A0*N^jFu?R8 zS>9w+H9Q4I4g&f1A7mFka@0bIS11?`gxKv~DWB1OHO0~p$y7cIo9dGpFK*qKQ@KO1 zxVO){&;QEMy(kHy)_+AQhu;7*lc70?=JY;)D5&y$Wobh+TRw$l@R4#1kGbjrq}m)f zvgmu#9DaA;B__Y!jG1DwAT-i>xTv)0Zl6~{sead~vQ1QU?Z61jUx27y6Bsn}sJgOq zR?B{IEuH3q` z<9`L81TWpp4_Q)6&l>ucyH-y?N>wb;KCrlLfZI5|t9 zDfZCY3baDqG&dFKyfPh~wGZ80ajYo#=3JIv>lBN@l1%wCJ(V+N7fpkaSfd+Pyec3v zBS}juk%5)Kf6H`4Jb1`G)mYRQy%qkaQ=joZ6``*b$x)IkcUmS8@Q2X&$wa-U(`>@UI#fLI4F*ZvK&} zdj`S%FAq)8)Gnet|~hT9>#^N<+g>3P7X=%V-EAD(8F6fZ(VwWrCi{MW3) zYqE`Pl^peqrlbO4xh^k~S#|lNyjP@Nf4GIhVdqHVIBo-7tl0kdDC^MGP2hcMffXGoO1cnC5 zMXLE=g0%Vi%LRYvvx!P`TeR`K95AZEK`C?*`I!CX{=olQ(p|cJcyg}y{u8*sBhi(t z6YuQXFUb2l=ewqB-?NA@^VVfO(Qm0G$z?X$tOC6?u(b8`b=;6xES>q2_^kW%bwL(4 zqQ+pq!_kqx2@Jy!!3t7z)NNE7Zz=*9M0;vtZ1e*H!@}8%rBXdVu~sF27!m>IEui3i z`!Rj2pds!OPeJpibqW><#sI)-uNH{EAKsxyD$A4LwjTKj_J#Rt=@--($2Q{}OU-W; zXJKCwrsTjX9bELQnB3m08V@+VgQd4vy`BcchhN<23@Owas<_aENQI6Nc&W9JEvXG| z0ENVp#s6ifiSvJkn%F_$e}Y{98f#K)J76!YVra8TMr$e42M~& zQE{{VWnSFW0tTY`J&L6yAn?yUaQ|&I3&g?kzl@XVe(p7EXTuP?xJL(k3;8jSpO3?+ zj8eAc`}OWgmzt7@A!&!^+JQOqC_!BbMEK$zVX*YW6fbE9vn&7GwP*(v=ozWm5>4Mk zY35qzFX#NN$q;lI+Jll}+}H)#Cd&k8=|=F%fIN0*giTlbbCS0^#va!-7`YTxI8FKp zgtbPxU6?Ya1JUS%W(Yz>_SQCKye9JDshrNfB1lpblPKwrNoQC*#GhYphoog4?wVILdZ)_+kUl zLf=Ju6w0!Y1+E++$K?Og5s?2rM#^eg?h9JEf{XKDC<3%F7&yPH-?QnzcifYW{c@*|s_Uugojb<%tjgxOf|;4$iN~it?r5sN%v5ib_auSix4dQF z@$Z3O_~!?|(VsQ>v;6zTdg{O9Z7wMH2mg^blNXf}H!HgkZ(;r6;yd~8%dUkj>QA2? zIEDSoZ5?wCrljQOY(++!86|JrkeKmLwVTV}NE7dP{! z!VR|DF3I2P+ z{$s|}{l^dSvHjgL;y^6$fT-`^T)R@!R2jB7zk?%x{*3-;ggId$sB ztXKZ*f7D!7Zdv)`#sLLGzdSQNjuvMhjxz_pMkH}e7YLZqJ=fWTM?+7i;otslo3dx~ zqb0N0{|758NSm9hTglFyvB%=qf5rfBMkaA)5eCrdm@fUk<~GIhe>bu*FfdAhM0kPX zKsFFBX#}xyQ%j2VDspo|Ls%J@6@G%Q`(|K3HUjgWaEK8g%}W~J01Zam8V)o9bZa;^ yBT!H6L^fifKG+E88J>8IKwWo=Y=lxI*a+w Date: Thu, 27 Jul 2023 17:14:23 +0200 Subject: [PATCH 100/230] fix: add default HandleIdentifierProvider for disabled versioning Setting versioning.enabled = false in versioning.cfg is not enough to disable versioning. It is also required to replace the bean class VersionedHandleIdentifierProvider with a HandleIdentifierProvider in identifier-service.xml. I've added one that is commented out as by default versioning is enabled. (cherry picked from commit 92c38de99e0d8dfd0e863812eb307cadd351c1e3) --- dspace/config/spring/api/identifier-service.xml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dspace/config/spring/api/identifier-service.xml b/dspace/config/spring/api/identifier-service.xml index 0c58cc1de932..79e19e879e8e 100644 --- a/dspace/config/spring/api/identifier-service.xml +++ b/dspace/config/spring/api/identifier-service.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> - + + + 11 - 5.3.31 + 5.3.32 2.7.18 5.7.11 5.6.15.Final @@ -1200,6 +1200,12 @@ ${spring.version} + + org.springframework + spring-context-support + ${spring.version} + + spring-tx org.springframework From e28a083ef79998d88fd9fb2e2661a065c63d5bab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 22:00:25 +0000 Subject: [PATCH 105/230] Bump org.apache.james:apache-mime4j-core from 0.8.9 to 0.8.10 Bumps org.apache.james:apache-mime4j-core from 0.8.9 to 0.8.10. --- updated-dependencies: - dependency-name: org.apache.james:apache-mime4j-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] (cherry picked from commit 7f91661f8415a6ffb9c37646f2a2d5e6bb981312) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f940dfb97a37..01830987b388 100644 --- a/pom.xml +++ b/pom.xml @@ -1302,7 +1302,7 @@ org.apache.james apache-mime4j-core - 0.8.9 + 0.8.10 From ae2ee43df83abbd396ba912e2eb1bd69be8227a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 00:08:54 +0000 Subject: [PATCH 106/230] Bump org.postgresql:postgresql from 42.6.0 to 42.7.2 Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.6.0 to 42.7.2. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/commits) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] (cherry picked from commit 0b2b81682a29df9df0feb363e9c3812e9a034ee5) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 376557bcdc1a..32d4a5428e52 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 5.7.11 5.6.15.Final 6.2.5.Final - 42.6.0 + 42.7.2 8.11.2 3.10.8 From 678aa9bad5cd00ffad0c9456a26a9be571f8c602 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:14:49 +0000 Subject: [PATCH 107/230] Bump org.eclipse.jetty.http2:http2-common Bumps org.eclipse.jetty.http2:http2-common from 9.4.53.v20231009 to 9.4.54.v20240208. --- updated-dependencies: - dependency-name: org.eclipse.jetty.http2:http2-common dependency-type: direct:production ... Signed-off-by: dependabot[bot] (cherry picked from commit a6e3d7a55a849fdb443e5f9df991d4f00d9aea9e) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 22185bbc946c..c7a838bf01ac 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ 2.3.9 1.1.1 - 9.4.53.v20231009 + 9.4.54.v20240208 2.22.1 2.0.30 1.19.0 From b36613951b0274b39e71cede8a33b9c31762d1b8 Mon Sep 17 00:00:00 2001 From: Martin Walk Date: Thu, 29 Feb 2024 15:21:15 +0100 Subject: [PATCH 108/230] Fix #9383: Set email subject for request copy form --- dspace-api/src/main/java/org/dspace/core/Email.java | 2 +- .../dspace/app/rest/repository/RequestItemRepository.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/core/Email.java b/dspace-api/src/main/java/org/dspace/core/Email.java index f6df740a53ef..c157d16d4967 100644 --- a/dspace-api/src/main/java/org/dspace/core/Email.java +++ b/dspace-api/src/main/java/org/dspace/core/Email.java @@ -395,7 +395,7 @@ public void send() throws MessagingException, IOException { for (String headerName : templateHeaders) { String headerValue = (String) vctx.get(headerName); if ("subject".equalsIgnoreCase(headerName)) { - if (null != headerValue) { + if ((subject == null || subject.isEmpty()) && null != headerValue) { subject = headerValue; } } else if ("charset".equalsIgnoreCase(headerName)) { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java index 6eb631cfa56e..5945d516600a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java @@ -247,11 +247,15 @@ public RequestItemRest put(Context context, HttpServletRequest request, message = responseMessageNode.asText(); } + JsonNode responseSubjectNode = requestBody.findValue("subject"); + String subject = null; + if (responseSubjectNode != null && !responseSubjectNode.isNull()) { + subject = responseSubjectNode.asText(); + } ri.setDecision_date(new Date()); requestItemService.update(context, ri); // Send the response email - String subject = requestBody.findValue("subject").asText(); try { requestItemEmailNotifier.sendResponse(context, ri, subject, message); } catch (IOException ex) { From 78d8e86369f7495611f4b88c48d3df8ff41c5bec Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Tue, 19 Mar 2024 15:18:28 +0100 Subject: [PATCH 109/230] upgrade to Spring Framework v5.3.33 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 30ee3c3fd783..5bb7b3f3afca 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 11 - 5.3.32 + 5.3.33 2.7.18 5.7.11 5.6.15.Final From 3817f3ff9d3322e5aca572d49f6204444ed3ecd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 13:07:21 +0000 Subject: [PATCH 110/230] Bump org.apache.solr:solr-solrj from 8.11.2 to 8.11.3 Bumps org.apache.solr:solr-solrj from 8.11.2 to 8.11.3. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production ... Signed-off-by: dependabot[bot] (cherry picked from commit e93455796623461e4a5f1fb5023ac9fb0f78f0e0) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5bb7b3f3afca..da252ad102c3 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ 5.6.15.Final 6.2.5.Final 42.7.2 - 8.11.2 + 8.11.3 3.10.8 2.10.0 From 48079d70a95b820c087a39e1f26c821fe7423f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Gra=C3=A7a?= Date: Fri, 22 Mar 2024 12:19:43 +0000 Subject: [PATCH 111/230] adding Unicode filtering for sorts --- dspace/solr/search/conf/schema.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/dspace/solr/search/conf/schema.xml b/dspace/solr/search/conf/schema.xml index df21afbc6426..66f2f176d2d6 100644 --- a/dspace/solr/search/conf/schema.xml +++ b/dspace/solr/search/conf/schema.xml @@ -162,6 +162,7 @@ + From acfe272fbca0d1ffba13a9a0ab391256ad4cf3d1 Mon Sep 17 00:00:00 2001 From: Agustina Martinez Date: Fri, 19 Jan 2024 21:32:04 +0000 Subject: [PATCH 112/230] Fix generating versioned identifiers if pre-registration is enabled (cherry picked from commit 1844fd28a0df0395192ff2b17c9018b2c46ed72e) --- .../content/WorkspaceItemServiceImpl.java | 15 ++++++++++--- .../dspace/content/packager/PackageUtils.java | 2 +- .../content/service/WorkspaceItemService.java | 21 ++++++++++++++++++- .../DefaultItemVersionProvider.java | 4 +++- .../org/dspace/app/packager/PackagerIT.java | 2 +- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java index b6e7372af184..b78f6b9f7de8 100644 --- a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java @@ -96,11 +96,18 @@ public WorkspaceItem find(Context context, int id) throws SQLException { @Override public WorkspaceItem create(Context context, Collection collection, boolean template) throws AuthorizeException, SQLException { - return create(context, collection, null, template); + return create(context, collection, null, template, false); } @Override - public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template) + public WorkspaceItem create(Context context, Collection collection, boolean template, boolean isNewVersion) + throws AuthorizeException, SQLException { + return create(context, collection, null, template, isNewVersion); + } + + @Override + public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template, + boolean isNewVersion) throws AuthorizeException, SQLException { // Check the user has permission to ADD to the collection authorizeService.authorizeAction(context, collection, Constants.ADD); @@ -174,8 +181,10 @@ public WorkspaceItem create(Context context, Collection collection, UUID uuid, b // If configured, register identifiers (eg handle, DOI) now. This is typically used with the Show Identifiers // submission step which previews minted handles and DOIs during the submission process. Default: false + // Additional check needed: if we are creating a new version of an existing item we skip the identifier + // generation here, as this will be performed when the new version is created in VersioningServiceImpl if (DSpaceServicesFactory.getInstance().getConfigurationService() - .getBooleanProperty("identifiers.submission.register", false)) { + .getBooleanProperty("identifiers.submission.register", false) && !isNewVersion) { try { // Get map of filters to use for identifier types, while the item is in progress Map, Filter> filters = FilterUtils.getIdentifierFilters(true); diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java index 9e7d870076aa..9a8ae4606487 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java @@ -503,7 +503,7 @@ public static DSpaceObject createDSpaceObject(Context context, DSpaceObject pare wsi = workspaceItemService.create(context, (Collection)parent, params.useCollectionTemplate()); } else { wsi = workspaceItemService.create(context, (Collection)parent, - uuid, params.useCollectionTemplate()); + uuid, params.useCollectionTemplate(), false); } // Please note that we are returning an Item which is *NOT* yet in the Archive, diff --git a/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java b/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java index c8df68e43498..8559bcc61402 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java @@ -56,6 +56,23 @@ public interface WorkspaceItemService extends InProgressSubmissionServicetrue, the workspace item starts as a copy + * of the collection's template item + * @param isNewVersion whether we are creating a new workspace item version of an existing item + * @return the newly created workspace item + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + public WorkspaceItem create(Context context, Collection collection, boolean template, boolean isNewVersion) + throws AuthorizeException, SQLException; + /** * Create a new workspace item, with a new ID. An Item is also created. The * submitter is the current user in the context. @@ -65,11 +82,13 @@ public WorkspaceItem create(Context context, Collection collection, boolean temp * @param uuid the preferred uuid of the new item (used if restoring an item and retaining old uuid) * @param template if true, the workspace item starts as a copy * of the collection's template item + * @param isNewVersion whether we are creating a new workspace item version of an existing item * @return the newly created workspace item * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template) + public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template, + boolean isNewVersion) throws AuthorizeException, SQLException; public WorkspaceItem create(Context c, WorkflowItem wfi) throws SQLException, AuthorizeException; diff --git a/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java b/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java index d4590ae24ea2..fa89b3441408 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java +++ b/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java @@ -52,7 +52,9 @@ public class DefaultItemVersionProvider extends AbstractVersionProvider implemen @Override public Item createNewItemAndAddItInWorkspace(Context context, Item nativeItem) { try { - WorkspaceItem workspaceItem = workspaceItemService.create(context, nativeItem.getOwningCollection(), false); + WorkspaceItem workspaceItem = workspaceItemService.create(context, nativeItem.getOwningCollection(), + false, + true); Item itemNew = workspaceItem.getItem(); itemService.update(context, itemNew); return itemNew; diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index 7d808ab8715c..2cddbb511f91 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -159,7 +159,7 @@ public void packagerUUIDAlreadyExistWithoutForceTest() throws Exception { performExportScript(article.getHandle(), tempFile); UUID id = article.getID(); itemService.delete(context, article); - WorkspaceItem workspaceItem = workspaceItemService.create(context, col1, id, false); + WorkspaceItem workspaceItem = workspaceItemService.create(context, col1, id, false, false); installItemService.installItem(context, workspaceItem, "123456789/0100"); performImportNoForceScript(tempFile); Iterator items = itemService.findByCollection(context, col1); From 9779c175db5fe3e22ce9c8ef3c7d3301d221f082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Gra=C3=A7a?= Date: Mon, 8 Apr 2024 16:44:43 +0100 Subject: [PATCH 113/230] Replace organisation->organization --- dspace/config/spring/api/discovery.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index fb25f11598fa..c5486ad84e63 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -2889,16 +2889,16 @@ - + - + - + From 5aa32dfd5a2c8867facec798dbc24e56168b3478 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 8 Apr 2024 10:35:20 -0500 Subject: [PATCH 114/230] Update all GitHub Actions. Add newly required CODECOV_TOKEN to codecov action --- .github/workflows/build.yml | 11 ++++++----- .github/workflows/codescan.yml | 2 +- .github/workflows/issue_opened.yml | 2 +- .github/workflows/pull_request_opened.yml | 2 +- .github/workflows/reusable-docker-build.yml | 4 ++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6913078e471..8b3cb1d017a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,7 @@ jobs: # https://github.com/actions/setup-java - name: Install JDK ${{ matrix.java }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: ${{ matrix.java }} distribution: 'temurin' @@ -65,14 +65,14 @@ jobs: # (This artifact is downloadable at the bottom of any job's summary page) - name: Upload Results of ${{ matrix.type }} to Artifact if: ${{ failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.type }} results path: ${{ matrix.resultsdir }} # Upload code coverage report to artifact, so that it can be shared with the 'codecov' job (see below) - name: Upload code coverage report to Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.type }} coverage report path: 'dspace/target/site/jacoco-aggregate/jacoco.xml' @@ -91,7 +91,7 @@ jobs: # Download artifacts from previous 'tests' job - name: Download coverage artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 # Now attempt upload to Codecov using its action. # NOTE: We use a retry action to retry the Codecov upload if it fails the first time. @@ -101,10 +101,11 @@ jobs: - name: Upload coverage to Codecov.io uses: Wandalen/wretry.action@v1.3.0 with: - action: codecov/codecov-action@v3 + action: codecov/codecov-action@v4 # Ensure codecov-action throws an error when it fails to upload with: | fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} # Try re-running action 5 times max attempt_limit: 5 # Run again in 30 seconds diff --git a/.github/workflows/codescan.yml b/.github/workflows/codescan.yml index 13bb0d2278ad..1e3d835e2713 100644 --- a/.github/workflows/codescan.yml +++ b/.github/workflows/codescan.yml @@ -39,7 +39,7 @@ jobs: # https://github.com/actions/setup-java - name: Install JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 11 distribution: 'temurin' diff --git a/.github/workflows/issue_opened.yml b/.github/workflows/issue_opened.yml index b4436dca3aad..0a35a6a95044 100644 --- a/.github/workflows/issue_opened.yml +++ b/.github/workflows/issue_opened.yml @@ -16,7 +16,7 @@ jobs: # Only add to project board if issue is flagged as "needs triage" or has no labels # NOTE: By default we flag new issues as "needs triage" in our issue template if: (contains(github.event.issue.labels.*.name, 'needs triage') || join(github.event.issue.labels.*.name) == '') - uses: actions/add-to-project@v0.5.0 + uses: actions/add-to-project@v1.0.0 # Note, the authentication token below is an ORG level Secret. # It must be created/recreated manually via a personal access token with admin:org, project, public_repo permissions # See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#permissions-for-the-github_token diff --git a/.github/workflows/pull_request_opened.yml b/.github/workflows/pull_request_opened.yml index f16e81c9fd25..bbac52af2438 100644 --- a/.github/workflows/pull_request_opened.yml +++ b/.github/workflows/pull_request_opened.yml @@ -21,4 +21,4 @@ jobs: # Assign the PR to whomever created it. This is useful for visualizing assignments on project boards # See https://github.com/toshimaru/auto-author-assign - name: Assign PR to creator - uses: toshimaru/auto-author-assign@v2.0.1 + uses: toshimaru/auto-author-assign@v2.1.0 diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml index aa8327f4d11b..2f80ef4ba925 100644 --- a/.github/workflows/reusable-docker-build.yml +++ b/.github/workflows/reusable-docker-build.yml @@ -152,7 +152,7 @@ jobs: # Upload digest to an artifact, so that it can be used in manifest below - name: Upload Docker build digest to artifact if: ${{ ! matrix.isPr }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: digests-${{ inputs.build_id }} path: /tmp/digests/* @@ -192,7 +192,7 @@ jobs: - docker-build steps: - name: Download Docker build digests - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: digests-${{ inputs.build_id }} path: /tmp/digests From a1d7c47f1ede3222cea38505de654113b962eefc Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 9 Apr 2024 09:53:21 -0500 Subject: [PATCH 115/230] Fix Docker build by ensuring all artifacts are named with architecture (amd64 vs arm64) (cherry picked from commit f4edf9286075a8233b6bff4937e820dd279f58b8) --- .github/workflows/reusable-docker-build.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml index 2f80ef4ba925..41a2b4b4fef7 100644 --- a/.github/workflows/reusable-docker-build.yml +++ b/.github/workflows/reusable-docker-build.yml @@ -154,7 +154,7 @@ jobs: if: ${{ ! matrix.isPr }} uses: actions/upload-artifact@v4 with: - name: digests-${{ inputs.build_id }} + name: digests-${{ inputs.build_id }}-${{ matrix.arch }} path: /tmp/digests/* if-no-files-found: error retention-days: 1 @@ -172,7 +172,7 @@ jobs: # If this build is NOT a PR and passed in a REDEPLOY_DEMO_URL secret, # Then redeploy https://demo.dspace.org if this build is for our deployment architecture and demo branch. - - name: Redeploy demo.dspace.org (based on maintenace branch) + - name: Redeploy demo.dspace.org (based on maintenance branch) if: | !matrix.isPR && env.REDEPLOY_DEMO_URL != '' && @@ -194,8 +194,10 @@ jobs: - name: Download Docker build digests uses: actions/download-artifact@v4 with: - name: digests-${{ inputs.build_id }} path: /tmp/digests + # Download digests for both AMD64 and ARM64 into same directory + pattern: digests-${{ inputs.build_id }}-* + merge-multiple: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 From 49e54eb34fb57380d2d47798e5c0e8270224ca98 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 9 Apr 2024 12:35:05 -0500 Subject: [PATCH 116/230] Ensure build digest name does NOT have slashes by changing arch to use dashes --- .github/workflows/reusable-docker-build.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml index 41a2b4b4fef7..687474caed18 100644 --- a/.github/workflows/reusable-docker-build.yml +++ b/.github/workflows/reusable-docker-build.yml @@ -93,6 +93,14 @@ jobs: runs-on: ${{ matrix.os }} steps: + # This step converts the slashes in the "arch" matrix values above into dashes & saves to env.ARCH_NAME + # E.g. "linux/amd64" becomes "linux-amd64" + # This is necessary because all upload artifacts CANNOT have special chars (like slashes) + - name: Prepare + run: | + platform=${{ matrix.arch }} + echo "ARCH_NAME=${platform//\//-}" >> $GITHUB_ENV + # https://github.com/actions/checkout - name: Checkout codebase uses: actions/checkout@v4 @@ -154,7 +162,7 @@ jobs: if: ${{ ! matrix.isPr }} uses: actions/upload-artifact@v4 with: - name: digests-${{ inputs.build_id }}-${{ matrix.arch }} + name: digests-${{ inputs.build_id }}-${{ env.ARCH_NAME }} path: /tmp/digests/* if-no-files-found: error retention-days: 1 From e22bf93a972dffe8279bf2793c43a311229a93ed Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Tue, 9 Apr 2024 17:57:00 +0200 Subject: [PATCH 117/230] Refactor SubmissionConfigConsumer to avoid reload the submission config multiple times during the creation of a collection (cherry picked from commit 00d0a01e1f2c05db67a797d809be3c04dcd215e2) --- .../consumer/SubmissionConfigConsumer.java | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/submit/consumer/SubmissionConfigConsumer.java b/dspace-api/src/main/java/org/dspace/submit/consumer/SubmissionConfigConsumer.java index a593fe8ae066..0cf4ae92c2ca 100644 --- a/dspace-api/src/main/java/org/dspace/submit/consumer/SubmissionConfigConsumer.java +++ b/dspace-api/src/main/java/org/dspace/submit/consumer/SubmissionConfigConsumer.java @@ -8,15 +8,10 @@ package org.dspace.submit.consumer; import org.apache.logging.log4j.Logger; -import org.dspace.content.Collection; -import org.dspace.content.DSpaceObject; import org.dspace.core.Constants; import org.dspace.core.Context; -import org.dspace.discovery.IndexingService; -import org.dspace.discovery.indexobject.IndexableCollection; import org.dspace.event.Consumer; import org.dspace.event.Event; -import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.submit.factory.SubmissionServiceFactory; /** @@ -28,11 +23,9 @@ public class SubmissionConfigConsumer implements Consumer { /** * log4j logger */ - private static Logger log = org.apache.logging.log4j.LogManager.getLogger(SubmissionConfigConsumer.class); + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SubmissionConfigConsumer.class); - IndexingService indexer = DSpaceServicesFactory.getInstance().getServiceManager() - .getServiceByName(IndexingService.class.getName(), - IndexingService.class); + private boolean reloadNeeded = false; @Override public void initialize() throws Exception { @@ -42,37 +35,27 @@ public void initialize() throws Exception { @Override public void consume(Context ctx, Event event) throws Exception { int st = event.getSubjectType(); - int et = event.getEventType(); + if (st == Constants.COLLECTION) { + // NOTE: IndexEventConsumer ("discovery") should be declared before this consumer + // We don't reindex the collection because it will normally be reindexed by IndexEventConsumer + // before the submission configurations are reloaded - if ( st == Constants.COLLECTION ) { - switch (et) { - case Event.MODIFY_METADATA: - // Submission configuration it's based on solr - // for collection's entity type but, at this point - // that info isn't indexed yet, we need to force it - DSpaceObject subject = event.getSubject(ctx); - Collection collectionFromDSOSubject = (Collection) subject; - indexer.indexContent(ctx, new IndexableCollection (collectionFromDSOSubject), true, false, false); - indexer.commit(); - - log.debug("SubmissionConfigConsumer occured: " + event.toString()); - // reload submission configurations - SubmissionServiceFactory.getInstance().getSubmissionConfigService().reload(); - break; - - default: - log.debug("SubmissionConfigConsumer occured: " + event.toString()); - // reload submission configurations - SubmissionServiceFactory.getInstance().getSubmissionConfigService().reload(); - break; - } + log.debug("SubmissionConfigConsumer occurred: " + event); + // submission configurations should be reloaded + reloadNeeded = true; } } @Override public void end(Context ctx) throws Exception { - // No-op + if (reloadNeeded) { + // reload submission configurations + SubmissionServiceFactory.getInstance().getSubmissionConfigService().reload(); + + // Reset the boolean used + reloadNeeded = false; + } } @Override From 7c505e113ed607cc692ca790943dfb6f1c920aa9 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 9 Apr 2024 14:47:21 -0500 Subject: [PATCH 118/230] Docker build IDs must all be unique to avoid image conflicts. Ensure no builds use a generic name like "dspace". --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 9f1e407cff4b..5abfb89a5dc7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -43,7 +43,7 @@ jobs: needs: dspace-dependencies uses: ./.github/workflows/reusable-docker-build.yml with: - build_id: dspace + build_id: dspace-prod image_name: dspace/dspace dockerfile_path: ./Dockerfile secrets: From 2afc9b158eb3b076b6ed4e07d5cfbe939e17fa07 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 10 Apr 2024 09:26:16 -0500 Subject: [PATCH 119/230] Docker build IDs must all be unique to avoid image conflicts. Avoid conflict with "-loadsql" build by appending "-prod" on main build id. --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5abfb89a5dc7..a9ff8760e763 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -120,7 +120,7 @@ jobs: if: github.repository == 'dspace/dspace' uses: ./.github/workflows/reusable-docker-build.yml with: - build_id: dspace-postgres-pgcrypto + build_id: dspace-postgres-pgcrypto-prod image_name: dspace/dspace-postgres-pgcrypto # Must build out of subdirectory to have access to install script for pgcrypto. # NOTE: this context will build the image based on the Dockerfile in the specified directory From 2f7ee4bc769b9fca70fbcb8f59a990cdbe78e7e6 Mon Sep 17 00:00:00 2001 From: Thomas Misilo Date: Fri, 16 Feb 2024 08:45:50 -0600 Subject: [PATCH 120/230] httpd-shibd-foreground.sh needs to be executable In order for the shib container to start, the file that is running needs to be executable (cherry picked from commit 3f9274f23f32e6983f3da81d001d9ce319e7245f) --- .../src/main/docker/dspace-shibboleth/httpd-shibd-foreground.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 dspace/src/main/docker/dspace-shibboleth/httpd-shibd-foreground.sh diff --git a/dspace/src/main/docker/dspace-shibboleth/httpd-shibd-foreground.sh b/dspace/src/main/docker/dspace-shibboleth/httpd-shibd-foreground.sh old mode 100644 new mode 100755 From 8d45c1f94d89d598254c3d97a1e87a4d0713046c Mon Sep 17 00:00:00 2001 From: Tom Misilo <1446856+misilot@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:19:56 -0500 Subject: [PATCH 121/230] Add Space in ePerson's Name for rejection metadata and email (cherry picked from commit ec3089dc4d201201bf607b419b518d06dc1fb4f2) --- .../java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java index bc91a1fd9298..faf15d02c6d8 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java @@ -1177,7 +1177,7 @@ protected WorkspaceItem returnToWorkspace(Context c, XmlWorkflowItem wfi) public String getEPersonName(EPerson ePerson) { String submitter = ePerson.getFullName(); - submitter = submitter + "(" + ePerson.getEmail() + ")"; + submitter = submitter + " (" + ePerson.getEmail() + ")"; return submitter; } From 9b47b2215cd88c63889266a5950c58461dccd3b6 Mon Sep 17 00:00:00 2001 From: "David P. Steelman" Date: Wed, 17 Apr 2024 13:55:34 -0400 Subject: [PATCH 122/230] Fix OpenSearch NullPointerException for unknown valid UUIDs in scope Fixes a NullPointerException when the "scope" parameter provided to the OpenSearch endpoint is a valid UUID, but is not a UUID associated with a Community or Collection. Instead of throwing a NullPointerException, this change modifies the code to return a null scope (resulting in an "unscoped" OpenSearch request), which is the same behavior that occurs when the UUID is invalid, or otherwise not usable. --- .../dspace/app/rest/utils/ScopeResolver.java | 22 +++++++++++++++ .../opensearch/OpenSearchControllerIT.java | 28 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ScopeResolver.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ScopeResolver.java index 658a3e996aef..7a425f5e81a8 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ScopeResolver.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ScopeResolver.java @@ -35,6 +35,18 @@ public class ScopeResolver { @Autowired CommunityService communityService; + /** + * Returns an IndexableObject corresponding to the community or collection + * of the given scope, or null if the scope is not a valid UUID, or is a + * valid UUID that does not correspond to a community of collection. + * + * @param context the DSpace context + * @param scope a String containing the UUID of the community or collection + * to return. + * @return an IndexableObject corresponding to the community or collection + * of the given scope, or null if the scope is not a valid UUID, or is a + * valid UUID that does not correspond to a community of collection. + */ public IndexableObject resolveScope(Context context, String scope) { IndexableObject scopeObj = null; if (StringUtils.isNotBlank(scope)) { @@ -43,6 +55,16 @@ public IndexableObject resolveScope(Context context, String scope) { scopeObj = new IndexableCommunity(communityService.find(context, uuid)); if (scopeObj.getIndexedObject() == null) { scopeObj = new IndexableCollection(collectionService.find(context, uuid)); + if (scopeObj.getIndexedObject() == null) { + // Can't find the UUID as a community or collection + // so log and return null + log.warn( + "The given scope string " + + StringUtils.trimToEmpty(scope) + + " is not a collection or community UUID." + ); + scopeObj = null; + } } } catch (IllegalArgumentException ex) { log.warn("The given scope string " + StringUtils.trimToEmpty(scope) + " is not a UUID", ex); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/opensearch/OpenSearchControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/opensearch/OpenSearchControllerIT.java index 1ddea619d2fc..b533e14568e6 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/opensearch/OpenSearchControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/opensearch/OpenSearchControllerIT.java @@ -269,4 +269,32 @@ public void emptyDescriptionTest() throws Exception { .andExpect(status().isOk()) .andExpect(xpath("rss/channel/description").string("No Description")); } + + @Test + public void scopeNotCommunityOrCollectionUUIDTest() throws Exception { + // Tests that a OpenSearch response with 1 result (equivalent to an + // unscoped request) is returned if the "scope" UUID is a + // validly-formatted UUID, but not a community or collection UUID. + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection collection1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1") + .build(); + + Item publicItem1 = ItemBuilder.createItem(context, collection1) + .withTitle("Boars at Yellowstone") + .withIssueDate("2017-10-17") + .withAuthor("Ballini, Andreas").withAuthor("Moriarti, Susan") + .build(); + + // UUID is valid, but not a community or collection UUID + String testUUID = "b68f0d1c-7316-41dc-835d-46b79b35642e"; + + getClient().perform(get("/opensearch/search") + .param("scope", testUUID) + .param("query", "*")) + .andExpect(status().isOk()) + .andExpect(xpath("feed/totalResults").string("1")); + } } From e82b94fa435663419a2fd78a9aad9d9e488f7ecc Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Mon, 15 Apr 2024 12:56:58 +0200 Subject: [PATCH 123/230] Add support for LazyDownload of files from S3 --- .../storage/bitstore/S3BitStoreService.java | 87 ++++++++++++++++--- .../storage/bitstore/S3BitStoreServiceIT.java | 21 ++++- 2 files changed, 90 insertions(+), 18 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java index 48f3b9f325f8..54333abbf49b 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java @@ -10,6 +10,7 @@ import static java.lang.String.valueOf; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -24,6 +25,7 @@ import javax.validation.constraints.NotNull; import com.amazonaws.AmazonClientException; +import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; @@ -35,6 +37,7 @@ import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.transfer.Download; +import com.amazonaws.services.s3.transfer.Transfer.TransferState; import com.amazonaws.services.s3.transfer.TransferManager; import com.amazonaws.services.s3.transfer.TransferManagerBuilder; import com.amazonaws.services.s3.transfer.Upload; @@ -102,6 +105,11 @@ public class S3BitStoreService extends BaseBitStoreService { private String awsRegionName; private boolean useRelativePath; + /** + * The maximum size of individual chunk to download from S3 when a file is accessed. Default 5Mb + */ + private long bufferSize = 5 * 1024 * 1024; + /** * container for all the assets */ @@ -258,20 +266,7 @@ public InputStream get(Bitstream bitstream) throws IOException { if (isRegisteredBitstream(key)) { key = key.substring(REGISTERED_FLAG.length()); } - try { - File tempFile = File.createTempFile("s3-disk-copy-" + UUID.randomUUID(), "temp"); - tempFile.deleteOnExit(); - - GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key); - - Download download = tm.download(getObjectRequest, tempFile); - download.waitForCompletion(); - - return new DeleteOnCloseFileInputStream(tempFile); - } catch (AmazonClientException | InterruptedException e) { - log.error("get(" + key + ")", e); - throw new IOException(e); - } + return new S3LazyInputStream(key, bufferSize, bitstream.getSizeBytes()); } /** @@ -622,4 +617,68 @@ public boolean isRegisteredBitstream(String internalId) { return internalId.startsWith(REGISTERED_FLAG); } + public void setBufferSize(long bufferSize) { + this.bufferSize = bufferSize; + } + + public class S3LazyInputStream extends InputStream { + private InputStream currentChunkStream; + private String objectKey; + private long endOfChunk = -1; + private long chunkMaxSize; + private long currPos = 0; + private long fileSize; + + public S3LazyInputStream(String objectKey, long chunkMaxSize, long fileSize) throws IOException { + this.objectKey = objectKey; + this.chunkMaxSize = chunkMaxSize; + this.endOfChunk = 0; + this.fileSize = fileSize; + downloadChunk(); + } + + @Override + public int read() throws IOException { + if (currPos == endOfChunk && currPos < fileSize) { + currentChunkStream.close(); + downloadChunk(); + } + + int byteRead = currPos < endOfChunk ? currentChunkStream.read() : -1; + if (byteRead != -1) { + currPos++; + } else { + currentChunkStream.close(); + } + return byteRead; + } + + private void downloadChunk() throws IOException, FileNotFoundException { + // Create a DownloadFileRequest with the desired byte range + long startByte = currPos; // Start byte (inclusive) + long endByte = Long.min(startByte + chunkMaxSize - 1, fileSize - 1); // End byte (inclusive) + GetObjectRequest getRequest = new GetObjectRequest(bucketName, objectKey) + .withRange(startByte, endByte); + + File currentChunkFile = File.createTempFile("s3-disk-copy-" + UUID.randomUUID(), "temp"); + currentChunkFile.deleteOnExit(); + try { + Download download = tm.download(getRequest, currentChunkFile); + download.waitForCompletion(); + currentChunkStream = new DeleteOnCloseFileInputStream(currentChunkFile); + endOfChunk = endOfChunk + download.getProgress().getBytesTransferred(); + } catch (AmazonClientException | InterruptedException e) { + currentChunkFile.delete(); + throw new IOException(e); + } + } + + @Override + public void close() throws IOException { + if (currentChunkStream != null) { + currentChunkStream.close(); + } + } + + } } diff --git a/dspace-api/src/test/java/org/dspace/storage/bitstore/S3BitStoreServiceIT.java b/dspace-api/src/test/java/org/dspace/storage/bitstore/S3BitStoreServiceIT.java index 30eeff2ddc82..dffde0b3a6a8 100644 --- a/dspace-api/src/test/java/org/dspace/storage/bitstore/S3BitStoreServiceIT.java +++ b/dspace-api/src/test/java/org/dspace/storage/bitstore/S3BitStoreServiceIT.java @@ -99,6 +99,7 @@ public void setup() throws Exception { s3BitStoreService = new S3BitStoreService(amazonS3Client); s3BitStoreService.setEnabled(BooleanUtils.toBoolean( configurationService.getProperty("assetstore.s3.enabled"))); + s3BitStoreService.setBufferSize(22); context.turnOffAuthorisationSystem(); parentCommunity = CommunityBuilder.createCommunity(context) @@ -129,12 +130,25 @@ public void testBitstreamPutAndGetWithAlreadyPresentBucket() throws IOException assertThat(amazonS3Client.listBuckets(), contains(bucketNamed(bucketName))); context.turnOffAuthorisationSystem(); - String content = "Test bitstream content"; + String content = "Test bitstream content"; + String contentOverOneSpan = "This content span two chunks"; + String contentExactlyTwoSpans = "Test bitstream contentTest bitstream content"; + String contentOverOneTwoSpans = "Test bitstream contentThis content span three chunks"; Bitstream bitstream = createBitstream(content); + Bitstream bitstreamOverOneSpan = createBitstream(contentOverOneSpan); + Bitstream bitstreamExactlyTwoSpans = createBitstream(contentExactlyTwoSpans); + Bitstream bitstreamOverOneTwoSpans = createBitstream(contentOverOneTwoSpans); context.restoreAuthSystemState(); - s3BitStoreService.put(bitstream, toInputStream(content)); + checkGetPut(bucketName, content, bitstream); + checkGetPut(bucketName, contentOverOneSpan, bitstreamOverOneSpan); + checkGetPut(bucketName, contentExactlyTwoSpans, bitstreamExactlyTwoSpans); + checkGetPut(bucketName, contentOverOneTwoSpans, bitstreamOverOneTwoSpans); + + } + private void checkGetPut(String bucketName, String content, Bitstream bitstream) throws IOException { + s3BitStoreService.put(bitstream, toInputStream(content)); String expectedChecksum = Utils.toHex(generateChecksum(content)); assertThat(bitstream.getSizeBytes(), is((long) content.length())); @@ -147,8 +161,7 @@ public void testBitstreamPutAndGetWithAlreadyPresentBucket() throws IOException String key = s3BitStoreService.getFullKey(bitstream.getInternalId()); ObjectMetadata objectMetadata = amazonS3Client.getObjectMetadata(bucketName, key); assertThat(objectMetadata.getContentMD5(), is(expectedChecksum)); - - } + } @Test public void testBitstreamPutAndGetWithoutSpecifingBucket() throws IOException { From 23ee2fd6cdd63b1fafe1916736a9359df2187348 Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Fri, 19 Apr 2024 07:52:32 +0200 Subject: [PATCH 124/230] DURACOM-249 fix checkstyle issues, add javadoc --- .../storage/bitstore/S3BitStoreService.java | 58 ++++++++++++------- .../storage/bitstore/S3BitStoreServiceIT.java | 6 +- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java index 54333abbf49b..e21a101a7e98 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java @@ -25,7 +25,6 @@ import javax.validation.constraints.NotNull; import com.amazonaws.AmazonClientException; -import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; @@ -37,7 +36,6 @@ import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.transfer.Download; -import com.amazonaws.services.s3.transfer.Transfer.TransferState; import com.amazonaws.services.s3.transfer.TransferManager; import com.amazonaws.services.s3.transfer.TransferManagerBuilder; import com.amazonaws.services.s3.transfer.Upload; @@ -621,6 +619,14 @@ public void setBufferSize(long bufferSize) { this.bufferSize = bufferSize; } + /** + * This inner class represent an InputStream that uses temporary files to + * represent chunk of the object downloaded from S3. When the input stream is + * read the class look first to the current chunk and download a new one once if + * the current one as been fully read. The class is responsible to close a chunk + * as soon as a new one is retrieved, the last chunk is closed when the input + * stream itself is closed or the last byte is read (the first of the two) + */ public class S3LazyInputStream extends InputStream { private InputStream currentChunkStream; private String objectKey; @@ -639,12 +645,14 @@ public S3LazyInputStream(String objectKey, long chunkMaxSize, long fileSize) thr @Override public int read() throws IOException { + // is the current chunk completely read and other are available? if (currPos == endOfChunk && currPos < fileSize) { currentChunkStream.close(); downloadChunk(); } - int byteRead = currPos < endOfChunk ? currentChunkStream.read() : -1; + int byteRead = currPos < endOfChunk ? currentChunkStream.read() : -1; + // do we get any data or are we at the end of the file? if (byteRead != -1) { currPos++; } else { @@ -653,25 +661,31 @@ public int read() throws IOException { return byteRead; } - private void downloadChunk() throws IOException, FileNotFoundException { - // Create a DownloadFileRequest with the desired byte range - long startByte = currPos; // Start byte (inclusive) - long endByte = Long.min(startByte + chunkMaxSize - 1, fileSize - 1); // End byte (inclusive) - GetObjectRequest getRequest = new GetObjectRequest(bucketName, objectKey) - .withRange(startByte, endByte); - - File currentChunkFile = File.createTempFile("s3-disk-copy-" + UUID.randomUUID(), "temp"); - currentChunkFile.deleteOnExit(); - try { - Download download = tm.download(getRequest, currentChunkFile); - download.waitForCompletion(); - currentChunkStream = new DeleteOnCloseFileInputStream(currentChunkFile); - endOfChunk = endOfChunk + download.getProgress().getBytesTransferred(); - } catch (AmazonClientException | InterruptedException e) { - currentChunkFile.delete(); - throw new IOException(e); - } - } + /** + * This method download the next chunk from S3 + * + * @throws IOException + * @throws FileNotFoundException + */ + private void downloadChunk() throws IOException, FileNotFoundException { + // Create a DownloadFileRequest with the desired byte range + long startByte = currPos; // Start byte (inclusive) + long endByte = Long.min(startByte + chunkMaxSize - 1, fileSize - 1); // End byte (inclusive) + GetObjectRequest getRequest = new GetObjectRequest(bucketName, objectKey) + .withRange(startByte, endByte); + + File currentChunkFile = File.createTempFile("s3-disk-copy-" + UUID.randomUUID(), "temp"); + currentChunkFile.deleteOnExit(); + try { + Download download = tm.download(getRequest, currentChunkFile); + download.waitForCompletion(); + currentChunkStream = new DeleteOnCloseFileInputStream(currentChunkFile); + endOfChunk = endOfChunk + download.getProgress().getBytesTransferred(); + } catch (AmazonClientException | InterruptedException e) { + currentChunkFile.delete(); + throw new IOException(e); + } + } @Override public void close() throws IOException { diff --git a/dspace-api/src/test/java/org/dspace/storage/bitstore/S3BitStoreServiceIT.java b/dspace-api/src/test/java/org/dspace/storage/bitstore/S3BitStoreServiceIT.java index dffde0b3a6a8..6ea21eac8d6d 100644 --- a/dspace-api/src/test/java/org/dspace/storage/bitstore/S3BitStoreServiceIT.java +++ b/dspace-api/src/test/java/org/dspace/storage/bitstore/S3BitStoreServiceIT.java @@ -147,8 +147,8 @@ public void testBitstreamPutAndGetWithAlreadyPresentBucket() throws IOException } - private void checkGetPut(String bucketName, String content, Bitstream bitstream) throws IOException { - s3BitStoreService.put(bitstream, toInputStream(content)); + private void checkGetPut(String bucketName, String content, Bitstream bitstream) throws IOException { + s3BitStoreService.put(bitstream, toInputStream(content)); String expectedChecksum = Utils.toHex(generateChecksum(content)); assertThat(bitstream.getSizeBytes(), is((long) content.length())); @@ -161,7 +161,7 @@ private void checkGetPut(String bucketName, String content, Bitstream bitstream) String key = s3BitStoreService.getFullKey(bitstream.getInternalId()); ObjectMetadata objectMetadata = amazonS3Client.getObjectMetadata(bucketName, key); assertThat(objectMetadata.getContentMD5(), is(expectedChecksum)); - } + } @Test public void testBitstreamPutAndGetWithoutSpecifingBucket() throws IOException { From 15d9d1c0423c9dc90ef67717043cb5e7dda6ccc8 Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Fri, 19 Apr 2024 21:03:45 +0200 Subject: [PATCH 125/230] Port from #9259 the changes to use a collection object to return the item process submission configured --- .../org/dspace/app/util/DCInputsReader.java | 10 ++++---- .../app/util/SubmissionConfigReader.java | 24 ++++++++++++------- .../main/java/org/dspace/app/util/Util.java | 14 +++-------- .../authority/ChoiceAuthorityServiceImpl.java | 4 ++-- .../ctask/general/RequiredMetadata.java | 9 +++---- .../service/SubmissionConfigService.java | 2 +- .../service/SubmissionConfigServiceImpl.java | 4 ++-- .../dspace/app/util/SubmissionConfigTest.java | 10 +++++++- .../converter/AInprogressItemConverter.java | 2 +- .../SubmissionDefinitionRestRepository.java | 2 +- .../WorkspaceItemRestRepository.java | 2 +- 11 files changed, 45 insertions(+), 38 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java index 38692c73a6ce..8dc8239ca507 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java @@ -14,7 +14,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import javax.servlet.ServletException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; @@ -150,17 +149,16 @@ public List getPairs(String name) { * Returns the set of DC inputs used for a particular collection, or the * default set if no inputs defined for the collection * - * @param collectionHandle collection's unique Handle + * @param collection collection for which search the set of DC inputs * @return DC input set * @throws DCInputsReaderException if no default set defined - * @throws ServletException */ - public List getInputsByCollectionHandle(String collectionHandle) + public List getInputsByCollection(Collection collection) throws DCInputsReaderException { SubmissionConfig config; try { config = SubmissionServiceFactory.getInstance().getSubmissionConfigService() - .getSubmissionConfigByCollection(collectionHandle); + .getSubmissionConfigByCollection(collection); String formName = config.getSubmissionName(); if (formName == null) { throw new DCInputsReaderException("No form designated as default"); @@ -691,7 +689,7 @@ private String getValue(Node nd) { public String getInputFormNameByCollectionAndField(Collection collection, String field) throws DCInputsReaderException { - List inputSets = getInputsByCollectionHandle(collection.getHandle()); + List inputSets = getInputsByCollection(collection); for (DCInputSet inputSet : inputSets) { String[] tokenized = Utils.tokenize(field); String schema = tokenized[0]; diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java index 0f144fd69f46..82bb1c9ca4a8 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java +++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java @@ -210,18 +210,26 @@ public int countSubmissionConfigs() { * Returns the Item Submission process config used for a particular * collection, or the default if none is defined for the collection * - * @param collectionHandle collection's unique Handle + * @param col collection for which search Submission process config * @return the SubmissionConfig representing the item submission config - * @throws SubmissionConfigReaderException if no default submission process configuration defined + * @throws IllegalStateException if no default submission process configuration defined */ - public SubmissionConfig getSubmissionConfigByCollection(String collectionHandle) { - // get the name of the submission process config for this collection - String submitName = collectionToSubmissionConfig - .get(collectionHandle); - if (submitName == null) { + public SubmissionConfig getSubmissionConfigByCollection(Collection col) { + + String submitName; + + if (col != null) { + + // get the name of the submission process config for this collection submitName = collectionToSubmissionConfig - .get(DEFAULT_COLLECTION); + .get(col.getHandle()); + if (submitName != null) { + return getSubmissionConfigByName(submitName); + } } + + submitName = collectionToSubmissionConfig.get(DEFAULT_COLLECTION); + if (submitName == null) { throw new IllegalStateException( "No item submission process configuration designated as 'default' in 'submission-map' section of " + diff --git a/dspace-api/src/main/java/org/dspace/app/util/Util.java b/dspace-api/src/main/java/org/dspace/app/util/Util.java index f8ef3b1731f7..3bc828d6c496 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/Util.java +++ b/dspace-api/src/main/java/org/dspace/app/util/Util.java @@ -405,21 +405,13 @@ public static List getControlledVocabulariesDisplayValueLocalized( DCInput myInputs = null; boolean myInputsFound = false; String formFileName = I18nUtil.getInputFormsFileName(locale); - String col_handle = ""; Collection collection = item.getOwningCollection(); - if (collection == null) { - // set an empty handle so to get the default input set - col_handle = ""; - } else { - col_handle = collection.getHandle(); - } - // Read the input form file for the specific collection DCInputsReader inputsReader = new DCInputsReader(formFileName); - List inputSets = inputsReader.getInputsByCollectionHandle(col_handle); + List inputSets = inputsReader.getInputsByCollection(collection); // Replace the values of Metadatum[] with the correct ones in case // of @@ -500,8 +492,8 @@ public static List[] splitList(List idsList, int i) { public static List differenceInSubmissionFields(Collection fromCollection, Collection toCollection) throws DCInputsReaderException { DCInputsReader reader = new DCInputsReader(); - List from = reader.getInputsByCollectionHandle(fromCollection.getHandle()); - List to = reader.getInputsByCollectionHandle(toCollection.getHandle()); + List from = reader.getInputsByCollection(fromCollection); + List to = reader.getInputsByCollection(toCollection); Set fromFieldName = new HashSet<>(); Set toFieldName = new HashSet<>(); diff --git a/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java index 34ba9e8c4550..f4d1f02710e1 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java @@ -242,7 +242,7 @@ public String getChoiceAuthorityName(String schema, String element, String quali // check if it is the requested collection Map controllerFormDef = controllerFormDefinitions.get(fieldKey); SubmissionConfig submissionConfig = submissionConfigService - .getSubmissionConfigByCollection(collection.getHandle()); + .getSubmissionConfigByCollection(collection); String submissionName = submissionConfig.getSubmissionName(); // check if the requested collection has a submission definition that use an authority for the metadata if (controllerFormDef.containsKey(submissionName)) { @@ -495,7 +495,7 @@ private ChoiceAuthority getAuthorityByFieldKeyCollection(String fieldKey, Collec try { configReaderService = SubmissionServiceFactory.getInstance().getSubmissionConfigService(); SubmissionConfig submissionName = configReaderService - .getSubmissionConfigByCollection(collection.getHandle()); + .getSubmissionConfigByCollection(collection); ma = controllerFormDefinitions.get(fieldKey).get(submissionName.getSubmissionName()); } catch (SubmissionConfigReaderException e) { // the system is in an illegal state as the submission definition is not valid diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/RequiredMetadata.java b/dspace-api/src/main/java/org/dspace/ctask/general/RequiredMetadata.java index 07bfed5fe572..2899e3f6bdd6 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/RequiredMetadata.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/RequiredMetadata.java @@ -17,6 +17,7 @@ import org.dspace.app.util.DCInputSet; import org.dspace.app.util.DCInputsReader; import org.dspace.app.util.DCInputsReaderException; +import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.MetadataValue; @@ -69,7 +70,7 @@ public int perform(DSpaceObject dso) throws IOException { handle = "in workflow"; } sb.append("Item: ").append(handle); - for (String req : getReqList(item.getOwningCollection().getHandle())) { + for (String req : getReqList(item.getOwningCollection())) { List vals = itemService.getMetadataByMetadataString(item, req); if (vals.size() == 0) { sb.append(" missing required field: ").append(req); @@ -91,14 +92,14 @@ public int perform(DSpaceObject dso) throws IOException { } } - protected List getReqList(String handle) throws DCInputsReaderException { - List reqList = reqMap.get(handle); + protected List getReqList(Collection collection) throws DCInputsReaderException { + List reqList = reqMap.get(collection.getHandle()); if (reqList == null) { reqList = reqMap.get("default"); } if (reqList == null) { reqList = new ArrayList(); - List inputSet = reader.getInputsByCollectionHandle(handle); + List inputSet = reader.getInputsByCollection(collection); for (DCInputSet inputs : inputSet) { for (DCInput[] row : inputs.getFields()) { for (DCInput input : row) { diff --git a/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigService.java b/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigService.java index c4b111a38f7e..36ba82f60d53 100644 --- a/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigService.java +++ b/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigService.java @@ -34,7 +34,7 @@ public interface SubmissionConfigService { public int countSubmissionConfigs(); - public SubmissionConfig getSubmissionConfigByCollection(String collectionHandle); + public SubmissionConfig getSubmissionConfigByCollection(Collection collection); public SubmissionConfig getSubmissionConfigByName(String submitName); diff --git a/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigServiceImpl.java b/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigServiceImpl.java index a72bcc2c3bf9..fe063954a1d3 100644 --- a/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigServiceImpl.java @@ -57,8 +57,8 @@ public int countSubmissionConfigs() { } @Override - public SubmissionConfig getSubmissionConfigByCollection(String collectionHandle) { - return submissionConfigReader.getSubmissionConfigByCollection(collectionHandle); + public SubmissionConfig getSubmissionConfigByCollection(Collection collection) { + return submissionConfigReader.getSubmissionConfigByCollection(collection); } @Override diff --git a/dspace-api/src/test/java/org/dspace/app/util/SubmissionConfigTest.java b/dspace-api/src/test/java/org/dspace/app/util/SubmissionConfigTest.java index cb1f828b93c4..4ac193109875 100644 --- a/dspace-api/src/test/java/org/dspace/app/util/SubmissionConfigTest.java +++ b/dspace-api/src/test/java/org/dspace/app/util/SubmissionConfigTest.java @@ -9,17 +9,20 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.List; import org.dspace.AbstractUnitTest; +import org.dspace.content.Collection; import org.dspace.submit.factory.SubmissionServiceFactory; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.Mock; /** * Tests for parsing and utilities on submission config forms / readers @@ -30,6 +33,9 @@ public class SubmissionConfigTest extends AbstractUnitTest { DCInputsReader inputReader; + @Mock + private Collection col1; + @BeforeClass public static void setUpClass() { } @@ -56,6 +62,8 @@ public void testReadAndProcessTypeBindSubmissionConfig() String typeBindSubmissionName = "typebindtest"; String typeBindSubmissionStepName = "typebindtest"; + when(col1.getHandle()).thenReturn(typeBindHandle); + // Expected field lists from typebindtest form List allConfiguredFields = new ArrayList<>(); allConfiguredFields.add("dc.title"); @@ -67,7 +75,7 @@ public void testReadAndProcessTypeBindSubmissionConfig() // Get submission configuration SubmissionConfig submissionConfig = SubmissionServiceFactory.getInstance().getSubmissionConfigService() - .getSubmissionConfigByCollection(typeBindHandle); + .getSubmissionConfigByCollection(col1); // Submission name should match name defined in item-submission.xml assertEquals(typeBindSubmissionName, submissionConfig.getSubmissionName()); // Step 0 - our process only has one step. It should not be null and have the ID typebindtest diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java index a5431d90004f..a80c8bd948b9 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java @@ -82,7 +82,7 @@ protected void fillFromModel(T obj, R witem, Projection projection) { if (collection != null) { SubmissionDefinitionRest def = converter.toRest( - submissionConfigService.getSubmissionConfigByCollection(collection.getHandle()), projection); + submissionConfigService.getSubmissionConfigByCollection(collection), projection); witem.setSubmissionDefinition(def); for (SubmissionSectionRest sections : def.getPanels()) { SubmissionStepConfig stepConfig = submissionSectionConverter.toModel(sections); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionDefinitionRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionDefinitionRestRepository.java index d964994928eb..17eb90b7901e 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionDefinitionRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionDefinitionRestRepository.java @@ -70,7 +70,7 @@ public SubmissionDefinitionRest findByCollection(@Parameter(value = "uuid", requ return null; } SubmissionDefinitionRest def = converter - .toRest(submissionConfigService.getSubmissionConfigByCollection(col.getHandle()), + .toRest(submissionConfigService.getSubmissionConfigByCollection(col), utils.obtainProjection()); return def; } 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 b4d04e59e32f..5f4bb0dfe927 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 @@ -251,7 +251,7 @@ public Iterable upload(Context context, HttpServletRequest re } SubmissionConfig submissionConfig = - submissionConfigService.getSubmissionConfigByCollection(collection.getHandle()); + submissionConfigService.getSubmissionConfigByCollection(collection); List result = null; List records = new ArrayList<>(); try { From cf6008271a731f7664a003bd797cb42b568848eb Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Fri, 19 Apr 2024 21:38:31 +0200 Subject: [PATCH 126/230] Refactor SubmissionConfigReader to use a map for the collections configured through the entityType value --- .../app/util/SubmissionConfigReader.java | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java index 82bb1c9ca4a8..7342cc4283fe 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java +++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java @@ -22,10 +22,10 @@ import org.apache.logging.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.core.Context; -import org.dspace.discovery.SearchServiceException; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.services.factory.DSpaceServicesFactory; import org.w3c.dom.Document; @@ -96,6 +96,13 @@ public class SubmissionConfigReader { */ private Map> stepDefns = null; + /** + * Hashmap which stores which submission process configuration is used by + * which entityType, computed from the item submission config file + * (specifically, the 'submission-map' tag) + */ + private Map entityTypeToSubmissionConfig = null; + /** * Reference to the item submission definitions defined in the * "submission-definitions" section @@ -127,6 +134,7 @@ public SubmissionConfigReader() throws SubmissionConfigReaderException { public void reload() throws SubmissionConfigReaderException { collectionToSubmissionConfig = null; + entityTypeToSubmissionConfig = null; stepDefns = null; submitDefns = null; buildInputs(configDir + SUBMIT_DEF_FILE_PREFIX + SUBMIT_DEF_FILE_SUFFIX); @@ -145,6 +153,7 @@ public void reload() throws SubmissionConfigReaderException { */ private void buildInputs(String fileName) throws SubmissionConfigReaderException { collectionToSubmissionConfig = new HashMap(); + entityTypeToSubmissionConfig = new HashMap(); submitDefns = new HashMap>>(); String uri = "file:" + new File(fileName).getAbsolutePath(); @@ -162,9 +171,6 @@ private void buildInputs(String fileName) throws SubmissionConfigReaderException } catch (FactoryConfigurationError fe) { throw new SubmissionConfigReaderException( "Cannot create Item Submission Configuration parser", fe); - } catch (SearchServiceException se) { - throw new SubmissionConfigReaderException( - "Cannot perform a discovery search for Item Submission Configuration", se); } catch (Exception e) { throw new SubmissionConfigReaderException( "Error creating Item Submission Configuration: " + e); @@ -228,6 +234,16 @@ public SubmissionConfig getSubmissionConfigByCollection(Collection col) { } } + // get the name of the submission process based on the entity type of this collections + if (!entityTypeToSubmissionConfig.isEmpty()) { + String entityType = collectionService.getMetadataFirstValue(col, "dspace", "entity", "type", Item.ANY); + submitName = entityTypeToSubmissionConfig + .get(entityType); + if (submitName != null) { + return getSubmissionConfigByName(submitName); + } + } + submitName = collectionToSubmissionConfig.get(DEFAULT_COLLECTION); if (submitName == null) { @@ -308,7 +324,7 @@ public SubmissionStepConfig getStepConfig(String stepID) * should correspond to the collection-form maps, the form definitions, and * the display/storage word pairs. */ - private void doNodes(Node n) throws SAXException, SearchServiceException, SubmissionConfigReaderException { + private void doNodes(Node n) throws SAXException, SubmissionConfigReaderException { if (n == null) { return; } @@ -355,9 +371,7 @@ private void doNodes(Node n) throws SAXException, SearchServiceException, Submis * the collection handle and item submission name, put name in hashmap keyed * by the collection handle. */ - private void processMap(Node e) throws SAXException, SearchServiceException { - // create a context - Context context = new Context(); + private void processMap(Node e) throws SAXException { NodeList nl = e.getChildNodes(); int len = nl.getLength(); @@ -377,7 +391,7 @@ private void processMap(Node e) throws SAXException, SearchServiceException { throw new SAXException( "name-map element is missing submission-name attribute in 'item-submission.xml'"); } - if (content != null && content.length() > 0) { + if (content != null && !content.isEmpty()) { throw new SAXException( "name-map element has content in 'item-submission.xml', it should be empty."); } @@ -385,12 +399,7 @@ private void processMap(Node e) throws SAXException, SearchServiceException { collectionToSubmissionConfig.put(id, value); } else { - // get all collections for this entity-type - List collections = collectionService.findAllCollectionsByEntityType( context, - entityType); - for (Collection collection : collections) { - collectionToSubmissionConfig.putIfAbsent(collection.getHandle(), value); - } + entityTypeToSubmissionConfig.put(entityType, value); } } // ignore any child node that isn't a "name-map" } From 1a65dfb15b021f5e58bdb821ee8d85330c416dd1 Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Fri, 19 Apr 2024 21:39:19 +0200 Subject: [PATCH 127/230] Remove the consumer submissionconfig from default configuration because it is not needed to reload forms if a collection entitytype is changed --- dspace/config/dspace.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index b7cc13e508dc..60a7506d8766 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -780,7 +780,7 @@ event.dispatcher.default.class = org.dspace.event.BasicDispatcher # Add rdf here, if you are using dspace-rdf to export your repository content as RDF. # Add iiif here, if you are using dspace-iiif. # Add orcidqueue here, if the integration with ORCID is configured and wish to enable the synchronization queue functionality -event.dispatcher.default.consumers = versioning, discovery, eperson, submissionconfig +event.dispatcher.default.consumers = versioning, discovery, eperson # The noindex dispatcher will not create search or browse indexes (useful for batch item imports) event.dispatcher.noindex.class = org.dspace.event.BasicDispatcher From 770b38c7934ba58cea1bcf23d819332128e2a956 Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Fri, 19 Apr 2024 22:35:55 +0200 Subject: [PATCH 128/230] Add test for item process submission forms mapped by entityType --- .../app/util/SubmissionConfigReader.java | 3 +- .../dspaceFolder/config/item-submission.xml | 10 + .../dspace/app/util/SubmissionConfigIT.java | 60 ++++ .../SubmissionDefinitionsControllerIT.java | 299 ++++++++++++------ 4 files changed, 275 insertions(+), 97 deletions(-) create mode 100644 dspace-api/src/test/java/org/dspace/app/util/SubmissionConfigIT.java diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java index 7342cc4283fe..70c5092602a3 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java +++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java @@ -11,6 +11,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -154,7 +155,7 @@ public void reload() throws SubmissionConfigReaderException { private void buildInputs(String fileName) throws SubmissionConfigReaderException { collectionToSubmissionConfig = new HashMap(); entityTypeToSubmissionConfig = new HashMap(); - submitDefns = new HashMap>>(); + submitDefns = new LinkedHashMap>>(); String uri = "file:" + new File(fileName).getAbsolutePath(); diff --git a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml index 452460501a54..2b4cee044916 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml @@ -24,6 +24,8 @@ + + @@ -257,6 +259,14 @@ + + + + + + + + diff --git a/dspace-api/src/test/java/org/dspace/app/util/SubmissionConfigIT.java b/dspace-api/src/test/java/org/dspace/app/util/SubmissionConfigIT.java new file mode 100644 index 000000000000..f171c45328a7 --- /dev/null +++ b/dspace-api/src/test/java/org/dspace/app/util/SubmissionConfigIT.java @@ -0,0 +1,60 @@ +/** + * 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.util; + +import static org.junit.Assert.assertEquals; + +import org.dspace.AbstractIntegrationTestWithDatabase; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.submit.factory.SubmissionServiceFactory; +import org.dspace.submit.service.SubmissionConfigService; +import org.junit.Test; + +/** + * Integration Tests for parsing and utilities on submission config forms / readers + * + * @author Toni Prieto + */ +public class SubmissionConfigIT extends AbstractIntegrationTestWithDatabase { + + @Test + public void testSubmissionConfigMapByCollectionOrEntityType() + throws SubmissionConfigReaderException { + + context.turnOffAuthorisationSystem(); + // Sep up a structure with one top community and two collections + Community topcom = CommunityBuilder.createCommunity(context, "123456789/topcommunity-test") + .withName("Parent Community") + .build(); + // col1 should use the item submission form directly mapped for this collection + Collection col1 = CollectionBuilder.createCollection(context, topcom, "123456789/collection-test") + .withName("Collection 1") + .withEntityType("CustomEntityType") + .build(); + // col2 should use the item submission form mapped for the entity type CustomEntityType + Collection col2 = CollectionBuilder.createCollection(context, topcom, "123456789/not-mapped1") + .withName("Collection 2") + .withEntityType("CustomEntityType") + .build(); + context.restoreAuthSystemState(); + + SubmissionConfigService submissionConfigService = SubmissionServiceFactory.getInstance() + .getSubmissionConfigService(); + + // for col1, it should return the item submission form defined directly for the collection + SubmissionConfig submissionConfig1 = submissionConfigService.getSubmissionConfigByCollection(col1); + assertEquals("collectiontest", submissionConfig1.getSubmissionName()); + + // for col2, it should return the item submission form defined for the entitytype CustomEntityType + SubmissionConfig submissionConfig2 = submissionConfigService.getSubmissionConfigByCollection(col2); + assertEquals("entitytypetest", submissionConfig2.getSubmissionName()); + } +} \ No newline at end of file diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java index babb1fac2326..1a1a4576dc89 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java @@ -32,6 +32,11 @@ */ public class SubmissionDefinitionsControllerIT extends AbstractControllerIntegrationTest { + // The total number of expected submission definitions is referred to in multiple tests and assertions as + // is the last page (totalDefinitions - 1) + // This integer should be maintained along with any changes to item-submissions.xml + private static final int totalDefinitions = 9; + @Test public void findAll() throws Exception { //When we call the root endpoint as anonymous user @@ -243,110 +248,110 @@ public void findAllPaginationTest() throws Exception { getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") .param("size", "1") .param("page", "0")) - .andExpect(status().isOk()) - .andExpect(content().contentType(contentType)) - .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("traditional"))) - .andExpect(jsonPath("$._links.first.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=0"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.self.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=0"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.next.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=1"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.last.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=6"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$.page.size", is(1))) - .andExpect(jsonPath("$.page.totalElements", is(7))) - .andExpect(jsonPath("$.page.totalPages", is(7))) - .andExpect(jsonPath("$.page.number", is(0))); + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("traditional"))) + .andExpect(jsonPath("$._links.first.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.self.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.next.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=1"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) + .andExpect(jsonPath("$.page.number", is(0))); getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") .param("size", "1") .param("page", "1")) - .andExpect(status().isOk()) - .andExpect(content().contentType(contentType)) - .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("test-hidden"))) - .andExpect(jsonPath("$._links.first.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=0"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=0"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.next.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=2"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.self.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=1"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.last.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page="), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$.page.size", is(1))) - .andExpect(jsonPath("$.page.totalElements", is(7))) - .andExpect(jsonPath("$.page.totalPages", is(7))) - .andExpect(jsonPath("$.page.number", is(1))); + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("languagetestprocess"))) + .andExpect(jsonPath("$._links.first.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.next.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=2"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.self.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=1"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) + .andExpect(jsonPath("$.page.number", is(1))); getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") .param("size", "1") .param("page", "2")) - .andExpect(status().isOk()) - .andExpect(content().contentType(contentType)) - .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("accessConditionNotDiscoverable"))) - .andExpect(jsonPath("$._links.first.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=0"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=1"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.next.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=3"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.self.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=2"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.last.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=6"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$.page.size", is(1))) - .andExpect(jsonPath("$.page.totalElements", is(7))) - .andExpect(jsonPath("$.page.totalPages", is(7))) - .andExpect(jsonPath("$.page.number", is(2))); + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("extractiontestprocess"))) + .andExpect(jsonPath("$._links.first.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=1"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.next.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=3"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.self.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=2"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) + .andExpect(jsonPath("$.page.number", is(2))); getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") .param("size", "1") .param("page", "3")) - .andExpect(status().isOk()) - .andExpect(content().contentType(contentType)) - .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("languagetestprocess"))) - .andExpect(jsonPath("$._links.first.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=0"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=2"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.next.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=4"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.self.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=3"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$._links.last.href", Matchers.allOf( - Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=6"), Matchers.containsString("size=1")))) - .andExpect(jsonPath("$.page.size", is(1))) - .andExpect(jsonPath("$.page.totalElements", is(7))) - .andExpect(jsonPath("$.page.totalPages", is(7))) - .andExpect(jsonPath("$.page.number", is(3))); + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("qualdroptest"))) + .andExpect(jsonPath("$._links.first.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=2"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.next.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=4"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.self.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=3"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) + .andExpect(jsonPath("$.page.number", is(3))); getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") - .param("size", "1") - .param("page", "4")) + .param("size", "1") + .param("page", "4")) .andExpect(status().isOk()) .andExpect(content().contentType(contentType)) - .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("qualdroptest"))) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("typebindtest"))) .andExpect(jsonPath("$._links.first.href", Matchers.allOf( Matchers.containsString("/api/config/submissiondefinitions?"), Matchers.containsString("page=0"), Matchers.containsString("size=1")))) @@ -361,18 +366,18 @@ public void findAllPaginationTest() throws Exception { Matchers.containsString("page=4"), Matchers.containsString("size=1")))) .andExpect(jsonPath("$._links.last.href", Matchers.allOf( Matchers.containsString("/api/config/submissiondefinitions?"), - Matchers.containsString("page=6"), Matchers.containsString("size=1")))) + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) .andExpect(jsonPath("$.page.size", is(1))) - .andExpect(jsonPath("$.page.totalElements", is(7))) - .andExpect(jsonPath("$.page.totalPages", is(7))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) .andExpect(jsonPath("$.page.number", is(4))); getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") - .param("size", "1") - .param("page", "5")) + .param("size", "1") + .param("page", "5")) .andExpect(status().isOk()) .andExpect(content().contentType(contentType)) - .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("extractiontestprocess"))) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("accessConditionNotDiscoverable"))) .andExpect(jsonPath("$._links.first.href", Matchers.allOf( Matchers.containsString("/api/config/submissiondefinitions?"), Matchers.containsString("page=0"), Matchers.containsString("size=1")))) @@ -386,12 +391,114 @@ public void findAllPaginationTest() throws Exception { Matchers.containsString("/api/config/submissiondefinitions?"), Matchers.containsString("page=5"), Matchers.containsString("size=1")))) .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) + .andExpect(jsonPath("$.page.number", is(5))); + + getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") + .param("size", "1") + .param("page", "5")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("accessConditionNotDiscoverable"))) + .andExpect(jsonPath("$._links.first.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=4"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.next.href", Matchers.allOf( Matchers.containsString("/api/config/submissiondefinitions?"), Matchers.containsString("page=6"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.self.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=5"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) .andExpect(jsonPath("$.page.size", is(1))) - .andExpect(jsonPath("$.page.totalElements", is(7))) - .andExpect(jsonPath("$.page.totalPages", is(7))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) .andExpect(jsonPath("$.page.number", is(5))); + + getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") + .param("size", "1") + .param("page", "6")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("test-hidden"))) + .andExpect(jsonPath("$._links.first.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=5"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.next.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=7"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.self.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=6"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) + .andExpect(jsonPath("$.page.number", is(6))); + + getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") + .param("size", "1") + .param("page", "7")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("collectiontest"))) + .andExpect(jsonPath("$._links.first.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=6"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.next.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=8"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.self.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=7"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) + .andExpect(jsonPath("$.page.number", is(7))); + + getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions") + .param("size", "1") + .param("page", "8")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("entitytypetest"))) + .andExpect(jsonPath("$._links.first.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=0"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.prev.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=7"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.self.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=8"), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$._links.last.href", Matchers.allOf( + Matchers.containsString("/api/config/submissiondefinitions?"), + Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1")))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(totalDefinitions))) + .andExpect(jsonPath("$.page.totalPages", is(totalDefinitions))) + .andExpect(jsonPath("$.page.number", is(8))); + } } From d5e2c71da40ae60c578557dda697b5d2824a5141 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 22 Apr 2024 10:42:21 -0500 Subject: [PATCH 129/230] Minor fixes to Entities import. MUST run "ignored" migrations. Also modifying submission configs no longer needed --- .../src/main/docker-compose/db.entities.yml | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/dspace/src/main/docker-compose/db.entities.yml b/dspace/src/main/docker-compose/db.entities.yml index 32c54a5d0bd1..809cf52df0b6 100644 --- a/dspace/src/main/docker-compose/db.entities.yml +++ b/dspace/src/main/docker-compose/db.entities.yml @@ -18,27 +18,12 @@ services: ### OVERRIDE default 'entrypoint' in 'docker-compose.yml #### # Ensure that the database is ready BEFORE starting tomcat # 1. While a TCP connection to dspacedb port 5432 is not available, continue to sleep - # 2. Then, run database migration to init database tables - # 3. (Custom for Entities) enable Entity-specific collection submission mappings in item-submission.xml - # This 'sed' command inserts the sample configurations specific to the Entities data set, see: - # https://github.com/DSpace/DSpace/blob/main/dspace/config/item-submission.xml#L36-L49 - # 4. Finally, start Tomcat + # 2. Then, run migration latest version of database tables (run with "ignored" in case this SQL data is outdated) + # 3. Finally, start Tomcat entrypoint: - /bin/bash - '-c' - | while (! /dev/null 2>&1; do sleep 1; done; - /dspace/bin/dspace database migrate - sed -i '/name-map collection-handle="default".*/a \\n \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - ' /dspace/config/item-submission.xml + /dspace/bin/dspace database migrate ignored catalina.sh run From 69f7f85defd40d1d97a48d0a4a27ccee6de91bfb Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 22 Apr 2024 10:43:06 -0500 Subject: [PATCH 130/230] Minor fixes to DB scripts. Use Postgres 15. Don't error out if pgcrypto already installed. --- .../src/main/docker/dspace-postgres-pgcrypto-curl/Dockerfile | 2 +- .../docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh | 4 ++-- dspace/src/main/docker/dspace-postgres-pgcrypto/Dockerfile | 2 +- .../main/docker/dspace-postgres-pgcrypto/install-pgcrypto.sh | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/Dockerfile b/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/Dockerfile index b2131a740262..aabf87df3eda 100644 --- a/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/Dockerfile +++ b/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/Dockerfile @@ -10,7 +10,7 @@ # docker build --build-arg POSTGRES_VERSION=13 --build-arg POSTGRES_PASSWORD=mypass ./dspace/src/main/docker/dspace-postgres-pgcrypto-curl/ # This will be published as dspace/dspace-postgres-pgcrypto:$DSPACE_VERSION-loadsql -ARG POSTGRES_VERSION=13 +ARG POSTGRES_VERSION=15 ARG POSTGRES_PASSWORD=dspace FROM postgres:${POSTGRES_VERSION} diff --git a/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh b/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh index 3f8e95e1044f..ff042ec1bba8 100644 --- a/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh +++ b/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh @@ -40,9 +40,9 @@ fi # Then, setup pgcrypto on this database psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL -- Create a new schema in this database named "extensions" (or whatever you want to name it) - CREATE SCHEMA extensions; + CREATE SCHEMA IF NOT EXISTS extensions; -- Enable this extension in this new schema - CREATE EXTENSION pgcrypto SCHEMA extensions; + CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA extensions; -- Update your database's "search_path" to also search the new "extensions" schema. -- You are just appending it on the end of the existing comma-separated list. ALTER DATABASE dspace SET search_path TO "\$user",public,extensions; diff --git a/dspace/src/main/docker/dspace-postgres-pgcrypto/Dockerfile b/dspace/src/main/docker/dspace-postgres-pgcrypto/Dockerfile index 7dde1a6bfd1c..2298cd4e76ea 100644 --- a/dspace/src/main/docker/dspace-postgres-pgcrypto/Dockerfile +++ b/dspace/src/main/docker/dspace-postgres-pgcrypto/Dockerfile @@ -10,7 +10,7 @@ # docker build --build-arg POSTGRES_VERSION=13 --build-arg POSTGRES_PASSWORD=mypass ./dspace/src/main/docker/dspace-postgres-pgcrypto/ # This will be published as dspace/dspace-postgres-pgcrypto:$DSPACE_VERSION -ARG POSTGRES_VERSION=13 +ARG POSTGRES_VERSION=15 ARG POSTGRES_PASSWORD=dspace FROM postgres:${POSTGRES_VERSION} diff --git a/dspace/src/main/docker/dspace-postgres-pgcrypto/install-pgcrypto.sh b/dspace/src/main/docker/dspace-postgres-pgcrypto/install-pgcrypto.sh index 65405aa7bdb6..67c4539b5a46 100644 --- a/dspace/src/main/docker/dspace-postgres-pgcrypto/install-pgcrypto.sh +++ b/dspace/src/main/docker/dspace-postgres-pgcrypto/install-pgcrypto.sh @@ -11,9 +11,9 @@ set -e psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL -- Create a new schema in this database named "extensions" (or whatever you want to name it) - CREATE SCHEMA extensions; + CREATE SCHEMA IF NOT EXISTS extensions; -- Enable this extension in this new schema - CREATE EXTENSION pgcrypto SCHEMA extensions; + CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA extensions; -- Update your database's "search_path" to also search the new "extensions" schema. -- You are just appending it on the end of the existing comma-separated list. ALTER DATABASE dspace SET search_path TO "\$user",public,extensions; From b1fb884aec4f407be205ceaf90416f6e8497d2da Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 22 Apr 2024 14:15:13 -0500 Subject: [PATCH 131/230] Remove unnecessary "exit" statements which stop running container (cherry picked from commit 11158ae525a68be445099072168c324197697b96) --- .../docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh b/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh index ff042ec1bba8..d8e0382010df 100644 --- a/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh +++ b/dspace/src/main/docker/dspace-postgres-pgcrypto-curl/install-pgcrypto.sh @@ -23,7 +23,6 @@ then rm /tmp/dspace-db-init.sql touch $CHECKFILE - exit fi # If $LOCALSQL environment variable set, then simply run it in PostgreSQL @@ -34,7 +33,6 @@ then psql -U $POSTGRES_USER < ${LOCALSQL} touch $CHECKFILE - exit fi # Then, setup pgcrypto on this database From 362c80136bfde04e3801796afd2d7e3d8485d392 Mon Sep 17 00:00:00 2001 From: Thomas Misilo Date: Sat, 9 Mar 2024 13:48:42 -0600 Subject: [PATCH 132/230] Change from openjdk to eclipse-temurin base images Since the opendjk image has been deprecated, it was suggested to change to eclipse-temurin Fixes #9277 (cherry picked from commit 86ca5aabf9ab71b3041562f0ac600f872ccd443f) --- Dockerfile | 2 +- Dockerfile.cli | 4 ++-- Dockerfile.dependencies | 2 +- Dockerfile.test | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3c536b317629..ee48dec5083c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,7 +28,7 @@ RUN mvn --no-transfer-progress package ${MAVEN_FLAGS} && \ mvn clean # Step 2 - Run Ant Deploy -FROM openjdk:${JDK_VERSION}-slim as ant_build +FROM eclipse-temurin:${JDK_VERSION} as ant_build ARG TARGET_DIR=dspace-installer # COPY the /install directory from 'build' container to /dspace-src in this container COPY --from=build /install /dspace-src diff --git a/Dockerfile.cli b/Dockerfile.cli index 62e83b79ef02..96a84bc56268 100644 --- a/Dockerfile.cli +++ b/Dockerfile.cli @@ -24,7 +24,7 @@ RUN mvn --no-transfer-progress package && \ mvn clean # Step 2 - Run Ant Deploy -FROM openjdk:${JDK_VERSION}-slim as ant_build +FROM eclipse-temurin:${JDK_VERSION} as ant_build ARG TARGET_DIR=dspace-installer # COPY the /install directory from 'build' container to /dspace-src in this container COPY --from=build /install /dspace-src @@ -45,7 +45,7 @@ RUN mkdir $ANT_HOME && \ RUN ant init_installation update_configs update_code # Step 3 - Run jdk -FROM openjdk:${JDK_VERSION} +FROM eclipse-temurin:${JDK_VERSION} # NOTE: DSPACE_INSTALL must align with the "dspace.dir" default configuration. ENV DSPACE_INSTALL=/dspace # Copy the /dspace directory from 'ant_build' container to /dspace in this container diff --git a/Dockerfile.dependencies b/Dockerfile.dependencies index 6f72ab058536..1400b356d418 100644 --- a/Dockerfile.dependencies +++ b/Dockerfile.dependencies @@ -7,7 +7,7 @@ ARG JDK_VERSION=11 # Step 1 - Run Maven Build -FROM maven:3-openjdk-${JDK_VERSION}-slim as build +FROM maven:3-eclipse-temurin-${JDK_VERSION} as build ARG TARGET_DIR=dspace-installer WORKDIR /app # Create the 'dspace' user account & home directory diff --git a/Dockerfile.test b/Dockerfile.test index 4e9b2b5b4343..f6f8c1a290f9 100644 --- a/Dockerfile.test +++ b/Dockerfile.test @@ -27,7 +27,7 @@ RUN mvn --no-transfer-progress package -Pdspace-rest && \ mvn clean # Step 2 - Run Ant Deploy -FROM openjdk:${JDK_VERSION}-slim as ant_build +FROM eclipse-temurin:${JDK_VERSION} as ant_build ARG TARGET_DIR=dspace-installer # COPY the /install directory from 'build' container to /dspace-src in this container COPY --from=build /install /dspace-src From 1cfa041a315d023a9ded6766571d4e8dc0280b2f Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Fri, 26 Apr 2024 10:07:10 +0200 Subject: [PATCH 133/230] Remove unused function findAllCollectionsByEntityType of CollectionService --- .../dspace/content/CollectionServiceImpl.java | 20 ------------------- .../content/service/CollectionService.java | 15 -------------- 2 files changed, 35 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java index 0d9507e3aa35..a0ac5b1c639a 100644 --- a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java @@ -1054,26 +1054,6 @@ public int countCollectionsWithSubmit(String q, Context context, Community commu return (int) resp.getTotalSearchResults(); } - @Override - @SuppressWarnings("rawtypes") - public List findAllCollectionsByEntityType(Context context, String entityType) - throws SearchServiceException { - List collectionList = new ArrayList<>(); - - DiscoverQuery discoverQuery = new DiscoverQuery(); - discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE); - discoverQuery.addFilterQueries("dspace.entity.type:" + entityType); - - DiscoverResult discoverResult = searchService.search(context, discoverQuery); - List solrIndexableObjects = discoverResult.getIndexableObjects(); - - for (IndexableObject solrCollection : solrIndexableObjects) { - Collection c = ((IndexableCollection) solrCollection).getIndexedObject(); - collectionList.add(c); - } - return collectionList; - } - /** * Returns total collection archived items * diff --git a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java index 90db5c731402..b923549b1998 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java @@ -456,21 +456,6 @@ public int countCollectionsWithSubmit(String q, Context context, Community commu public int countCollectionsWithSubmit(String q, Context context, Community community, String entityType) throws SQLException, SearchServiceException; - /** - * Returns a list of all collections for a specific entity type. - * NOTE: for better performance, this method retrieves its results from an index (cache) - * and does not query the database directly. - * This means that results may be stale or outdated until - * https://github.com/DSpace/DSpace/issues/2853 is resolved." - * - * @param context DSpace Context - * @param entityType limit the returned collection to those related to given entity type - * @return list of collections found - * @throws SearchServiceException if search error - */ - public List findAllCollectionsByEntityType(Context context, String entityType) - throws SearchServiceException; - /** * Returns total collection archived items * From 10aa3189198e3c6023625acb8b94037239d5cc51 Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Fri, 26 Apr 2024 14:48:08 +0200 Subject: [PATCH 134/230] Add comment to clarify in which use case the consumer submissionconfig is useful --- dspace/config/dspace.cfg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index 60a7506d8766..0b7cd6ee44ae 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -823,6 +823,11 @@ event.consumer.orcidqueue.class = org.dspace.orcid.consumer.OrcidQueueConsumer event.consumer.orcidqueue.filters = Item+Install|Modify|Modify_Metadata|Delete|Remove # item submission config reload consumer +# This consumer can be useful for reloading changes made in the item-submission.xml config file, +# without restarting Tomcat, primarily for adding new collection mappings. +# With this consumer, configuration reloading is triggered after a collection is updated. +# It is disabled by default. To enable it, add 'submissionconfig' to the list of +# activated consumers (event.dispatcher.default.consumers). event.consumer.submissionconfig.class = org.dspace.submit.consumer.SubmissionConfigConsumer event.consumer.submissionconfig.filters = Collection+Modify_Metadata From 9d12600d13c6f5783d2c9afc2902ff448aaac8e8 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Tue, 18 Apr 2023 15:47:14 +0200 Subject: [PATCH 135/230] [Ticket 2124] Slow response times --- .../authorization/impl/DeleteFeature.java | 6 +- .../converter/AInprogressItemConverter.java | 10 +- .../rest/model/AInprogressSubmissionRest.java | 29 +-- .../app/rest/model/WorkflowItemRest.java | 25 +- .../app/rest/model/WorkspaceItemRest.java | 15 ++ .../WorkflowItemCollectionLinkRepository.java | 60 +++++ .../WorkflowItemItemLinkRepository.java | 60 +++++ .../WorkflowItemSubmitterLinkRepository.java | 60 +++++ ...WorkspaceItemCollectionLinkRepository.java | 60 +++++ .../WorkspaceItemItemLinkRepository.java | 60 +++++ .../WorkspaceItemSubmitterLinkRepository.java | 60 +++++ .../jwt/ShortLivedJWTTokenHandler.java | 1 - .../WorkflowItemRestLinkRepositoryIT.java | 226 ++++++++++++++++++ .../WorkspaceItemRestLinkRepositoryIT.java | 222 +++++++++++++++++ 14 files changed, 854 insertions(+), 40 deletions(-) create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemCollectionLinkRepository.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemItemLinkRepository.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemSubmitterLinkRepository.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemCollectionLinkRepository.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemItemLinkRepository.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemSubmitterLinkRepository.java create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkflowItemRestLinkRepositoryIT.java create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestLinkRepositoryIT.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DeleteFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DeleteFeature.java index 02ca816290d0..0f5378125d8f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DeleteFeature.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DeleteFeature.java @@ -65,11 +65,13 @@ public class DeleteFeature implements AuthorizationFeature { @Override public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException { if (object instanceof BaseObjectRest) { + DSpaceObject dSpaceObject = (DSpaceObject) utils.getDSpaceAPIObjectFromRest(context, object); + if (object.getType().equals(WorkspaceItemRest.NAME)) { - object = ((WorkspaceItemRest)object).getItem(); + WorkspaceItem workspaceItem = (WorkspaceItem) utils.getDSpaceAPIObjectFromRest(context, object); + dSpaceObject = workspaceItem.getItem(); } - DSpaceObject dSpaceObject = (DSpaceObject) utils.getDSpaceAPIObjectFromRest(context, object); DSpaceObject parentObject = getParentObject(context, dSpaceObject); switch (object.getType()) { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java index a5431d90004f..f40022f19f79 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java @@ -70,11 +70,11 @@ protected void fillFromModel(T obj, R witem, Projection projection) { submitter = obj.getSubmitter(); witem.setId(obj.getID()); - witem.setCollection(collection != null ? converter.toRest(collection, projection) : null); - witem.setItem(converter.toRest(item, projection)); - if (submitter != null) { - witem.setSubmitter(converter.toRest(submitter, projection)); - } +// witem.setCollection(collection != null ? converter.toRest(collection, projection) : null); +// witem.setItem(converter.toRest(item, projection)); +// if (submitter != null) { +// witem.setSubmitter(converter.toRest(submitter, projection)); +// } // 1. retrieve the submission definition // 2. iterate over the submission section to allow to plugin additional diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/AInprogressSubmissionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/AInprogressSubmissionRest.java index 903e2866c855..79cf007ba190 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/AInprogressSubmissionRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/AInprogressSubmissionRest.java @@ -22,16 +22,11 @@ */ public abstract class AInprogressSubmissionRest extends BaseObjectRest { + private Date lastModified = new Date(); private Map sections; @JsonIgnore - private CollectionRest collection; - @JsonIgnore - private ItemRest item; - @JsonIgnore private SubmissionDefinitionRest submissionDefinition; - @JsonIgnore - private EPersonRest submitter; public Date getLastModified() { return lastModified; @@ -41,14 +36,6 @@ public void setLastModified(Date lastModified) { this.lastModified = lastModified; } - public ItemRest getItem() { - return item; - } - - public void setItem(ItemRest item) { - this.item = item; - } - public SubmissionDefinitionRest getSubmissionDefinition() { return submissionDefinition; } @@ -57,14 +44,6 @@ public void setSubmissionDefinition(SubmissionDefinitionRest submissionDefinitio this.submissionDefinition = submissionDefinition; } - public EPersonRest getSubmitter() { - return submitter; - } - - public void setSubmitter(EPersonRest submitter) { - this.submitter = submitter; - } - public Map getSections() { if (sections == null) { sections = new HashMap(); @@ -76,12 +55,6 @@ public void setSections(Map sections) { this.sections = sections; } - public CollectionRest getCollection() { - return collection; - } - public void setCollection(CollectionRest collection) { - this.collection = collection; - } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkflowItemRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkflowItemRest.java index 8f580f441477..4a840a0bb77b 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkflowItemRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkflowItemRest.java @@ -15,10 +15,22 @@ * @author Andrea Bollini (andrea.bollini at 4science.it) */ @LinksRest(links = { - @LinkRest( - name = WorkflowItemRest.STEP, - method = "getStep" - ) + @LinkRest( + name = WorkflowItemRest.STEP, + method = "getStep" + ), + @LinkRest( + name = WorkflowItemRest.SUBMITTER, + method = "getWorkflowItemSubmitter" + ), + @LinkRest( + name = WorkflowItemRest.ITEM, + method = "getWorkflowItemItem" + ), + @LinkRest( + name = WorkflowItemRest.COLLECTION, + method = "getWorkflowItemCollection" + ) }) public class WorkflowItemRest extends AInprogressSubmissionRest { public static final String NAME = "workflowitem"; @@ -26,6 +38,11 @@ public class WorkflowItemRest extends AInprogressSubmissionRest { public static final String STEP = "step"; + public static final String SUBMITTER = "submitter"; + public static final String ITEM = "item"; + public static final String COLLECTION = "collection"; + + @Override public String getCategory() { return CATEGORY; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkspaceItemRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkspaceItemRest.java index 57a5ab5c7f0e..b40d1a4494f4 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkspaceItemRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkspaceItemRest.java @@ -18,6 +18,18 @@ @LinkRest( name = WorkspaceItemRest.SUPERVISION_ORDERS, method = "getSupervisionOrders" + ), + @LinkRest( + name = WorkspaceItemRest.SUBMITTER, + method = "getWorkspaceItemSubmitter" + ), + @LinkRest( + name = WorkspaceItemRest.ITEM, + method = "getWorkspaceItemItem" + ), + @LinkRest( + name = WorkspaceItemRest.COLLECTION, + method = "getWorkspaceItemCollection" ) }) public class WorkspaceItemRest extends AInprogressSubmissionRest { @@ -25,6 +37,9 @@ public class WorkspaceItemRest extends AInprogressSubmissionRest { public static final String CATEGORY = RestAddressableModel.SUBMISSION; public static final String SUPERVISION_ORDERS = "supervisionOrders"; + public static final String SUBMITTER = "submitter"; + public static final String ITEM = "item"; + public static final String COLLECTION = "collection"; @Override public String getCategory() { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemCollectionLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemCollectionLinkRepository.java new file mode 100644 index 000000000000..fa92a69e77d6 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemCollectionLinkRepository.java @@ -0,0 +1,60 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.sql.SQLException; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.app.rest.model.CollectionRest; +import org.dspace.app.rest.model.WorkflowItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.core.Context; +import org.dspace.workflow.WorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +/** + * Link repository for "collection" subresource of a workflow item. + */ +@Component(WorkflowItemRest.CATEGORY + "." + WorkflowItemRest.NAME + "." + WorkflowItemRest.COLLECTION) +public class WorkflowItemCollectionLinkRepository extends AbstractDSpaceRestRepository + implements LinkRestRepository { + + @Autowired + XmlWorkflowItemService wis; + + /** + * Retrieve the item for a workflow collection. + * + * @param request - The current request + * @param id - The workflow item ID for which to retrieve the collection + * @param optionalPageable - optional pageable object + * @param projection - the current projection + * @return the item for the workflow collection + */ + @PreAuthorize("hasPermission(#id, 'WORKFLOWITEM', 'READ')") + public CollectionRest getWorkflowItemCollection(@Nullable HttpServletRequest request, Integer id, + @Nullable Pageable optionalPageable, Projection projection) { + try { + Context context = obtainContext(); + WorkflowItem witem = wis.find(context, id); + if (witem == null) { + throw new ResourceNotFoundException("No such workflow item: " + id); + } + + return converter.toRest(witem.getCollection(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemItemLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemItemLinkRepository.java new file mode 100644 index 000000000000..40624799bff4 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemItemLinkRepository.java @@ -0,0 +1,60 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.sql.SQLException; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.model.WorkflowItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.core.Context; +import org.dspace.workflow.WorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +/** + * Link repository for "item" subresource of a workflow item. + */ +@Component(WorkflowItemRest.CATEGORY + "." + WorkflowItemRest.NAME + "." + WorkflowItemRest.ITEM) +public class WorkflowItemItemLinkRepository extends AbstractDSpaceRestRepository + implements LinkRestRepository { + + @Autowired + XmlWorkflowItemService wis; + + /** + * Retrieve the item for a workflow item. + * + * @param request - The current request + * @param id - The workflow item ID for which to retrieve the item + * @param optionalPageable - optional pageable object + * @param projection - the current projection + * @return the item for the workflow item + */ + @PreAuthorize("hasPermission(#id, 'WORKFLOWITEM', 'READ')") + public ItemRest getWorkflowItemItem(@Nullable HttpServletRequest request, Integer id, + @Nullable Pageable optionalPageable, Projection projection) { + try { + Context context = obtainContext(); + WorkflowItem witem = wis.find(context, id); + if (witem == null) { + throw new ResourceNotFoundException("No such workflow item: " + id); + } + + return converter.toRest(witem.getItem(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemSubmitterLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemSubmitterLinkRepository.java new file mode 100644 index 000000000000..b4b0ec0adfff --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemSubmitterLinkRepository.java @@ -0,0 +1,60 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.sql.SQLException; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.app.rest.model.EPersonRest; +import org.dspace.app.rest.model.WorkflowItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.core.Context; +import org.dspace.workflow.WorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +/** + * Link repository for "submitter" subresource of a workflow item. + */ +@Component(WorkflowItemRest.CATEGORY + "." + WorkflowItemRest.NAME + "." + WorkflowItemRest.SUBMITTER) +public class WorkflowItemSubmitterLinkRepository extends AbstractDSpaceRestRepository + implements LinkRestRepository { + + @Autowired + XmlWorkflowItemService wis; + + /** + * Retrieve the submitter for a workflow item. + * + * @param request - The current request + * @param id - The workflow item ID for which to retrieve the submitter + * @param optionalPageable - optional pageable object + * @param projection - the current projection + * @return the submitter for the workflow item + */ + @PreAuthorize("hasPermission(#id, 'WORKFLOWITEM', 'READ')") + public EPersonRest getWorkflowItemSubmitter(@Nullable HttpServletRequest request, Integer id, + @Nullable Pageable optionalPageable, Projection projection) { + try { + Context context = obtainContext(); + WorkflowItem witem = wis.find(context, id); + if (witem == null) { + throw new ResourceNotFoundException("No such workflow item: " + id); + } + + return converter.toRest(witem.getSubmitter(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemCollectionLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemCollectionLinkRepository.java new file mode 100644 index 000000000000..c8f9373b07c7 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemCollectionLinkRepository.java @@ -0,0 +1,60 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.sql.SQLException; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.app.rest.model.CollectionRest; +import org.dspace.app.rest.model.WorkspaceItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.content.WorkspaceItem; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +/** + * Link repository for "collection" subresource of a workspace item. + */ +@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME + "." + WorkspaceItemRest.COLLECTION) +public class WorkspaceItemCollectionLinkRepository extends AbstractDSpaceRestRepository + implements LinkRestRepository { + + @Autowired + WorkspaceItemService wis; + + /** + * Retrieve the collection for a workspace item. + * + * @param request - The current request + * @param id - The workspace item ID for which to retrieve the collection + * @param optionalPageable - optional pageable object + * @param projection - the current projection + * @return the collection for the workspace item + */ + @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'READ')") + public CollectionRest getWorkspaceItemCollection(@Nullable HttpServletRequest request, Integer id, + @Nullable Pageable optionalPageable, Projection projection) { + try { + Context context = obtainContext(); + WorkspaceItem witem = wis.find(context, id); + if (witem == null) { + throw new ResourceNotFoundException("No such workspace item: " + id); + } + + return converter.toRest(witem.getCollection(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemItemLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemItemLinkRepository.java new file mode 100644 index 000000000000..48052fe5371f --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemItemLinkRepository.java @@ -0,0 +1,60 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.sql.SQLException; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.model.WorkspaceItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.content.WorkspaceItem; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +/** + * Link repository for "item" subresource of a workspace item. + */ +@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME + "." + WorkspaceItemRest.ITEM) +public class WorkspaceItemItemLinkRepository extends AbstractDSpaceRestRepository + implements LinkRestRepository { + + @Autowired + WorkspaceItemService wis; + + /** + * Retrieve the item for a workspace item. + * + * @param request - The current request + * @param id - The workspace item ID for which to retrieve the item + * @param optionalPageable - optional pageable object + * @param projection - the current projection + * @return the item for the workspace item + */ + @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'READ')") + public ItemRest getWorkspaceItemItem(@Nullable HttpServletRequest request, Integer id, + @Nullable Pageable optionalPageable, Projection projection) { + try { + Context context = obtainContext(); + WorkspaceItem witem = wis.find(context, id); + if (witem == null) { + throw new ResourceNotFoundException("No such workspace item: " + id); + } + + return converter.toRest(witem.getItem(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemSubmitterLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemSubmitterLinkRepository.java new file mode 100644 index 000000000000..a98de6a0b3ac --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemSubmitterLinkRepository.java @@ -0,0 +1,60 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.sql.SQLException; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.app.rest.model.EPersonRest; +import org.dspace.app.rest.model.WorkspaceItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.content.WorkspaceItem; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +/** + * Link repository for "submitter" subresource of a workspace item. + */ +@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME + "." + WorkspaceItemRest.SUBMITTER) +public class WorkspaceItemSubmitterLinkRepository extends AbstractDSpaceRestRepository + implements LinkRestRepository { + + @Autowired + WorkspaceItemService wis; + + /** + * Retrieve the submitter for a workspace item. + * + * @param request - The current request + * @param id - The workspace item ID for which to retrieve the submitter + * @param optionalPageable - optional pageable object + * @param projection - the current projection + * @return the submitter for the workspace item + */ + @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'READ')") + public EPersonRest getWorkspaceItemSubmitter(@Nullable HttpServletRequest request, Integer id, + @Nullable Pageable optionalPageable, Projection projection) { + try { + Context context = obtainContext(); + WorkspaceItem witem = wis.find(context, id); + if (witem == null) { + throw new ResourceNotFoundException("No such workspace item: " + id); + } + + return converter.toRest(witem.getSubmitter(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/jwt/ShortLivedJWTTokenHandler.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/jwt/ShortLivedJWTTokenHandler.java index fc4ab39407a4..72c305b5d12e 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/jwt/ShortLivedJWTTokenHandler.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/jwt/ShortLivedJWTTokenHandler.java @@ -16,7 +16,6 @@ import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import com.nimbusds.jwt.util.DateUtils; -import org.apache.commons.lang3.StringUtils; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.springframework.stereotype.Component; diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkflowItemRestLinkRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkflowItemRestLinkRepositoryIT.java new file mode 100644 index 000000000000..7228a7ba0b9d --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkflowItemRestLinkRepositoryIT.java @@ -0,0 +1,226 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.jayway.jsonpath.matchers.JsonPathMatchers; +import org.dspace.app.rest.matcher.CollectionMatcher; +import org.dspace.app.rest.matcher.EPersonMatcher; +import org.dspace.app.rest.matcher.ItemMatcher; +import org.dspace.app.rest.matcher.WorkflowItemMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.EPersonBuilder; +import org.dspace.builder.WorkflowItemBuilder; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.eperson.EPerson; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Test suite for the WorkflowItem Link repositories + */ +public class WorkflowItemRestLinkRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + /** + * The workflowitem resource endpoint must have an embeddable submitter + * + * @throws Exception + */ + public void findOneEmbedSubmitterTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@dspace.org") + .withNameInMetadata("Sub", "Mitter") + .build(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1") + .withWorkflowGroup("reviewer", admin) + .build(); + + XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1) + .withSubmitter(submitter) + .withTitle("Workflow Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + String authToken = getAuthToken(admin.getEmail(), password); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID())).andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workflow Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("$._embedded.submitter"))); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID()).param("embed", "submitter")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workflow Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$._embedded.submitter", Matchers.is( + EPersonMatcher.matchEPersonEntry(submitter)))); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID() + "/submitter")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", EPersonMatcher.matchEPersonEntry(submitter))); + + } + + @Test + /** + * The workflowitem resource endpoint must have an embeddable collection + * + * @throws Exception + */ + public void findOneEmbedCollectionTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@dspace.org") + .withNameInMetadata("Sub", "Mitter") + .build(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1") + .withWorkflowGroup("reviewer", admin) + .build(); + + XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1) + .withSubmitter(submitter) + .withTitle("Workflow Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + String authToken = getAuthToken(admin.getEmail(), password); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID())).andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workflow Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("$._embedded.collection"))); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID()).param("embed", "collection")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workflow Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$._embedded.collection", Matchers.is( + CollectionMatcher.matchCollection(col1)))); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID() + "/collection")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", CollectionMatcher.matchCollection(col1))); + + } + + @Test + /** + * The workflowitem resource endpoint must have an embeddable item + * + * @throws Exception + */ + public void findOneEmbedItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@dspace.org") + .withNameInMetadata("Sub", "Mitter") + .build(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1") + .withWorkflowGroup("reviewer", admin) + .build(); + + XmlWorkflowItem witem = WorkflowItemBuilder.createWorkflowItem(context, col1) + .withSubmitter(submitter) + .withTitle("Workflow Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + String authToken = getAuthToken(admin.getEmail(), password); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID())).andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workflow Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("$._embedded.item"))); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID()).param("embed", "item")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkflowItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workflow Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$._embedded.item", Matchers.is( + ItemMatcher.matchItemProperties(witem.getItem())))); + + getClient(authToken).perform(get("/api/workflow/workflowitems/" + witem.getID() + "/item")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", ItemMatcher.matchItemProperties(witem.getItem()))); + + } + + +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestLinkRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestLinkRepositoryIT.java new file mode 100644 index 000000000000..709480e8cd52 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestLinkRepositoryIT.java @@ -0,0 +1,222 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.jayway.jsonpath.matchers.JsonPathMatchers; +import org.dspace.app.rest.matcher.CollectionMatcher; +import org.dspace.app.rest.matcher.EPersonMatcher; +import org.dspace.app.rest.matcher.ItemMatcher; +import org.dspace.app.rest.matcher.WorkspaceItemMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.EPersonBuilder; +import org.dspace.builder.WorkspaceItemBuilder; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.WorkspaceItem; +import org.dspace.eperson.EPerson; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Test suite for the WorkspaceItem Link repositories + */ +public class WorkspaceItemRestLinkRepositoryIT extends AbstractControllerIntegrationTest { + + + @Test + /** + * The workspaceitem resource endpoint must have an embeddable submitter + * + * @throws Exception + */ + public void findOneEmbedSubmitterTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@dspace.org") + .withNameInMetadata("Sub", "Mitter") + .build(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withSubmitter(submitter) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + String authToken = getAuthToken(admin.getEmail(), password); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID())).andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workspace Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("$._embedded.submitter"))); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID()).param("embed", "submitter")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workspace Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$._embedded.submitter", Matchers.is( + EPersonMatcher.matchEPersonEntry(submitter)))); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID() + "/submitter")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", EPersonMatcher.matchEPersonEntry(submitter))); + + } + + @Test + /** + * The workspaceitem resource endpoint must have an embeddable collection + * + * @throws Exception + */ + public void findOneEmbedCollectionTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@dspace.org") + .withNameInMetadata("Sub", "Mitter") + .build(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withSubmitter(submitter) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + String authToken = getAuthToken(admin.getEmail(), password); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID())).andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workspace Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("$._embedded.collection"))); + + getClient(authToken).perform( + get("/api/submission/workspaceitems/" + witem.getID()).param("embed", "collection")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workspace Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$._embedded.collection", Matchers.is( + CollectionMatcher.matchCollection(col1)))); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID() + "/collection")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", CollectionMatcher.matchCollection(col1))); + + } + + @Test + /** + * The workspaceitem resource endpoint must have an embeddable item + * + * @throws Exception + */ + public void findOneEmbedItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("submitter@dspace.org") + .withNameInMetadata("Sub", "Mitter") + .build(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withSubmitter(submitter) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + String authToken = getAuthToken(admin.getEmail(), password); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID())).andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workspace Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$", JsonPathMatchers.hasNoJsonPath("$._embedded.item"))); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID()).param("embed", "item")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workspace Item 1", + "2017-10-17", + "ExtraEntry")))) + .andExpect(jsonPath("$._embedded.item", Matchers.is( + ItemMatcher.matchItemProperties(witem.getItem())))); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + witem.getID() + "/item")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", ItemMatcher.matchItemProperties(witem.getItem()))); + + } + + +} From d139d06c58e95b6585c46987b716c2ecdfbf8d3b Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Mon, 29 Apr 2024 12:58:20 +0200 Subject: [PATCH 136/230] 105866: test fixes --- .../jwt/ShortLivedJWTTokenHandler.java | 1 + .../app/rest/DiscoveryRestControllerIT.java | 18 ------- .../org/dspace/app/rest/LoginAsEPersonIT.java | 4 +- .../rest/WorkspaceItemRestRepositoryIT.java | 53 ++++++++++++++----- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/jwt/ShortLivedJWTTokenHandler.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/jwt/ShortLivedJWTTokenHandler.java index 72c305b5d12e..fc4ab39407a4 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/jwt/ShortLivedJWTTokenHandler.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/jwt/ShortLivedJWTTokenHandler.java @@ -16,6 +16,7 @@ import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import com.nimbusds.jwt.util.DateUtils; +import org.apache.commons.lang3.StringUtils; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.springframework.stereotype.Component; diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java index 80d8ab2df422..cd84567d6493 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java @@ -5822,10 +5822,6 @@ public void discoverSearchPoolTaskObjectsTest() throws Exception { .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( SearchResultMatcher.match("workflow", "pooltask", "pooltasks") ))) - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects",Matchers.contains( - allOf(hasJsonPath("$._embedded.indexableObject._embedded.workflowitem._embedded.item", - is(SearchResultMatcher.matchEmbeddedObjectOnItemName("item", "Mathematical Theory")))) - ))) .andExpect(jsonPath("$._embedded.searchResult.page.totalElements", is(1))); getClient(adminToken).perform(get("/api/discover/search/objects") @@ -5839,12 +5835,6 @@ public void discoverSearchPoolTaskObjectsTest() throws Exception { SearchResultMatcher.match("workflow", "pooltask", "pooltasks"), SearchResultMatcher.match("workflow", "pooltask", "pooltasks") ))) - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects",Matchers.containsInAnyOrder( - allOf(hasJsonPath("$._embedded.indexableObject._embedded.workflowitem._embedded.item", - is(SearchResultMatcher.matchEmbeddedObjectOnItemName("item", "Metaphysics")))), - allOf(hasJsonPath("$._embedded.indexableObject._embedded.workflowitem._embedded.item", - is(SearchResultMatcher.matchEmbeddedObjectOnItemName("item", "Test Metaphysics")))) - ))) .andExpect(jsonPath("$._embedded.searchResult.page.totalElements", is(2))); } @@ -5909,14 +5899,6 @@ public void discoverSearchPoolTaskObjectsEmptyQueryTest() throws Exception { SearchResultMatcher.match("workflow", "pooltask", "pooltasks"), SearchResultMatcher.match("workflow", "pooltask", "pooltasks") ))) - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects",Matchers.containsInAnyOrder( - allOf(hasJsonPath("$._embedded.indexableObject._embedded.workflowitem._embedded.item", - is(SearchResultMatcher.matchEmbeddedObjectOnItemName("item", "Mathematical Theory")))), - allOf(hasJsonPath("$._embedded.indexableObject._embedded.workflowitem._embedded.item", - is(SearchResultMatcher.matchEmbeddedObjectOnItemName("item", "Metaphysics")))), - allOf(hasJsonPath("$._embedded.indexableObject._embedded.workflowitem._embedded.item", - is(SearchResultMatcher.matchEmbeddedObjectOnItemName("item", "Test Metaphysics")))) - ))) .andExpect(jsonPath("$._embedded.searchResult.page.totalElements", is(3))); } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/LoginAsEPersonIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/LoginAsEPersonIT.java index bf3b54c9224a..60d0e1a2a56d 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/LoginAsEPersonIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/LoginAsEPersonIT.java @@ -191,6 +191,7 @@ public void createEmptyWorkspaceItemLoginOnBehalfOfCheckSubmitterTest() throws E // create a workspaceitem explicitly in the col1 MvcResult mvcResult = getClient(authToken).perform(post("/api/submission/workspaceitems") .param("owningCollection", col1.getID().toString()) + .param("embed", "collection") .header("X-On-Behalf-Of", eperson.getID()) .contentType(org.springframework .http.MediaType.APPLICATION_JSON)) @@ -204,7 +205,8 @@ public void createEmptyWorkspaceItemLoginOnBehalfOfCheckSubmitterTest() throws E Map map = mapper.readValue(content, Map.class); String workspaceItemId = String.valueOf(map.get("id")); - getClient(authToken).perform(get("/api/submission/workspaceitems/" + workspaceItemId)) + getClient(authToken).perform(get("/api/submission/workspaceitems/" + workspaceItemId) + .param("embed", "submitter")) .andExpect(jsonPath("$._embedded.submitter", EPersonMatcher.matchProperties(eperson))); } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java index 8b2f3f093a37..82108c4bbeb0 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java @@ -878,6 +878,7 @@ public void createEmptyWorkspateItemTest() throws Exception { // create a workspaceitem explicitly in the col1 getClient(authToken).perform(post("/api/submission/workspaceitems") .param("owningCollection", col1.getID().toString()) + .param("embed", "collection") .contentType(org.springframework.http.MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(jsonPath("$._embedded.collection.id", is(col1.getID().toString()))) @@ -886,6 +887,7 @@ public void createEmptyWorkspateItemTest() throws Exception { // create a workspaceitem explicitly in the col2 getClient(authToken).perform(post("/api/submission/workspaceitems") .param("owningCollection", col2.getID().toString()) + .param("embed", "collection") .contentType(org.springframework.http.MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(jsonPath("$._embedded.collection.id", is(col2.getID().toString()))) @@ -894,10 +896,10 @@ public void createEmptyWorkspateItemTest() throws Exception { // create a workspaceitem without an explicit collection, this will go in the first valid collection for the // user: the col1 getClient(authToken).perform(post("/api/submission/workspaceitems") + .param("embed", "collection") .contentType(org.springframework.http.MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(jsonPath("$._embedded.collection.id", is(col1.getID().toString()))) - .andExpect(jsonPath("$", WorkspaceItemMatcher.matchFullEmbeds())) .andDo(result -> idRef3.set(read(result.getResponse().getContentAsString(), "$.id"))); @@ -945,7 +947,8 @@ public void createSingleWorkspaceItemFromBibtexFileWithOneEntryTest() throws Exc try { // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1) getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(bibtexFile)) + .file(bibtexFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -974,6 +977,7 @@ public void createSingleWorkspaceItemFromBibtexFileWithOneEntryTest() throws Exc try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") .file(bibtexFile) + .param("embed", "collection") .param("owningCollection", col2.getID().toString())) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -1037,7 +1041,8 @@ public void createSingleWorkspaceItemFromBibtexArticleFileWithOneEntryTest() thr try { // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1) getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(bibtexFile)) + .file(bibtexFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0]" + @@ -1071,6 +1076,7 @@ public void createSingleWorkspaceItemFromBibtexArticleFileWithOneEntryTest() thr try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") .file(bibtexFile) + .param("embed", "collection") .param("owningCollection", col2.getID().toString())) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0]" + @@ -1134,7 +1140,8 @@ public void createSingleWorkspaceItemFromBibtexFileWithDiacriticsTest() throws E try { // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1) getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(bibtexFile)) + .file(bibtexFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections." + @@ -1165,6 +1172,7 @@ public void createSingleWorkspaceItemFromBibtexFileWithDiacriticsTest() throws E try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") .file(bibtexFile) + .param("embed", "collection") .param("owningCollection", col2.getID().toString())) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections." + @@ -1231,7 +1239,8 @@ public void createSingleWorkspaceItemFromBibtexFileWithMultipleAuthorsTest() thr try { // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1) getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(bibtexFile)) + .file(bibtexFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0]" + @@ -1271,6 +1280,7 @@ public void createSingleWorkspaceItemFromBibtexFileWithMultipleAuthorsTest() thr try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") .file(bibtexFile) + .param("embed", "collection") .param("owningCollection", col2.getID().toString())) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0]" + @@ -1336,7 +1346,8 @@ public void createSingleWorkspaceItemFromCSVWithOneEntryTest() throws Exception AtomicReference> idRef = new AtomicReference<>(); try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(csvFile)) + .file(csvFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -1376,6 +1387,7 @@ public void createSingleWorkspaceItemFromCSVWithOneEntryTest() throws Exception try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") .file(csvFile) + .param("embed", "collection") .param("owningCollection", col2.getID().toString())) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone" @@ -1453,7 +1465,8 @@ public void createSingleWorkspaceItemFromCSVWithOneEntryAndMissingDataTest() thr try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(csvFile)) + .file(csvFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -1531,7 +1544,8 @@ public void createSingleWorkspaceItemFromTSVWithOneEntryTest() throws Exception // create workspaceitems in the default collection (col1) try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(tsvFile)) + .file(tsvFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -1607,7 +1621,8 @@ public void createSingleWorkspaceItemFromRISWithOneEntryTest() throws Exception // create workspaceitems in the default collection (col1) try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(tsvFile)) + .file(tsvFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -1684,7 +1699,8 @@ public void createSingleWorkspaceItemFromEndnoteWithOneEntryTest() throws Except // create workspaceitems in the default collection (col1) try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(endnoteFile)) + .file(endnoteFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -1763,7 +1779,8 @@ public void createSingleWorkspaceItemFromTSVWithOneEntryAndMissingDataTest() thr // create workspaceitems in the default collection (col1) try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(csvFile)) + .file(csvFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -1844,7 +1861,9 @@ public void createSingleWorkspaceItemFromMultipleFilesWithOneEntryTest() throws // create a workspaceitem from a single bibliographic entry file explicitly in the default collection (col1) try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") - .file(bibtexFile).file(pubmedFile)) + .file(bibtexFile) + .file(pubmedFile) + .param("embed", "collection")) // create should return 200, 201 (created) is better for single resource .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -1879,6 +1898,7 @@ public void createSingleWorkspaceItemFromMultipleFilesWithOneEntryTest() throws try { getClient(authToken).perform(multipart("/api/submission/workspaceitems") .file(bibtexFile).file(pubmedFile) + .param("embed", "collection") .param("owningCollection", col2.getID().toString())) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", @@ -4323,6 +4343,7 @@ public void createWorkspaceItemFromExternalSources() throws Exception { String token = getAuthToken(admin.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/submission/workspaceitems?owningCollection=" + col1.getID().toString()) + .param("embed", "item") .contentType(parseMediaType(TEXT_URI_LIST_VALUE)) .content("https://localhost:8080/server/api/integration/" + "externalsources/mock/entryValues/one")) @@ -4333,7 +4354,8 @@ public void createWorkspaceItemFromExternalSources() throws Exception { workspaceItemId = (Integer) map.get("id"); String itemUuidString = String.valueOf(((Map) ((Map) map.get("_embedded")).get("item")).get("uuid")); - getClient(token).perform(get("/api/submission/workspaceitems/" + workspaceItemId)) + getClient(token).perform(get("/api/submission/workspaceitems/" + workspaceItemId) + .param("embed", "item")) .andExpect(status().isOk()) .andExpect(jsonPath("$", Matchers.allOf( hasJsonPath("$.id", is(workspaceItemId)), @@ -4528,6 +4550,7 @@ public void createWorkspaceItemFromExternalSourcesNonAdminWithPermission() throw String token = getAuthToken(eperson.getEmail(), password); getClient(token).perform(post("/api/submission/workspaceitems") + .param("embed", "collection") .param("owningCollection", col1.getID().toString()) .contentType(parseMediaType(TEXT_URI_LIST_VALUE)) .content("https://localhost:8080/server/api/integration/externalsources/" + @@ -4537,7 +4560,9 @@ public void createWorkspaceItemFromExternalSourcesNonAdminWithPermission() throw .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id"))); workspaceItemId = idRef.get(); - getClient(token).perform(get("/api/submission/workspaceitems/" + workspaceItemId)) + getClient(token).perform(get("/api/submission/workspaceitems/" + workspaceItemId) + .param("embed", "collection") + .param("embed", "item")) .andExpect(status().isOk()) .andExpect(jsonPath("$", Matchers.allOf( hasJsonPath("$.id", is(workspaceItemId)), From 75c688daef432348e916aca0335dbf5b368d8586 Mon Sep 17 00:00:00 2001 From: DSpace Bot <68393067+dspace-bot@users.noreply.github.com> Date: Mon, 29 Apr 2024 14:31:20 -0500 Subject: [PATCH 137/230] [Port dspace-7_x] Drop not null for EPerson in Process table (#9510) * Set EPerson nullable in ProcessTable (cherry picked from commit 9ed997d2ddcce046b6affc4f2f8edbe62f03cc51) * chore: Remove nullable = false in EPerson Entity (cherry picked from commit f1a38c2485715613115734f887567fdfcf412d2c) * chore: Avoid NPE when getEPerson is called (cherry picked from commit 2f9ad722986ae2997856e88ce125cbd1e8500037) * test: Add test for insert nullable EPerson in Process' table (cherry picked from commit 8fe264ee6930f278def5f54df964ea8c8f4a5b60) * Revert "Set EPerson nullable in ProcessTable" This reverts commit aea7b9385b6c6972b0ac27e061d082bb92eaf4a6. (cherry picked from commit 7de931c7be8ab885a20030115ad730fc40e73832) * feat: Drop NOT NULL for user_id in Process table (cherry picked from commit 3b73786c554e8fe768cedf04baa86ac6e447fd6e) * chore: add endline (cherry picked from commit 27ed14c38ca57cb6fcf5185c0517c3aef27fd589) * fix: add headers file (cherry picked from commit a3ea7cbaaa89fe34094f110071aef4acfa811d35) * Rename file sql (cherry picked from commit eb22285924752aec13ea6aa16fbba7bff5c54daf) * Rename sql script to 7.6.x (cherry picked from commit d2ef87eab6467524e73bd8c5edb5f97ed314a327) * fix: Set fetch lazy in EPerson Process (cherry picked from commit d6340403ffade379a4c2745b52c37b28940b063f) * fix: set the user attached to a process to null if none is found in the DB (cherry picked from commit afb734df5fa20f9e814397efa6ab7aef93b1a3b7) --------- Co-authored-by: Roy Bruschini Co-authored-by: Jens Vannerum --- .../src/main/java/org/dspace/scripts/Process.java | 4 ++-- .../org/dspace/scripts/ProcessServiceImpl.java | 15 +++++++++++---- ...6_2024.03.07__set_eperson_process_nullable.sql | 9 +++++++++ ...6_2024.03.07__set_eperson_process_nullable.sql | 9 +++++++++ .../test/java/org/dspace/process/ProcessIT.java | 11 +++++++++++ .../app/rest/converter/ProcessConverter.java | 7 ++++++- 6 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.03.07__set_eperson_process_nullable.sql create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.03.07__set_eperson_process_nullable.sql diff --git a/dspace-api/src/main/java/org/dspace/scripts/Process.java b/dspace-api/src/main/java/org/dspace/scripts/Process.java index eab3ba460c09..9834c78c1551 100644 --- a/dspace-api/src/main/java/org/dspace/scripts/Process.java +++ b/dspace-api/src/main/java/org/dspace/scripts/Process.java @@ -51,8 +51,8 @@ public class Process implements ReloadableEntity { @Column(name = "process_id", unique = true, nullable = false) private Integer processId; - @ManyToOne - @JoinColumn(name = "user_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") private EPerson ePerson; @Column(name = "start_time") diff --git a/dspace-api/src/main/java/org/dspace/scripts/ProcessServiceImpl.java b/dspace-api/src/main/java/org/dspace/scripts/ProcessServiceImpl.java index 2e14aeaa36c0..f242ec7acdad 100644 --- a/dspace-api/src/main/java/org/dspace/scripts/ProcessServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/scripts/ProcessServiceImpl.java @@ -92,10 +92,17 @@ public Process create(Context context, EPerson ePerson, String scriptName, }); Process createdProcess = processDAO.create(context, process); - log.info(LogHelper.getHeader(context, "process_create", - "Process has been created for eperson with email " + ePerson.getEmail() - + " with ID " + createdProcess.getID() + " and scriptName " + - scriptName + " and parameters " + parameters)); + + if (ePerson != null) { + log.info(LogHelper.getHeader(context, "process_create", + "Process has been created for eperson with email " + ePerson.getEmail() + + " with ID " + createdProcess.getID() + " and scriptName " + + scriptName + " and parameters " + parameters)); + } else { + log.info(LogHelper.getHeader(context, "process_create", + "Process has been created for command-line user with ID " + createdProcess.getID() + + " and scriptName " + scriptName + " and parameters " + parameters)); + } return createdProcess; } diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.03.07__set_eperson_process_nullable.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.03.07__set_eperson_process_nullable.sql new file mode 100644 index 000000000000..39dc1115be49 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.03.07__set_eperson_process_nullable.sql @@ -0,0 +1,9 @@ +-- +-- 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/ +-- + +ALTER TABLE process ALTER COLUMN user_id DROP NOT NULL; diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.03.07__set_eperson_process_nullable.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.03.07__set_eperson_process_nullable.sql new file mode 100644 index 000000000000..39dc1115be49 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.03.07__set_eperson_process_nullable.sql @@ -0,0 +1,9 @@ +-- +-- 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/ +-- + +ALTER TABLE process ALTER COLUMN user_id DROP NOT NULL; diff --git a/dspace-api/src/test/java/org/dspace/process/ProcessIT.java b/dspace-api/src/test/java/org/dspace/process/ProcessIT.java index d6640652121c..6cf840ea6abe 100644 --- a/dspace-api/src/test/java/org/dspace/process/ProcessIT.java +++ b/dspace-api/src/test/java/org/dspace/process/ProcessIT.java @@ -9,6 +9,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.HashSet; import java.util.LinkedList; @@ -87,4 +88,14 @@ public void removeOneGroupTest() throws Exception { assertFalse(isPresent); } + + @Test + public void addProcessWithNullEPersonTest() throws Exception { + try { + ProcessBuilder.createProcess(context, null, "mock-script", new LinkedList<>(), + new HashSet<>()).build(); + } catch (NullPointerException e) { + fail("Should not have thrown NullPointerException"); + } + } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java index de03d6063019..38eaf4204798 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java @@ -14,6 +14,7 @@ import org.dspace.app.rest.projection.Projection; import org.dspace.scripts.Process; import org.dspace.scripts.service.ProcessService; +import org.hibernate.ObjectNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -39,7 +40,11 @@ public ProcessRest convert(Process process, Projection projection) { processRest.setId(process.getID()); processRest.setScriptName(process.getName()); processRest.setProcessId(process.getID()); - processRest.setUserId(process.getEPerson().getID()); + try { + processRest.setUserId(process.getEPerson().getID()); + } catch (ObjectNotFoundException e ) { + processRest.setUserId(null); + } processRest.setProcessStatus(process.getProcessStatus()); processRest.setStartTime(process.getStartTime()); processRest.setEndTime(process.getFinishedTime()); From 2f99646417117fc54eb0b2ed301af88ea306c71f Mon Sep 17 00:00:00 2001 From: haoueclf Date: Mon, 11 Dec 2023 13:42:50 +0100 Subject: [PATCH 138/230] [DS-3439] Copy collection template item specified metadata during Sword v2 METS deposit ingestion. (cherry picked from commit 7ead4ae7f005f79f8c6a9fe704d60511259bdaee) --- .../org/dspace/content/ItemServiceImpl.java | 50 +++++++++++++++++++ .../content/WorkspaceItemServiceImpl.java | 48 +----------------- .../packager/AbstractMETSIngester.java | 3 ++ .../dspace/content/service/ItemService.java | 12 +++++ 4 files changed, 66 insertions(+), 47 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java index 26a61877fe7f..285b3b6940ff 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.UUID; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -276,6 +277,55 @@ public Item createTemplateItem(Context context, Collection collection) throws SQ } } + @Override + public void populateWithTemplateItemMetadata(Context context, Collection collection, boolean template, Item item) + throws SQLException { + + Item templateItem = collection.getTemplateItem(); + + Optional colEntityType = getDSpaceEntityType(collection); + Optional templateItemEntityType = getDSpaceEntityType(templateItem); + + if (template && colEntityType.isPresent() && templateItemEntityType.isPresent() && + !StringUtils.equals(colEntityType.get().getValue(), templateItemEntityType.get().getValue())) { + throw new IllegalStateException("The template item has entity type : (" + + templateItemEntityType.get().getValue() + ") different than collection entity type : " + + colEntityType.get().getValue()); + } + + if (template && colEntityType.isPresent() && templateItemEntityType.isEmpty()) { + MetadataValue original = colEntityType.get(); + MetadataField metadataField = original.getMetadataField(); + MetadataSchema metadataSchema = metadataField.getMetadataSchema(); + // NOTE: dspace.entity.type = does not make sense + // the collection entity type is by default blank when a collection is first created + if (StringUtils.isNotBlank(original.getValue())) { + addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(), + metadataField.getQualifier(), original.getLanguage(), original.getValue()); + } + } + + if (template && (templateItem != null)) { + List md = getMetadata(templateItem, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + + for (MetadataValue aMd : md) { + MetadataField metadataField = aMd.getMetadataField(); + MetadataSchema metadataSchema = metadataField.getMetadataSchema(); + addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(), + metadataField.getQualifier(), aMd.getLanguage(), aMd.getValue()); + } + } + } + + private Optional getDSpaceEntityType(DSpaceObject dSpaceObject) { + return Objects.nonNull(dSpaceObject) ? dSpaceObject.getMetadata() + .stream() + .filter(x -> x.getMetadataField().toString('.') + .equalsIgnoreCase("dspace.entity.type")) + .findFirst() + : Optional.empty(); + } + @Override public Iterator findAll(Context context) throws SQLException { return itemDAO.findAll(context, true); diff --git a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java index b78f6b9f7de8..1da9e6e44a6a 100644 --- a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java @@ -12,11 +12,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Optional; import java.util.UUID; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; import org.dspace.app.util.DCInputsReaderException; import org.dspace.app.util.Util; @@ -141,41 +138,7 @@ public WorkspaceItem create(Context context, Collection collection, UUID uuid, b .addPolicy(context, item, Constants.DELETE, item.getSubmitter(), ResourcePolicy.TYPE_SUBMISSION); // Copy template if appropriate - Item templateItem = collection.getTemplateItem(); - - Optional colEntityType = getDSpaceEntityType(collection); - Optional templateItemEntityType = getDSpaceEntityType(templateItem); - - if (template && colEntityType.isPresent() && templateItemEntityType.isPresent() && - !StringUtils.equals(colEntityType.get().getValue(), templateItemEntityType.get().getValue())) { - throw new IllegalStateException("The template item has entity type : (" + - templateItemEntityType.get().getValue() + ") different than collection entity type : " + - colEntityType.get().getValue()); - } - - if (template && colEntityType.isPresent() && templateItemEntityType.isEmpty()) { - MetadataValue original = colEntityType.get(); - MetadataField metadataField = original.getMetadataField(); - MetadataSchema metadataSchema = metadataField.getMetadataSchema(); - // NOTE: dspace.entity.type = does not make sense - // the collection entity type is by default blank when a collection is first created - if (StringUtils.isNotBlank(original.getValue())) { - itemService.addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(), - metadataField.getQualifier(), original.getLanguage(), original.getValue()); - } - } - - if (template && (templateItem != null)) { - List md = itemService.getMetadata(templateItem, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - - for (MetadataValue aMd : md) { - MetadataField metadataField = aMd.getMetadataField(); - MetadataSchema metadataSchema = metadataField.getMetadataSchema(); - itemService.addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(), - metadataField.getQualifier(), aMd.getLanguage(), - aMd.getValue()); - } - } + itemService.populateWithTemplateItemMetadata(context, collection, template, item); itemService.update(context, item); @@ -213,15 +176,6 @@ public WorkspaceItem create(Context context, Collection collection, UUID uuid, b return workspaceItem; } - private Optional getDSpaceEntityType(DSpaceObject dSpaceObject) { - return Objects.nonNull(dSpaceObject) ? dSpaceObject.getMetadata() - .stream() - .filter(x -> x.getMetadataField().toString('.') - .equalsIgnoreCase("dspace.entity.type")) - .findFirst() - : Optional.empty(); - } - @Override public WorkspaceItem create(Context c, WorkflowItem workflowItem) throws SQLException, AuthorizeException { WorkspaceItem workspaceItem = workspaceItemDAO.create(c, new WorkspaceItem()); diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java index 98277c4f9c06..0ed0abe21825 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java @@ -636,6 +636,9 @@ protected DSpaceObject replaceObject(Context context, DSpaceObject dso, owningCollection = inProgressSubmission.getCollection(); } + itemService.populateWithTemplateItemMetadata(context, owningCollection, params.useCollectionTemplate(), + item); + addLicense(context, item, license, owningCollection , params); diff --git a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java index de7644af83fe..12867ad18c3f 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java @@ -83,6 +83,18 @@ public interface ItemService */ public Item createTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException; + /** + * Populate the given item with all template item specified metadata. + * + * @param context DSpace context object + * @param collection Collection (parent) + * @param template if true, the item inherits all collection's template item metadata + * @param item item to populate with template item specified metadata + * @throws SQLException if database error + */ + public void populateWithTemplateItemMetadata (Context context, Collection collection, boolean template, Item item) + throws SQLException; + /** * Get all the items in the archive. Only items with the "in archive" flag * set are included. The order of the list is indeterminate. From 849a252fa85e79c7669648bcd317e18b8c66e8ad Mon Sep 17 00:00:00 2001 From: Agustina Martinez Date: Wed, 24 Jan 2024 21:13:52 +0000 Subject: [PATCH 139/230] Update ContainerManagerDSpace.java Remove duplicate item.delete call that causes hibernate errors as item is already deleted (cherry picked from commit 57032050b97e264a2a875d4bae49f092e06df481) --- .../main/java/org/dspace/sword2/ContainerManagerDSpace.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java index 454afd80dc1c..81b48d22c081 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java @@ -760,9 +760,6 @@ protected void doContainerDelete(SwordContext swordContext, Item item, WorkflowItem wfi = wft.getWorkflowItem(context, item); workflowItemService.deleteWrapper(context, wfi); } - - // then delete the item - itemService.delete(context, item); } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); } catch (AuthorizeException e) { From 435988ca00f00fa9c116792defe0925c05d65cd3 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Tue, 30 Apr 2024 16:40:47 +0200 Subject: [PATCH 140/230] Swap the delete and constraint db lines --- ...023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql | 4 ++-- ...023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql index 2e352e2ee7cf..61f361625dd9 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql @@ -6,7 +6,7 @@ -- http://www.dspace.org/license/ -- +DELETE FROM ResourcePolicy WHERE eperson_id is null and epersongroup_id is null; + ALTER TABLE ResourcePolicy ADD CONSTRAINT resourcepolicy_eperson_and_epersongroup_not_nullobject_chk CHECK (eperson_id is not null or epersongroup_id is not null) ; - -DELETE FROM ResourcePolicy WHERE eperson_id is null and epersongroup_id is null; diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql index 2e352e2ee7cf..61f361625dd9 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql @@ -6,7 +6,7 @@ -- http://www.dspace.org/license/ -- +DELETE FROM ResourcePolicy WHERE eperson_id is null and epersongroup_id is null; + ALTER TABLE ResourcePolicy ADD CONSTRAINT resourcepolicy_eperson_and_epersongroup_not_nullobject_chk CHECK (eperson_id is not null or epersongroup_id is not null) ; - -DELETE FROM ResourcePolicy WHERE eperson_id is null and epersongroup_id is null; From 07377d12c8ba249bb1cf17c094e84c2f2f8eda30 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 30 Apr 2024 09:48:55 -0500 Subject: [PATCH 141/230] Add ITs which test SWORD deletion for workspace vs workflow items (we already have a test for archived items) (cherry picked from commit 70b0a2874964682ff5efbff9452351fae534f1f6) --- .../java/org/dspace/app/sword2/Swordv2IT.java | 137 +++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/sword2/Swordv2IT.java b/dspace-server-webapp/src/test/java/org/dspace/app/sword2/Swordv2IT.java index 64e3db7dfc1a..3ff79f78055c 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/sword2/Swordv2IT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/sword2/Swordv2IT.java @@ -20,9 +20,13 @@ import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; import org.dspace.builder.ItemBuilder; +import org.dspace.builder.WorkflowItemBuilder; +import org.dspace.builder.WorkspaceItemBuilder; import org.dspace.content.Collection; import org.dspace.content.Item; +import org.dspace.content.WorkspaceItem; import org.dspace.services.ConfigurationService; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.junit.Assume; import org.junit.Before; import org.junit.ClassRule; @@ -295,7 +299,7 @@ public void depositAndEditViaSwordTest() throws Exception { assertThat(response.getBody(), containsString(newTitle)); //---- - // STEP 5: Verify uploaded content can be DELETED via SWORDv2 (by an Admin ONLY) + // STEP 5: Verify archived Item can be DELETED via SWORDv2 (by an Admin ONLY) //---- // Edit URI should also allow user to DELETE the uploaded content // Since we submitted to a collection WITHOUT a workflow, this item is in archive. That means DELETE @@ -306,7 +310,6 @@ public void depositAndEditViaSwordTest() throws Exception { .headers(authHeaders) .build(); response = responseAsString(request); - // Expect a 204 No Content response assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); @@ -322,6 +325,136 @@ public void depositAndEditViaSwordTest() throws Exception { assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); } + @Test + public void deleteWorkspaceItemViaSwordTest() throws Exception { + context.turnOffAuthorisationSystem(); + // Create a top level community and one Collection + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Test SWORDv2 Collection") + .withSubmitterGroup(eperson) + .build(); + + String titleOfItem = "This is a test SWORD workspace item"; + WorkspaceItem wsi = WorkspaceItemBuilder.createWorkspaceItem(context, collection) + .withSubmitter(eperson) + .withTitle(titleOfItem) + .build(); + + // Above changes MUST be committed to the database for SWORDv2 to see them. + context.commit(); + context.restoreAuthSystemState(); + + // Edit link of WorkspaceItem is the Item UUID + String editLink = "/swordv2/edit/" + wsi.getItem().getID(); + + //---- + // STEP 1: Verify WorkspaceItem is found via SWORDv2 when logged in as the submitter + //---- + HttpHeaders authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + RequestEntity request = RequestEntity.get(editLink) + .accept(MediaType.valueOf("application/atom+xml")) + .headers(authHeaders) + .build(); + ResponseEntity response = responseAsString(request); + assertEquals(HttpStatus.OK, response.getStatusCode()); + // Verify the new Item title is now included in the response body + assertThat(response.getBody(), containsString(titleOfItem)); + + //---- + // STEP 2: Verify WorkspaceItem can be deleted by submitter + //---- + authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + request = RequestEntity.delete(editLink) + .headers(authHeaders) + .build(); + response = responseAsString(request); + // Expect a 204 No Content response + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + + // Verify that Edit URI now returns a 404 (deleted successfully) + authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + request = RequestEntity.get(editLink) + .accept(MediaType.valueOf("application/atom+xml")) + .headers(authHeaders) + .build(); + response = responseAsString(request); + // Expect a 404 response as content was deleted + assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); + } + + + @Test + public void deleteWorkflowItemViaSwordTest() throws Exception { + context.turnOffAuthorisationSystem(); + // Create a top level community and one Collection + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + // Create a Collection with a workflow step enabled + Collection collection = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Test SWORDv2 Workflow Collection") + .withSubmitterGroup(eperson) + .withWorkflowGroup(1, admin) + .build(); + + String titleOfItem = "This is a test SWORD workflow item"; + XmlWorkflowItem workflowItem = WorkflowItemBuilder.createWorkflowItem(context, collection) + .withSubmitter(eperson) + .withTitle(titleOfItem) + .withIssueDate("2017-10-17") + .build(); + // Above changes MUST be committed to the database for SWORDv2 to see them. + context.commit(); + context.restoreAuthSystemState(); + + // Edit link of WorkflowItem is the Item UUID + String editLink = "/swordv2/edit/" + workflowItem.getItem().getID(); + + //---- + // STEP 1: Verify WorkflowItem is found via SWORDv2 when logged in as the submitter + //---- + HttpHeaders authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + RequestEntity request = RequestEntity.get(editLink) + .accept(MediaType.valueOf("application/atom+xml")) + .headers(authHeaders) + .build(); + ResponseEntity response = responseAsString(request); + assertEquals(HttpStatus.OK, response.getStatusCode()); + // Verify the new Item title is now included in the response body + assertThat(response.getBody(), containsString(titleOfItem)); + + //---- + // STEP 2: Verify WorkflowItem can be deleted by ADMIN only + //---- + // NOTE: Once Item is in Workflow, deletion requires ADMIN permissions + authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(admin.getEmail(), password); + request = RequestEntity.delete(editLink) + .headers(authHeaders) + .build(); + response = responseAsString(request); + // Expect a 204 No Content response + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + + // Verify that Edit URI now returns a 404 (deleted successfully) + authHeaders = new HttpHeaders(); + authHeaders.setBasicAuth(eperson.getEmail(), password); + request = RequestEntity.get(editLink) + .accept(MediaType.valueOf("application/atom+xml")) + .headers(authHeaders) + .build(); + response = responseAsString(request); + // Expect a 404 response as content was deleted + assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); + } + @Test public void editUnauthorizedTest() throws Exception { // Attempt to POST to /edit endpoint without sending authentication information From 67d7c0bf3bb646ba94f2d7196f7ed20a41d0e701 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 30 Apr 2024 10:30:12 -0500 Subject: [PATCH 142/230] Fix deletion by only cleaning up wrapper for Workspace/workflow items (cherry picked from commit 5c13569d0fc6709d43fd8824e875220b4ccad302) --- .../main/java/org/dspace/sword2/ContainerManagerDSpace.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java index 81b48d22c081..c0e8ef6bdc46 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java @@ -755,11 +755,14 @@ protected void doContainerDelete(SwordContext swordContext, Item item, WorkflowTools wft = new WorkflowTools(); if (wft.isItemInWorkspace(swordContext.getContext(), item)) { WorkspaceItem wsi = wft.getWorkspaceItem(context, item); - workspaceItemService.deleteAll(context, wsi); + workspaceItemService.deleteWrapper(context, wsi); } else if (wft.isItemInWorkflow(context, item)) { WorkflowItem wfi = wft.getWorkflowItem(context, item); workflowItemService.deleteWrapper(context, wfi); } + + // then delete the item + itemService.delete(context, item); } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); } catch (AuthorizeException e) { From f9d3efd1e7efc7ac6f96d5ed48f6bc16b2f2da0d Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Fri, 26 Jan 2024 09:58:57 +0100 Subject: [PATCH 143/230] added validation of page url (cherry picked from commit 771f37a1facf97d29850db835490b6c2bfa07adb) --- .../app/rest/repository/FeedbackRestRepository.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java index 8fd28bbe94b8..8188237114e0 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java @@ -79,8 +79,14 @@ protected FeedbackRest createAndReturn(Context context) throws AuthorizeExceptio throw new DSpaceBadRequestException("e-mail and message fields are mandatory!"); } + String pageUrl = feedbackRest.getPage(); + String urlPrefix = configurationService.getProperty("dspace.ui.url"); + if (! StringUtils.startsWith(pageUrl, urlPrefix)) { + throw new DSpaceBadRequestException("unexpected page url was submitted"); + } + try { - feedbackService.sendEmail(context, req, recipientEmail, senderEmail, message, feedbackRest.getPage()); + feedbackService.sendEmail(context, req, recipientEmail, senderEmail, message, pageUrl); } catch (IOException | MessagingException e) { throw new RuntimeException(e.getMessage(), e); } @@ -100,4 +106,4 @@ public void setFeedbackService(FeedbackService feedbackService) { this.feedbackService = feedbackService; } -} \ No newline at end of file +} From 0cfe4aec73db1681c80cbc914898c3c050c3cc11 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Fri, 26 Jan 2024 10:40:48 +0100 Subject: [PATCH 144/230] allow empty feedback page url (cherry picked from commit c4cc56a4291106beb8b3250e4e4058d13ab962e2) --- .../org/dspace/app/rest/repository/FeedbackRestRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java index 8188237114e0..42672062175a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java @@ -81,7 +81,7 @@ protected FeedbackRest createAndReturn(Context context) throws AuthorizeExceptio String pageUrl = feedbackRest.getPage(); String urlPrefix = configurationService.getProperty("dspace.ui.url"); - if (! StringUtils.startsWith(pageUrl, urlPrefix)) { + if (StringUtils.isNotBlank(pageUrl) && ! StringUtils.startsWith(pageUrl, urlPrefix)) { throw new DSpaceBadRequestException("unexpected page url was submitted"); } From 30e3cde30d2b996a151626fd3068c482ef198772 Mon Sep 17 00:00:00 2001 From: Agustina Martinez Date: Mon, 29 Jan 2024 16:33:46 +0000 Subject: [PATCH 145/230] Update ItemImportServiceImpl.java expand setPermission to take the rpType string (cherry picked from commit 679df52bbdcb3f9b85da2d3128417f99b2133b80) --- .../org/dspace/app/itemimport/ItemImportServiceImpl.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 255f4bdcbb15..c1357aff9eb5 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 @@ -1743,7 +1743,8 @@ protected void processOptions(Context c, Item myItem, List options) } else { logInfo("\tSetting special permissions for " + bitstreamName); - setPermission(c, myGroup, actionID, bs); + String rpType = useWorkflow ? ResourcePolicy.TYPE_SUBMISSION : ResourcePolicy.TYPE_INHERITED; + setPermission(c, myGroup, rpType, actionID, bs); } } @@ -1801,13 +1802,14 @@ protected void processOptions(Context c, Item myItem, List options) * * @param c DSpace Context * @param g Dspace Group + * @param rpType resource policy type string * @param actionID action identifier * @param bs Bitstream * @throws SQLException if database error * @throws AuthorizeException if authorization error * @see org.dspace.core.Constants */ - protected void setPermission(Context c, Group g, int actionID, Bitstream bs) + protected void setPermission(Context c, Group g, String rpType, int actionID, Bitstream bs) throws SQLException, AuthorizeException { if (!isTest) { // remove the default policy @@ -1819,6 +1821,7 @@ protected void setPermission(Context c, Group g, int actionID, Bitstream bs) rp.setdSpaceObject(bs); rp.setAction(actionID); rp.setGroup(g); + rp.setRpType(rpType); resourcePolicyService.update(c, rp); } else { From a97d72f993ce6cb6edf2e3991707895fc4288626 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 1 May 2024 11:50:22 -0500 Subject: [PATCH 146/230] Minor update to latest Spring version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da252ad102c3..9f8f8f247024 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 11 - 5.3.33 + 5.3.34 2.7.18 5.7.11 5.6.15.Final From 735906c42921f1e79b7ee843b9d836049f051afb Mon Sep 17 00:00:00 2001 From: John Abrahams Date: Wed, 1 May 2024 11:54:44 -0400 Subject: [PATCH 147/230] Install unzip util in final built image (cherry picked from commit 3eae430beca18f18d1396e614f8aa1f5b85169a7) --- Dockerfile.cli | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Dockerfile.cli b/Dockerfile.cli index 96a84bc56268..53040a2fad89 100644 --- a/Dockerfile.cli +++ b/Dockerfile.cli @@ -33,9 +33,9 @@ WORKDIR /dspace-src ENV ANT_VERSION 1.10.13 ENV ANT_HOME /tmp/ant-$ANT_VERSION ENV PATH $ANT_HOME/bin:$PATH -# Need wget to install ant, and unzip for managing AIPs +# Need wget to install ant RUN apt-get update \ - && apt-get install -y --no-install-recommends wget unzip \ + && apt-get install -y --no-install-recommends wget \ && apt-get purge -y --auto-remove \ && rm -rf /var/lib/apt/lists/* # Download and install 'ant' @@ -52,3 +52,8 @@ ENV DSPACE_INSTALL=/dspace COPY --from=ant_build /dspace $DSPACE_INSTALL # Give java extra memory (1GB) ENV JAVA_OPTS=-Xmx1000m +# Install unzip for AIPs +RUN apt-get update \ + && apt-get install -y --no-install-recommends unzip \ + && apt-get purge -y --auto-remove \ + && rm -rf /var/lib/apt/lists/* From e1dc6951028b468e8676341ad1ccc28a95d0dd28 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 1 May 2024 11:37:05 -0500 Subject: [PATCH 148/230] Remove obsolete "version" tag from compose files (cherry picked from commit 9ca0ad5579348e4e092307e7688bda1c5c9a178f) --- docker-compose-cli.yml | 1 - docker-compose.yml | 1 - dspace/src/main/docker-compose/cli.assetstore.yml | 2 -- dspace/src/main/docker-compose/cli.ingest.yml | 2 -- dspace/src/main/docker-compose/db.entities.yml | 2 -- dspace/src/main/docker-compose/db.restore.yml | 2 -- dspace/src/main/docker-compose/docker-compose-angular.yml | 1 - dspace/src/main/docker-compose/docker-compose-iiif.yml | 1 - dspace/src/main/docker-compose/docker-compose-shibboleth.yml | 1 - 9 files changed, 13 deletions(-) diff --git a/docker-compose-cli.yml b/docker-compose-cli.yml index 4f4d4a189161..d6a194617e02 100644 --- a/docker-compose-cli.yml +++ b/docker-compose-cli.yml @@ -1,4 +1,3 @@ -version: "3.7" networks: # Default to using network named 'dspacenet' from docker-compose.yml. # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") diff --git a/docker-compose.yml b/docker-compose.yml index a7894135c6ab..23fce37db245 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.7' networks: dspacenet: ipam: diff --git a/dspace/src/main/docker-compose/cli.assetstore.yml b/dspace/src/main/docker-compose/cli.assetstore.yml index d6a6a4395f4e..6563aa081eb1 100644 --- a/dspace/src/main/docker-compose/cli.assetstore.yml +++ b/dspace/src/main/docker-compose/cli.assetstore.yml @@ -6,8 +6,6 @@ # http://www.dspace.org/license/ # -version: "3.7" - services: dspace-cli: environment: diff --git a/dspace/src/main/docker-compose/cli.ingest.yml b/dspace/src/main/docker-compose/cli.ingest.yml index d22a235d4fdd..6172147f1955 100644 --- a/dspace/src/main/docker-compose/cli.ingest.yml +++ b/dspace/src/main/docker-compose/cli.ingest.yml @@ -6,8 +6,6 @@ # http://www.dspace.org/license/ # -version: "3.7" - services: dspace-cli: environment: diff --git a/dspace/src/main/docker-compose/db.entities.yml b/dspace/src/main/docker-compose/db.entities.yml index 809cf52df0b6..3480c0df870d 100644 --- a/dspace/src/main/docker-compose/db.entities.yml +++ b/dspace/src/main/docker-compose/db.entities.yml @@ -6,8 +6,6 @@ # http://www.dspace.org/license/ # -version: "3.7" - services: dspacedb: image: dspace/dspace-postgres-pgcrypto:dspace-7_x-loadsql diff --git a/dspace/src/main/docker-compose/db.restore.yml b/dspace/src/main/docker-compose/db.restore.yml index fc2f30b9d8e0..09990e675619 100644 --- a/dspace/src/main/docker-compose/db.restore.yml +++ b/dspace/src/main/docker-compose/db.restore.yml @@ -6,8 +6,6 @@ # http://www.dspace.org/license/ # -version: "3.7" - # # Overrides the default "dspacedb" container behavior to load a local SQL file into PostgreSQL. # diff --git a/dspace/src/main/docker-compose/docker-compose-angular.yml b/dspace/src/main/docker-compose/docker-compose-angular.yml index 8f9bdf94b38b..c9b87c904f17 100644 --- a/dspace/src/main/docker-compose/docker-compose-angular.yml +++ b/dspace/src/main/docker-compose/docker-compose-angular.yml @@ -6,7 +6,6 @@ # http://www.dspace.org/license/ # -version: '3.7' networks: # Default to using network named 'dspacenet' from docker-compose.yml. # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") diff --git a/dspace/src/main/docker-compose/docker-compose-iiif.yml b/dspace/src/main/docker-compose/docker-compose-iiif.yml index d795192f13c4..6f5470e5d157 100644 --- a/dspace/src/main/docker-compose/docker-compose-iiif.yml +++ b/dspace/src/main/docker-compose/docker-compose-iiif.yml @@ -10,7 +10,6 @@ # Test environment for DSpace + Cantaloupe for IIIF support. See README for instructions. # This should NEVER be used in production scenarios. # -version: '3.7' networks: # Default to using network named 'dspacenet' from docker-compose.yml. # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") diff --git a/dspace/src/main/docker-compose/docker-compose-shibboleth.yml b/dspace/src/main/docker-compose/docker-compose-shibboleth.yml index 33eadcb142d7..f7fb2dcbd1ae 100644 --- a/dspace/src/main/docker-compose/docker-compose-shibboleth.yml +++ b/dspace/src/main/docker-compose/docker-compose-shibboleth.yml @@ -10,7 +10,6 @@ # Test environment for DSpace + Shibboleth (running via mod_shib in Apache). See README for instructions. # This should NEVER be used in production scenarios. # -version: '3.7' networks: # Default to using network named 'dspacenet' from docker-compose.yml. # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") From 08c46bd0a1dcbfd238f52b454c0b6eb33c97f651 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 16:41:54 +0000 Subject: [PATCH 149/230] Bump org.xmlunit:xmlunit-core from 2.9.1 to 2.10.0 in /dspace-api Bumps [org.xmlunit:xmlunit-core](https://github.com/xmlunit/xmlunit) from 2.9.1 to 2.10.0. - [Release notes](https://github.com/xmlunit/xmlunit/releases) - [Changelog](https://github.com/xmlunit/xmlunit/blob/main/RELEASE_NOTES.md) - [Commits](https://github.com/xmlunit/xmlunit/compare/v2.9.1...v2.10.0) --- updated-dependencies: - dependency-name: org.xmlunit:xmlunit-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] (cherry picked from commit 1fdc3ce220b8bb7e13410176537cf06122bb5ea7) --- dspace-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 5b578fa49d5a..4c881cbd2465 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -900,7 +900,7 @@ org.xmlunit xmlunit-core - 2.9.1 + 2.10.0 test From 097d2530630fd862e6af13ed734374bdb1fb1046 Mon Sep 17 00:00:00 2001 From: Marie Verdonck Date: Thu, 22 Feb 2024 20:58:00 +0100 Subject: [PATCH 150/230] Make sure vocab init is run for vocabulary returned in /api/submission/vocabularies (cherry picked from commit 42437dd65be8400d96d1abf36d7abce58426b118) --- .../dspace/content/authority/DSpaceControlledVocabulary.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java index 16632ee5466b..94c9452356b0 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java @@ -224,6 +224,7 @@ public Choice getChoice(String authKey, String locale) { @Override public boolean isHierarchical() { + init(); return true; } @@ -256,6 +257,7 @@ public Choice getParentChoice(String authorityName, String childId, String local @Override public Integer getPreloadLevel() { + init(); return preloadLevel; } From 62b42ff2d1f13ebdca1efbb47f63f05796717405 Mon Sep 17 00:00:00 2001 From: Agustina Martinez Date: Thu, 21 Mar 2024 11:12:59 +0000 Subject: [PATCH 151/230] Update RoleDisseminator.java Fix NPE if empty password hash string (cherry picked from commit 04824a2e9826d03f83f77a36361f0f42e23b9ec0) --- .../main/java/org/dspace/content/packager/RoleDisseminator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java index f627779af8dc..15e9f1b14494 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java @@ -431,7 +431,7 @@ protected void writeEPerson(EPerson eperson, XMLStreamWriter writer, if (emitPassword) { PasswordHash password = ePersonService.getPasswordHash(eperson); - if (null != password) { + if (null != password && password.getHashString() != null) { writer.writeStartElement(PASSWORD_HASH); String algorithm = password.getAlgorithm(); From ce9129c961a65ef9027872e27946d656606227f9 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Fri, 3 May 2024 14:20:58 +0200 Subject: [PATCH 152/230] 105866: Remove commented code --- .../dspace/app/rest/converter/AInprogressItemConverter.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java index f40022f19f79..4cd3d2bfb2e7 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java @@ -70,11 +70,6 @@ protected void fillFromModel(T obj, R witem, Projection projection) { submitter = obj.getSubmitter(); witem.setId(obj.getID()); -// witem.setCollection(collection != null ? converter.toRest(collection, projection) : null); -// witem.setItem(converter.toRest(item, projection)); -// if (submitter != null) { -// witem.setSubmitter(converter.toRest(submitter, projection)); -// } // 1. retrieve the submission definition // 2. iterate over the submission section to allow to plugin additional From 24f2bca4b3619691fb27f40d7869e79fb83bae78 Mon Sep 17 00:00:00 2001 From: Xiqinger <163422483+Xiqinger@users.noreply.github.com> Date: Tue, 26 Mar 2024 22:42:47 +0800 Subject: [PATCH 153/230] check path before mkdirs (cherry picked from commit fda62bc10154e9e3e84fcadabd46f6915321c4c6) --- .../app/itemimport/ItemImportServiceImpl.java | 83 +++++++++---------- 1 file changed, 41 insertions(+), 42 deletions(-) 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 6531b7d0c194..cd55e97a6356 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 @@ -1959,58 +1959,57 @@ public String unzip(File zipfile, String destDir) throws IOException { try { while (entries.hasMoreElements()) { entry = entries.nextElement(); + String entryName = entry.getName(); + File outFile = new File(zipDir + entryName); + // Verify that this file/directory will be extracted into our zipDir (and not somewhere else!) + if (!outFile.toPath().normalize().startsWith(zipDir)) { + throw new IOException("Bad zip entry: '" + entryName + + "' in file '" + zipfile.getAbsolutePath() + "'!" + + " Cannot process this file or directory."); + } if (entry.isDirectory()) { - if (!new File(zipDir + entry.getName()).mkdirs()) { + if (!outFile.mkdirs()) { logError("Unable to create contents directory: " + zipDir + entry.getName()); } } else { - String entryName = entry.getName(); - File outFile = new File(zipDir + entryName); - // Verify that this file will be extracted into our zipDir (and not somewhere else!) - if (!outFile.toPath().normalize().startsWith(zipDir)) { - throw new IOException("Bad zip entry: '" + entryName - + "' in file '" + zipfile.getAbsolutePath() + "'!" - + " Cannot process this file."); - } else { - logInfo("Extracting file: " + entryName); + logInfo("Extracting file: " + entryName); - int index = entryName.lastIndexOf('/'); - if (index == -1) { - // Was it created on Windows instead? - index = entryName.lastIndexOf('\\'); + int index = entryName.lastIndexOf('/'); + if (index == -1) { + // Was it created on Windows instead? + index = entryName.lastIndexOf('\\'); + } + if (index > 0) { + File dir = new File(zipDir + entryName.substring(0, index)); + if (!dir.exists() && !dir.mkdirs()) { + logError("Unable to create directory: " + dir.getAbsolutePath()); } - if (index > 0) { - File dir = new File(zipDir + entryName.substring(0, index)); - if (!dir.exists() && !dir.mkdirs()) { - logError("Unable to create directory: " + dir.getAbsolutePath()); - } - //Entries could have too many directories, and we need to adjust the sourcedir - // file1.zip (SimpleArchiveFormat / item1 / contents|dublin_core|... - // SimpleArchiveFormat / item2 / contents|dublin_core|... - // or - // file2.zip (item1 / contents|dublin_core|... - // item2 / contents|dublin_core|... - - //regex supports either windows or *nix file paths - String[] entryChunks = entryName.split("/|\\\\"); - if (entryChunks.length > 2) { - if (StringUtils.equals(sourceDirForZip, sourcedir)) { - sourceDirForZip = sourcedir + "/" + entryChunks[0]; - } + //Entries could have too many directories, and we need to adjust the sourcedir + // file1.zip (SimpleArchiveFormat / item1 / contents|dublin_core|... + // SimpleArchiveFormat / item2 / contents|dublin_core|... + // or + // file2.zip (item1 / contents|dublin_core|... + // item2 / contents|dublin_core|... + + //regex supports either windows or *nix file paths + String[] entryChunks = entryName.split("/|\\\\"); + if (entryChunks.length > 2) { + if (StringUtils.equals(sourceDirForZip, sourcedir)) { + sourceDirForZip = sourcedir + "/" + entryChunks[0]; } } - byte[] buffer = new byte[1024]; - int len; - InputStream in = zf.getInputStream(entry); - BufferedOutputStream out = new BufferedOutputStream( - new FileOutputStream(outFile)); - while ((len = in.read(buffer)) >= 0) { - out.write(buffer, 0, len); - } - in.close(); - out.close(); } + byte[] buffer = new byte[1024]; + int len; + InputStream in = zf.getInputStream(entry); + BufferedOutputStream out = new BufferedOutputStream( + new FileOutputStream(outFile)); + while ((len = in.read(buffer)) >= 0) { + out.write(buffer, 0, len); + } + in.close(); + out.close(); } } } finally { From cbfe0beede1b969698db89b7fccca60412930946 Mon Sep 17 00:00:00 2001 From: Xiqinger <163422483+Xiqinger@users.noreply.github.com> Date: Tue, 26 Mar 2024 22:54:00 +0800 Subject: [PATCH 154/230] Add empty check before call iterator().next() (cherry picked from commit b2663c810c2372c7ab841fc223d3ecd0d6823ba0) --- .../app/itemupdate/DeleteBitstreamsAction.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java index cb5dcfb75dc0..65157f5207e7 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java @@ -70,16 +70,19 @@ public void execute(Context context, ItemArchive itarch, boolean isTest, } } - if (alterProvenance) { + if (alterProvenance && !bundles.isEmpty()) { DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", ""); String append = "Bitstream " + bs.getName() + " deleted on " + DCDate .getCurrent() + "; "; - Item item = bundles.iterator().next().getItems().iterator().next(); - ItemUpdate.pr("Append provenance with: " + append); + List items = bundles.iterator().next().getItems(); + if (!items.isEmpty()) { + Item item = items.iterator().next(); + ItemUpdate.pr("Append provenance with: " + append); - if (!isTest) { - MetadataUtilities.appendMetadata(context, item, dtom, false, append); + if (!isTest) { + MetadataUtilities.appendMetadata(context, item, dtom, false, append); + } } } } From 1920101273933a3b0310ae696c3a5ef369ce70e0 Mon Sep 17 00:00:00 2001 From: Xiqinger <163422483+Xiqinger@users.noreply.github.com> Date: Tue, 26 Mar 2024 23:08:13 +0800 Subject: [PATCH 155/230] avoid outputStream write after close (cherry picked from commit 214568d480782a4792aebb916403930d61d13052) --- .../CreativeCommonsRDFStreamDisseminationCrosswalk.java | 1 - .../CreativeCommonsTextStreamDisseminationCrosswalk.java | 1 - .../content/crosswalk/LicenseStreamDisseminationCrosswalk.java | 1 - .../org/dspace/content/packager/AbstractMETSDisseminator.java | 1 + .../src/main/java/org/dspace/subscriptions/ContentGenerator.java | 1 + 5 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java index 9042a3a7f523..0528c0c20570 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java @@ -59,7 +59,6 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out) Bitstream cc = creativeCommonsService.getLicenseRdfBitstream((Item) dso); if (cc != null) { Utils.copy(bitstreamService.retrieve(context, cc), out); - out.close(); } } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java index edb9d60a623e..cd26b4d19cee 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java @@ -65,7 +65,6 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out) Bitstream cc = creativeCommonsService.getLicenseTextBitstream((Item) dso); if (cc != null) { Utils.copy(bitstreamService.retrieve(context, cc), out); - out.close(); } } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java index 75b884613db9..46858747870d 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java @@ -57,7 +57,6 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out) if (licenseBs != null) { Utils.copy(bitstreamService.retrieve(context, licenseBs), out); - out.close(); } } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java index 685fd9000da8..fd50ec8023e2 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java @@ -628,6 +628,7 @@ protected MdSec makeMdSec(Context context, DSpaceObject dso, Class mdSecClass, // Disseminate crosswalk output to an outputstream ByteArrayOutputStream disseminateOutput = new ByteArrayOutputStream(); sxwalk.disseminate(context, dso, disseminateOutput); + disseminateOutput.close(); // Convert output to an inputstream, so we can write to manifest or Zip file ByteArrayInputStream crosswalkedStream = new ByteArrayInputStream( disseminateOutput.toByteArray()); diff --git a/dspace-api/src/main/java/org/dspace/subscriptions/ContentGenerator.java b/dspace-api/src/main/java/org/dspace/subscriptions/ContentGenerator.java index c3035614343b..e8f6996cbde8 100644 --- a/dspace-api/src/main/java/org/dspace/subscriptions/ContentGenerator.java +++ b/dspace-api/src/main/java/org/dspace/subscriptions/ContentGenerator.java @@ -89,6 +89,7 @@ private String generateBodyMail(Context context, List indexable .orElseGet(() -> entityType2Disseminator.get("Item")) .disseminate(context, item, out); } + out.close(); return out.toString(); } catch (Exception e) { log.error(e.getMessage(), e); From d6f6444f5891761626695b732721a2de8ae85e40 Mon Sep 17 00:00:00 2001 From: nwoodward Date: Fri, 5 Apr 2024 14:22:23 -0500 Subject: [PATCH 156/230] updated query to get collections referenced in the subscribers table (cherry picked from commit c5989c65bbfa587c173a222e71966ec073a9222c) --- .../java/org/dspace/content/dao/impl/CollectionDAOImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java index c0ef6ea42fce..e07da9f44490 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java @@ -159,7 +159,8 @@ public List findAuthorizedByGroup(Context context, EPerson ePerson, @Override public List findCollectionsWithSubscribers(Context context) throws SQLException { - return list(createQuery(context, "SELECT DISTINCT col FROM Subscription s join s.collection col")); + return list(createQuery(context, "SELECT c FROM Collection c JOIN Subscription s ON c.id = " + + "s.dSpaceObject")); } @Override From 1da7c6b93317ae68203cc8c1c854ca85519e0588 Mon Sep 17 00:00:00 2001 From: nwoodward Date: Thu, 11 Apr 2024 11:01:21 -0500 Subject: [PATCH 157/230] make sure collections list is unique (cherry picked from commit d27331a0b3ab4fba393f697e9cb48fc8b9760894) --- .../java/org/dspace/content/dao/impl/CollectionDAOImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java index e07da9f44490..befa1397a8ee 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java @@ -159,7 +159,7 @@ public List findAuthorizedByGroup(Context context, EPerson ePerson, @Override public List findCollectionsWithSubscribers(Context context) throws SQLException { - return list(createQuery(context, "SELECT c FROM Collection c JOIN Subscription s ON c.id = " + + return list(createQuery(context, "SELECT DISTINCT c FROM Collection c JOIN Subscription s ON c.id = " + "s.dSpaceObject")); } From 4d54f74ae139bd6c837648c67c9dca2dfad0acff Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 29 Feb 2024 14:06:54 +0100 Subject: [PATCH 158/230] trim trailing whitespaces in search query (cherry picked from commit 43e2a1d402139f32b2e239172e5636b62798eae1) --- .../CrossRefImportMetadataSourceServiceImpl.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java index 71b088ff162b..f4cdb4e61602 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java @@ -192,8 +192,9 @@ private SearchByIdCallable(String id) { @Override public List call() throws Exception { List results = new ArrayList<>(); + URIBuilder uriBuilder = new URIBuilder(url); String ID = URLDecoder.decode(query.getParameterAsClass("id", String.class), "UTF-8"); - URIBuilder uriBuilder = new URIBuilder(url + "/" + ID); + uriBuilder.setPath(uriBuilder.getPath() + "/" + ID); Map> params = new HashMap>(); String responseString = liveImportClient.executeHttpGetRequest(1000, uriBuilder.toString(), params); JsonNode jsonNode = convertStringJsonToJsonNode(responseString); @@ -277,7 +278,7 @@ private class CountByQueryCallable implements Callable { private CountByQueryCallable(String queryString) { query = new Query(); - query.addParameter("query", queryString); + query.addParameter("query", StringUtils.trim(queryString)); } private CountByQueryCallable(Query query) { @@ -308,7 +309,7 @@ private class DoiCheckCallable implements Callable { private DoiCheckCallable(final String id) { final Query query = new Query(); - query.addParameter("id", id); + query.addParameter("id", StringUtils.trim(id)); this.query = query; } @@ -319,7 +320,8 @@ private DoiCheckCallable(final Query query) { @Override public Integer call() throws Exception { Map> params = new HashMap>(); - URIBuilder uriBuilder = new URIBuilder(url + "/" + query.getParameterAsClass("id", String.class)); + URIBuilder uriBuilder = new URIBuilder(url); + uriBuilder.setPath(uriBuilder.getPath() + "/" + query.getParameterAsClass("id", String.class)); String responseString = liveImportClient.executeHttpGetRequest(1000, uriBuilder.toString(), params); JsonNode jsonNode = convertStringJsonToJsonNode(responseString); return StringUtils.equals(jsonNode.at("/status").toString(), "ok") ? 1 : 0; From cef170ad121f82047ad61b7d4bf5910a04be6632 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 29 Feb 2024 14:44:51 +0100 Subject: [PATCH 159/230] extend trimming (cherry picked from commit 2c6f43d48f4527f41e54d4c41fa8ddd232960bd0) --- .../crossref/CrossRefImportMetadataSourceServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java index f4cdb4e61602..419f6ca8a085 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java @@ -133,7 +133,7 @@ private class SearchByQueryCallable implements Callable> { private SearchByQueryCallable(String queryString, Integer maxResult, Integer start) { query = new Query(); - query.addParameter("query", queryString); + query.addParameter("query", StringUtils.trim(queryString)); query.addParameter("count", maxResult); query.addParameter("start", start); } @@ -186,7 +186,7 @@ private SearchByIdCallable(Query query) { private SearchByIdCallable(String id) { this.query = new Query(); - query.addParameter("id", id); + query.addParameter("id", StringUtils.trim(id)); } @Override From 1606862aa38cbf2a387dfeade1055b71fc0fc255 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 29 Feb 2024 14:19:25 +0100 Subject: [PATCH 160/230] add processor to handle CrossRef abstracts (cherry picked from commit 498d1379701e670c276b3daf104d2069c965c9c0) --- dspace/config/spring/api/crossref-integration.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dspace/config/spring/api/crossref-integration.xml b/dspace/config/spring/api/crossref-integration.xml index d1e416d2b0c6..4786c44a7865 100644 --- a/dspace/config/spring/api/crossref-integration.xml +++ b/dspace/config/spring/api/crossref-integration.xml @@ -132,8 +132,11 @@ - + + + + From a000f1430a4a150c0ac46667ea60a97c5265f781 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 29 Feb 2024 14:22:49 +0100 Subject: [PATCH 161/230] add CrossRefAbstractProcessor (cherry picked from commit fa3f10e0b632b0e6bcc344193cbefeead3edb0f7) --- .../crossref/CrossRefAbstractProcessor.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java new file mode 100644 index 000000000000..689c4e587028 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java @@ -0,0 +1,117 @@ +package org.dspace.importer.external.crossref; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dspace.importer.external.metadatamapping.contributor.JsonPathMetadataProcessor; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collection; + +public class CrossRefAbstractProcessor implements JsonPathMetadataProcessor { + + private final static Logger log = LogManager.getLogger(); + + private String path; + + @Override + public Collection processMetadata(String json) { + JsonNode rootNode = convertStringJsonToJsonNode(json); + JsonNode abstractNode = rootNode.at(path); + Collection values = new ArrayList<>(); + if (!abstractNode.isMissingNode()) { + String abstractValue = abstractNode.textValue(); + if (StringUtils.isNotEmpty(abstractValue)) { + abstractValue = prettifyAbstract(abstractValue); + if (abstractValue != null) { + values.add(abstractValue); + } + } + } + return values; + } + + /** + * remove JATS markup from abstract + * + * @param abstractValue abstract with JATS markup + * @return abstract without JATS markup + */ + private String prettifyAbstract(String abstractValue) { + if (!abstractValue.contains(""; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + Document xmlDoc; + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + InputSource is = new InputSource(new StringReader(xmlString)); + xmlDoc = builder.parse(is); + } catch (SAXException | IOException | ParserConfigurationException e) { + log.warn("unable to parse XML markup in CrossRef abstract field: " + e.getMessage()); + return null; + } + + StringBuilder sb = new StringBuilder(); + + NodeList rootElements = xmlDoc.getElementsByTagName("root"); + Node rootElement = rootElements.item(0); + NodeList childElements = rootElement.getChildNodes(); + for (int i = 0; i < childElements.getLength(); i++) { + Node childElement = childElements.item(i); + String nodeName = childElement.getNodeName(); + if (StringUtils.equals(nodeName, "jats:title")) { + if (! StringUtils.equals(childElement.getTextContent(), "Abstract")) { + sb.append(childElement.getTextContent()); + sb.append("\n"); + } + } + else if (StringUtils.equals(nodeName, "jats:sec")) { + NodeList secElements = childElement.getChildNodes(); + for (int j = 0; j < secElements.getLength(); j++) { + Node secChildElement = secElements.item(j); + sb.append(secChildElement.getTextContent()); + sb.append("\n"); + } + sb.append("\n"); + } + } + + return sb.toString().trim(); + } + + private JsonNode convertStringJsonToJsonNode(String json) { + ObjectMapper mapper = new ObjectMapper(); + JsonNode body = null; + try { + body = mapper.readTree(json); + } catch (JsonProcessingException e) { + log.error("Unable to process json response.", e); + } + return body; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} From 6b57079569abddf8e7de7726fac850f5608925b7 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 29 Feb 2024 14:52:07 +0100 Subject: [PATCH 162/230] add header in class file (cherry picked from commit b7720043974fbbadf104b37798fefaf619e58e5e) --- .../external/crossref/CrossRefAbstractProcessor.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java index 689c4e587028..b774e07fc86e 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java @@ -1,3 +1,10 @@ +/** + * 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.importer.external.crossref; import com.fasterxml.jackson.core.JsonProcessingException; From 71798f0f743353a7bcc1a8828a1b1b215e338e79 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 29 Feb 2024 20:52:24 +0100 Subject: [PATCH 163/230] fix code style violations (cherry picked from commit 23b8b696a078000c06c56a9608defdaef36318c5) --- .../crossref/CrossRefAbstractProcessor.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java index b774e07fc86e..21c702aeabac 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java @@ -7,6 +7,14 @@ */ package org.dspace.importer.external.crossref; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collection; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -20,14 +28,6 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Collection; - public class CrossRefAbstractProcessor implements JsonPathMetadataProcessor { private final static Logger log = LogManager.getLogger(); @@ -88,8 +88,7 @@ private String prettifyAbstract(String abstractValue) { sb.append(childElement.getTextContent()); sb.append("\n"); } - } - else if (StringUtils.equals(nodeName, "jats:sec")) { + } else if (StringUtils.equals(nodeName, "jats:sec")) { NodeList secElements = childElement.getChildNodes(); for (int j = 0; j < secElements.getLength(); j++) { Node secChildElement = secElements.item(j); From 263b45046cc8068221b668c64f3722576e823498 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 29 Feb 2024 21:07:02 +0100 Subject: [PATCH 164/230] sort imports lexicographically (cherry picked from commit 2867b36ebb0aeb67f8fda70cc72bd9a7dc88a6c5) --- .../external/crossref/CrossRefAbstractProcessor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java index 21c702aeabac..1b6da9d37b16 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java @@ -7,13 +7,13 @@ */ package org.dspace.importer.external.crossref; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; From e22f9a211f789d4cd218c70a78fc4dae2255bf15 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 6 May 2024 10:09:23 -0500 Subject: [PATCH 165/230] Upgrade Tika and bcprov-jdk18on to latest versions. Synced other dependencies with versions used on `main` (where possible to do so) --- pom.xml | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 9f8f8f247024..82718c0f3e9e 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 5.7.11 5.6.15.Final 6.2.5.Final - 42.7.2 + 42.7.3 8.11.3 3.10.8 @@ -38,13 +38,13 @@ 1.1.1 9.4.54.v20240208 - 2.22.1 - 2.0.30 + 2.23.1 + 2.0.31 1.19.0 1.7.36 - 2.5.0 + 2.9.2 - 1.70 + 1.78.1 @@ -1295,13 +1295,19 @@ org.bouncycastle - bcpkix-jdk15on + bcpkix-jdk18on ${bouncycastle.version} org.bouncycastle - bcprov-jdk15on + bcprov-jdk18on + ${bouncycastle.version} + + + + org.bouncycastle + bcutil-jdk18on ${bouncycastle.version} @@ -1502,13 +1508,18 @@ commons-lang3 3.14.0 - + commons-logging commons-logging 1.3.0 + + org.apache.commons + commons-compress + 1.26.0 + org.apache.commons commons-pool2 From dbf063dfb9aff359f0ec153497f2a58b5d189258 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 6 May 2024 12:24:13 -0500 Subject: [PATCH 166/230] Ensure potentially large Solr query uses POST, not GET (cherry picked from commit 0a21a11c9a88f0b87b05ea2fe4ba619a15daaf10) --- .../src/main/java/org/dspace/content/EntityTypeServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java index 0e0c6d51e501..b5b066d9c36f 100644 --- a/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java @@ -148,7 +148,7 @@ public List getSubmitAuthorizedTypes(Context context) sQuery.setFacetMinCount(1); sQuery.setFacetLimit(Integer.MAX_VALUE); sQuery.setFacetSort(FacetParams.FACET_SORT_INDEX); - QueryResponse qResp = solrSearchCore.getSolr().query(sQuery); + QueryResponse qResp = solrSearchCore.getSolr().query(sQuery, solrSearchCore.REQUEST_METHOD); FacetField facetField = qResp.getFacetField("search.entitytype"); if (Objects.nonNull(facetField)) { for (Count c : facetField.getValues()) { From 606b10ccb76ef7307164142adce5bcf59829ac9e Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 7 May 2024 17:16:33 -0500 Subject: [PATCH 167/230] Add migration to set user_id to null if EPerson no longer exists & enforce it for future (cherry picked from commit ef24645cbf31ed1572f98669e883033d65fc6c4d) --- .../V7.6_2024.05.07__process_eperson_constraint.sql | 13 +++++++++++++ .../V7.6_2024.05.07__process_eperson_constraint.sql | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.05.07__process_eperson_constraint.sql create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.05.07__process_eperson_constraint.sql diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.05.07__process_eperson_constraint.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.05.07__process_eperson_constraint.sql new file mode 100644 index 000000000000..26de16f466ee --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.05.07__process_eperson_constraint.sql @@ -0,0 +1,13 @@ +-- +-- 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/ +-- + +-- If Process references an EPerson that no longer exists, set the "user_id" to null. +UPDATE process SET user_id = null WHERE NOT EXISTS (SELECT * FROM EPerson where uuid = process.user_id); + +-- Add new constraint where process.user_id is nullified if referenced EPerson is deleted. +ALTER TABLE process ADD CONSTRAINT process_eperson FOREIGN KEY (user_id) REFERENCES EPerson(uuid) ON DELETE SET NULL; diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.05.07__process_eperson_constraint.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.05.07__process_eperson_constraint.sql new file mode 100644 index 000000000000..26de16f466ee --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.05.07__process_eperson_constraint.sql @@ -0,0 +1,13 @@ +-- +-- 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/ +-- + +-- If Process references an EPerson that no longer exists, set the "user_id" to null. +UPDATE process SET user_id = null WHERE NOT EXISTS (SELECT * FROM EPerson where uuid = process.user_id); + +-- Add new constraint where process.user_id is nullified if referenced EPerson is deleted. +ALTER TABLE process ADD CONSTRAINT process_eperson FOREIGN KEY (user_id) REFERENCES EPerson(uuid) ON DELETE SET NULL; From 448a69483bf0bce10b58cfc3d3bdb37dda6d3e6c Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 7 May 2024 17:17:00 -0500 Subject: [PATCH 168/230] Fix NullPointerException. Only return userid if EPerson not null (cherry picked from commit f34c592352bf64383721d489afcb6846000e290e) --- .../java/org/dspace/app/rest/converter/ProcessConverter.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java index 38eaf4204798..54231132d769 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java @@ -14,7 +14,6 @@ import org.dspace.app.rest.projection.Projection; import org.dspace.scripts.Process; import org.dspace.scripts.service.ProcessService; -import org.hibernate.ObjectNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -40,10 +39,8 @@ public ProcessRest convert(Process process, Projection projection) { processRest.setId(process.getID()); processRest.setScriptName(process.getName()); processRest.setProcessId(process.getID()); - try { + if (process.getEPerson() != null) { processRest.setUserId(process.getEPerson().getID()); - } catch (ObjectNotFoundException e ) { - processRest.setUserId(null); } processRest.setProcessStatus(process.getProcessStatus()); processRest.setStartTime(process.getStartTime()); From 1b091a033e6ce2b043cd5482a97108d2f87316c7 Mon Sep 17 00:00:00 2001 From: Nona Luypaert Date: Tue, 12 Mar 2024 15:50:11 +0100 Subject: [PATCH 169/230] Fix OAIHarvester#extractHandle not handling config properly - defaults for oai.harvester.acceptedHandleServer and oai.harvester.rejectedHandlePrefix are now set - rejected handles no longer pass if multiple prefixes were configured for oai.harvester.rejectedHandlePrefix (cherry picked from commit 862a6c5be6f6abf7f91c50ce387fbc468fa29081) --- .../java/org/dspace/harvest/OAIHarvester.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java index 5aeb40bdd912..1b8d0002ce2c 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java +++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java @@ -16,6 +16,7 @@ import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Date; @@ -683,15 +684,11 @@ protected void processRecord(Element record, String OREPrefix, final long curren * @return null or the handle to be used. */ protected String extractHandle(Item item) { - String[] acceptedHandleServers = configurationService.getArrayProperty("oai.harvester.acceptedHandleServer"); - if (acceptedHandleServers == null) { - acceptedHandleServers = new String[] {"hdl.handle.net"}; - } + String[] acceptedHandleServers = configurationService + .getArrayProperty("oai.harvester.acceptedHandleServer", new String[] {"hdl.handle.net"}); - String[] rejectedHandlePrefixes = configurationService.getArrayProperty("oai.harvester.rejectedHandlePrefix"); - if (rejectedHandlePrefixes == null) { - rejectedHandlePrefixes = new String[] {"123456789"}; - } + String[] rejectedHandlePrefixes = configurationService + .getArrayProperty("oai.harvester.rejectedHandlePrefix", new String[] {"123456789"}); List values = itemService.getMetadata(item, "dc", "identifier", Item.ANY, Item.ANY); @@ -706,12 +703,9 @@ protected String extractHandle(Item item) { for (String server : acceptedHandleServers) { if (urlPieces[2].equals(server)) { - for (String prefix : rejectedHandlePrefixes) { - if (!urlPieces[3].equals(prefix)) { - return urlPieces[3] + "/" + urlPieces[4]; - } + if (Arrays.stream(rejectedHandlePrefixes).noneMatch(prefix -> prefix.equals(urlPieces[3]))) { + return urlPieces[3] + "/" + urlPieces[4]; } - } } } From 532e21ffb9072178b3e299b66327a425a3a4f06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Wed, 8 May 2024 15:22:56 -0400 Subject: [PATCH 170/230] Updated CheckStyle so that new Java features such as string blocks are supported, but without requiring to change anything else (cherry picked from commit ef8c621a0fdf0ced3c13d8a1b93522dee5b4f421) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 82718c0f3e9e..f7ce30b30df1 100644 --- a/pom.xml +++ b/pom.xml @@ -287,7 +287,7 @@ com.puppycrawl.tools checkstyle - 8.30 + 8.38 From 2fdc422b249993045e8b905a9f2ea0826a355b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Gra=C3=A7a?= Date: Thu, 9 May 2024 14:39:51 +0100 Subject: [PATCH 171/230] change IT from organisation to organization --- .../java/org/dspace/app/rest/DiscoveryRestControllerIT.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java index 80d8ab2df422..c70b214731f0 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java @@ -1277,11 +1277,11 @@ public void checkSortOrderInPersonOrOrgunitConfigurationTest() throws Exception DiscoverySortFieldConfiguration.SORT_ORDER.desc.name()), SortOptionMatcher.sortOptionMatcher("organization.legalName", DiscoverySortFieldConfiguration.SORT_ORDER.asc.name()), - SortOptionMatcher.sortOptionMatcher("organisation.address.addressCountry", + SortOptionMatcher.sortOptionMatcher("organization.address.addressCountry", DiscoverySortFieldConfiguration.SORT_ORDER.asc.name()), - SortOptionMatcher.sortOptionMatcher("organisation.address.addressLocality", + SortOptionMatcher.sortOptionMatcher("organization.address.addressLocality", DiscoverySortFieldConfiguration.SORT_ORDER.asc.name()), - SortOptionMatcher.sortOptionMatcher("organisation.foundingDate", + SortOptionMatcher.sortOptionMatcher("organization.foundingDate", DiscoverySortFieldConfiguration.SORT_ORDER.desc.name()), SortOptionMatcher.sortOptionMatcher("dc.date.accessioned", DiscoverySortFieldConfiguration.SORT_ORDER.desc.name()), From 31020d1d4ff0d2af6baf9adb32b4bb2fef753b1e Mon Sep 17 00:00:00 2001 From: Roy Bruschini Date: Mon, 25 Mar 2024 16:52:55 +0100 Subject: [PATCH 172/230] Create templates mail and renamed name in getEmailFileName (cherry picked from commit 7a637e6871134a3d81cc9abbbe158090bdcec6f0) --- .../app/itemimport/ItemImportServiceImpl.java | 4 ++-- dspace/config/emails/batch_import_error | 19 +++++++++++++++++++ dspace/config/emails/batch_import_success | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 dspace/config/emails/batch_import_error create mode 100644 dspace/config/emails/batch_import_success 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 cd55e97a6356..1e219ee6314c 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 @@ -2234,7 +2234,7 @@ public void emailSuccessMessage(Context context, EPerson eperson, String fileName) throws MessagingException { try { Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); - Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "bte_batch_import_success")); + Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "batch_import_success")); email.addRecipient(eperson.getEmail()); email.addArgument(fileName); @@ -2250,7 +2250,7 @@ public void emailErrorMessage(EPerson eperson, String error) logError("An error occurred during item import, the user will be notified. " + error); try { Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); - Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "bte_batch_import_error")); + Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "batch_import_error")); email.addRecipient(eperson.getEmail()); email.addArgument(error); email.addArgument(configurationService.getProperty("dspace.ui.url") + "/feedback"); diff --git a/dspace/config/emails/batch_import_error b/dspace/config/emails/batch_import_error new file mode 100644 index 000000000000..2e2a2b742720 --- /dev/null +++ b/dspace/config/emails/batch_import_error @@ -0,0 +1,19 @@ +## Email sent to DSpace users when they batch import fails. +## +## Parameters: {0} the export error +## {1} the URL to the feedback page +## +## +## See org.dspace.core.Email for information on the format of this file. +## +#set($subject = 'DSpace - The batch import was not completed.') +The batch import you initiated from the DSpace UI was not completed, due to the following reason: + ${params[0]} + +For more information you may contact your system administrator: + ${params[1]} + + + +The DSpace Team + diff --git a/dspace/config/emails/batch_import_success b/dspace/config/emails/batch_import_success new file mode 100644 index 000000000000..7e9fdbf7416a --- /dev/null +++ b/dspace/config/emails/batch_import_success @@ -0,0 +1,16 @@ + +## Email sent to DSpace users when they successfully batch import items. +## +## Parameters: {0} the filepath to the mapfile created by the batch import +## +## +## See org.dspace.core.Email for information on the format of this file. +## +#set($subject = 'DSpace - Batch import successfully completed') +The batch item import you initiated from the DSpace UI has completed successfully. + +You may find the mapfile for the import in the following path: ${params[0]} + + +The DSpace Team + From d90cf24a21a47268e710392985994e9a385ac23a Mon Sep 17 00:00:00 2001 From: Roy Bruschini Date: Mon, 25 Mar 2024 16:55:43 +0100 Subject: [PATCH 173/230] Fix typo (cherry picked from commit 74c15e8d55c88e68bb7d7f716deffe5409922868) --- dspace/config/emails/batch_import_error | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace/config/emails/batch_import_error b/dspace/config/emails/batch_import_error index 2e2a2b742720..2c62d72bf9c9 100644 --- a/dspace/config/emails/batch_import_error +++ b/dspace/config/emails/batch_import_error @@ -1,4 +1,4 @@ -## Email sent to DSpace users when they batch import fails. +## Email sent to DSpace users when their batch import fails. ## ## Parameters: {0} the export error ## {1} the URL to the feedback page From ca27ea5fc2b071b6bfe76ba6de6715e6577f237d Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Thu, 9 May 2024 17:42:21 +0200 Subject: [PATCH 174/230] Remove not unique id from inner beans to avoid xml validation issues (cherry picked from commit 844b73ff4903ef59b2a69f438b5bec207a63ead4) --- .../data/dspaceFolder/config/spring/api/item-filters.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dspace-api/src/test/data/dspaceFolder/config/spring/api/item-filters.xml b/dspace-api/src/test/data/dspaceFolder/config/spring/api/item-filters.xml index 836d4f089677..4107202be566 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/spring/api/item-filters.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/spring/api/item-filters.xml @@ -295,8 +295,7 @@ - + @@ -352,8 +351,7 @@ - + From 2976ae397167a5969481c109894d6482b8e90f93 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Fri, 10 May 2024 16:41:09 +0200 Subject: [PATCH 175/230] bugfix: array index can be out of bound (cherry picked from commit 4fc6b07466a7b131fe61f62b8585087c3697afb5) --- .../crosswalk/SubscriptionDsoMetadataForEmailCompose.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/SubscriptionDsoMetadataForEmailCompose.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/SubscriptionDsoMetadataForEmailCompose.java index 05fda2b97475..ad92018b2220 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/SubscriptionDsoMetadataForEmailCompose.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/SubscriptionDsoMetadataForEmailCompose.java @@ -49,7 +49,7 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out) thr for (String actualMetadata : metadata) { String[] splitted = actualMetadata.split("\\."); String qualifier = null; - if (splitted.length == 1) { + if (splitted.length == 3) { qualifier = splitted[2]; } var metadataValue = itemService.getMetadataFirstValue(item, splitted[0], splitted[1], qualifier, ANY); From d14f1130241fc312d94f9df1cedc98bf32e207ad Mon Sep 17 00:00:00 2001 From: "Gantner, Florian Klaus" Date: Thu, 7 Mar 2024 15:31:03 +0100 Subject: [PATCH 176/230] use datacite api response for recordscount and paginated calls. update test file for response as expected from the api. (cherry picked from commit 65ac01a4a655176351b0a74a8daf5b701a418d35) --- ...taCiteImportMetadataSourceServiceImpl.java | 39 ++++++++++++++++++- .../org/dspace/app/rest/dataCite-test.json | 2 +- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java index a11f2bc2471d..298c30ec39a5 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java @@ -73,8 +73,32 @@ public ImportRecord getRecord(String recordId) throws MetadataSourceException { @Override public int getRecordsCount(String query) throws MetadataSourceException { - Collection records = getRecords(query, 0, -1); - return records == null ? 0 : records.size(); + String id = getID(query); + Map> params = new HashMap<>(); + Map uriParameters = new HashMap<>(); + params.put("uriParameters", uriParameters); + if (StringUtils.isBlank(id)) { + id = query; + } + uriParameters.put("query", id); + uriParameters.put("page[size]", "1"); + int timeoutMs = configurationService.getIntProperty("datacite.timeout", 180000); + String url = configurationService.getProperty("datacite.url", "https://api.datacite.org/dois/"); + String responseString = liveImportClient.executeHttpGetRequest(timeoutMs, url, params); + JsonNode jsonNode = convertStringJsonToJsonNode(responseString); + if (jsonNode == null) { + log.warn("DataCite returned invalid JSON"); + throw new MetadataSourceException("Could not read datacite source"); + } + JsonNode dataNode = jsonNode.at("/meta/total"); + if (dataNode != null) { + try { + return Integer.valueOf(dataNode.toString()); + } catch (Exception e) { + log.debug("Could not read integer value" + dataNode.toString()); + } + } + return 0; } @Override @@ -95,6 +119,17 @@ public Collection getRecords(String query, int start, int count) t id = query; } uriParameters.put("query", id); + // start = current dspace page / datacite page number starting with 1 + // dspace rounds up/down to the next configured pagination settings. + if (start > 0 && count > 0) { + uriParameters.put("page[number]", Integer.toString((start / count) + 1)); + } + + // count = dspace page size / default datacite page size is currently 25 https://support.datacite.org/docs/pagination + if (count > 0) { + uriParameters.put("page[size]", Integer.toString(count)); + } + int timeoutMs = configurationService.getIntProperty("datacite.timeout", 180000); String url = configurationService.getProperty("datacite.url", "https://api.datacite.org/dois/"); String responseString = liveImportClient.executeHttpGetRequest(timeoutMs, url, params); diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-test.json b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-test.json index 8ede6f29a08e..1b7f63cd89c0 100644 --- a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-test.json +++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-test.json @@ -1 +1 @@ -{"data":{"id":"10.48550/arxiv.2207.04779","type":"dois","attributes":{"doi":"10.48550/arxiv.2207.04779","prefix":"10.48550","suffix":"arxiv.2207.04779","identifiers":[{"identifier":"2207.04779","identifierType":"arXiv"}],"alternateIdentifiers":[{"alternateIdentifierType":"arXiv","alternateIdentifier":"2207.04779"}],"creators":[{"name":"Bayer, Jonas","nameType":"Personal","givenName":"Jonas","familyName":"Bayer","affiliation":[],"nameIdentifiers":[]},{"name":"Benzmüller, Christoph","nameType":"Personal","givenName":"Christoph","familyName":"Benzmüller","affiliation":[],"nameIdentifiers":[]},{"name":"Buzzard, Kevin","nameType":"Personal","givenName":"Kevin","familyName":"Buzzard","affiliation":[],"nameIdentifiers":[]},{"name":"David, Marco","nameType":"Personal","givenName":"Marco","familyName":"David","affiliation":[],"nameIdentifiers":[]},{"name":"Lamport, Leslie","nameType":"Personal","givenName":"Leslie","familyName":"Lamport","affiliation":[],"nameIdentifiers":[]},{"name":"Matiyasevich, Yuri","nameType":"Personal","givenName":"Yuri","familyName":"Matiyasevich","affiliation":[],"nameIdentifiers":[]},{"name":"Paulson, Lawrence","nameType":"Personal","givenName":"Lawrence","familyName":"Paulson","affiliation":[],"nameIdentifiers":[]},{"name":"Schleicher, Dierk","nameType":"Personal","givenName":"Dierk","familyName":"Schleicher","affiliation":[],"nameIdentifiers":[]},{"name":"Stock, Benedikt","nameType":"Personal","givenName":"Benedikt","familyName":"Stock","affiliation":[],"nameIdentifiers":[]},{"name":"Zelmanov, Efim","nameType":"Personal","givenName":"Efim","familyName":"Zelmanov","affiliation":[],"nameIdentifiers":[]}],"titles":[{"title":"Mathematical Proof Between Generations"}],"publisher":"arXiv","container":{},"publicationYear":2022,"subjects":[{"lang":"en","subject":"History and Overview (math.HO)","subjectScheme":"arXiv"},{"lang":"en","subject":"Logic in Computer Science (cs.LO)","subjectScheme":"arXiv"},{"subject":"FOS: Mathematics","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Mathematics","schemeUri":"http://www.oecd.org/science/inno/38235147.pdf","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Computer and information sciences","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Computer and information sciences","schemeUri":"http://www.oecd.org/science/inno/38235147.pdf","subjectScheme":"Fields of Science and Technology (FOS)"}],"contributors":[],"dates":[{"date":"2022-07-08T14:42:33Z","dateType":"Submitted","dateInformation":"v1"},{"date":"2022-07-13T00:14:24Z","dateType":"Updated","dateInformation":"v1"},{"date":"2022-07","dateType":"Available","dateInformation":"v1"},{"date":"2022","dateType":"Issued"}],"language":null,"types":{"ris":"GEN","bibtex":"misc","citeproc":"article","schemaOrg":"CreativeWork","resourceType":"Article","resourceTypeGeneral":"Preprint"},"relatedIdentifiers":[],"relatedItems":[],"sizes":[],"formats":[],"version":"1","rightsList":[{"rights":"arXiv.org perpetual, non-exclusive license","rightsUri":"http://arxiv.org/licenses/nonexclusive-distrib/1.0/"}],"descriptions":[{"description":"A proof is one of the most important concepts of mathematics. However, there is a striking difference between how a proof is defined in theory and how it is used in practice. This puts the unique status of mathematics as exact science into peril. Now may be the time to reconcile theory and practice, i.e. precision and intuition, through the advent of computer proof assistants. For the most time this has been a topic for experts in specialized communities. However, mathematical proofs have become increasingly sophisticated, stretching the boundaries of what is humanly comprehensible, so that leading mathematicians have asked for formal verification of their proofs. At the same time, major theorems in mathematics have recently been computer-verified by people from outside of these communities, even by beginning students. This article investigates the gap between the different definitions of a proof and possibilities to build bridges. It is written as a polemic or a collage by different members of the communities in mathematics and computer science at different stages of their careers, challenging well-known preconceptions and exploring new perspectives.","descriptionType":"Abstract"},{"description":"17 pages, 1 figure","descriptionType":"Other"}],"geoLocations":[],"fundingReferences":[],"xml":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHJlc291cmNlIHhtbG5zPSJodHRwOi8vZGF0YWNpdGUub3JnL3NjaGVtYS9rZXJuZWwtNCIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnNjaGVtYUxvY2F0aW9uPSJodHRwOi8vZGF0YWNpdGUub3JnL3NjaGVtYS9rZXJuZWwtNCBodHRwOi8vc2NoZW1hLmRhdGFjaXRlLm9yZy9tZXRhL2tlcm5lbC00LjMvbWV0YWRhdGEueHNkIj4KICA8aWRlbnRpZmllciBpZGVudGlmaWVyVHlwZT0iRE9JIj4xMC40ODU1MC9BUlhJVi4yMjA3LjA0Nzc5PC9pZGVudGlmaWVyPgogIDxhbHRlcm5hdGVJZGVudGlmaWVycz4KICAgIDxhbHRlcm5hdGVJZGVudGlmaWVyIGFsdGVybmF0ZUlkZW50aWZpZXJUeXBlPSJhclhpdiI+MjIwNy4wNDc3OTwvYWx0ZXJuYXRlSWRlbnRpZmllcj4KICA8L2FsdGVybmF0ZUlkZW50aWZpZXJzPgogIDxjcmVhdG9ycz4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5CYXllciwgSm9uYXM8L2NyZWF0b3JOYW1lPgogICAgICA8Z2l2ZW5OYW1lPkpvbmFzPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPkJheWVyPC9mYW1pbHlOYW1lPgogICAgPC9jcmVhdG9yPgogICAgPGNyZWF0b3I+CiAgICAgIDxjcmVhdG9yTmFtZSBuYW1lVHlwZT0iUGVyc29uYWwiPkJlbnptw7xsbGVyLCBDaHJpc3RvcGg8L2NyZWF0b3JOYW1lPgogICAgICA8Z2l2ZW5OYW1lPkNocmlzdG9waDwvZ2l2ZW5OYW1lPgogICAgICA8ZmFtaWx5TmFtZT5CZW56bcO8bGxlcjwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5CdXp6YXJkLCBLZXZpbjwvY3JlYXRvck5hbWU+CiAgICAgIDxnaXZlbk5hbWU+S2V2aW48L2dpdmVuTmFtZT4KICAgICAgPGZhbWlseU5hbWU+QnV6emFyZDwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5EYXZpZCwgTWFyY288L2NyZWF0b3JOYW1lPgogICAgICA8Z2l2ZW5OYW1lPk1hcmNvPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPkRhdmlkPC9mYW1pbHlOYW1lPgogICAgPC9jcmVhdG9yPgogICAgPGNyZWF0b3I+CiAgICAgIDxjcmVhdG9yTmFtZSBuYW1lVHlwZT0iUGVyc29uYWwiPkxhbXBvcnQsIExlc2xpZTwvY3JlYXRvck5hbWU+CiAgICAgIDxnaXZlbk5hbWU+TGVzbGllPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPkxhbXBvcnQ8L2ZhbWlseU5hbWU+CiAgICA8L2NyZWF0b3I+CiAgICA8Y3JlYXRvcj4KICAgICAgPGNyZWF0b3JOYW1lIG5hbWVUeXBlPSJQZXJzb25hbCI+TWF0aXlhc2V2aWNoLCBZdXJpPC9jcmVhdG9yTmFtZT4KICAgICAgPGdpdmVuTmFtZT5ZdXJpPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPk1hdGl5YXNldmljaDwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5QYXVsc29uLCBMYXdyZW5jZTwvY3JlYXRvck5hbWU+CiAgICAgIDxnaXZlbk5hbWU+TGF3cmVuY2U8L2dpdmVuTmFtZT4KICAgICAgPGZhbWlseU5hbWU+UGF1bHNvbjwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5TY2hsZWljaGVyLCBEaWVyazwvY3JlYXRvck5hbWU+CiAgICAgIDxnaXZlbk5hbWU+RGllcms8L2dpdmVuTmFtZT4KICAgICAgPGZhbWlseU5hbWU+U2NobGVpY2hlcjwvZmFtaWx5TmFtZT4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5TdG9jaywgQmVuZWRpa3Q8L2NyZWF0b3JOYW1lPgogICAgICA8Z2l2ZW5OYW1lPkJlbmVkaWt0PC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPlN0b2NrPC9mYW1pbHlOYW1lPgogICAgPC9jcmVhdG9yPgogICAgPGNyZWF0b3I+CiAgICAgIDxjcmVhdG9yTmFtZSBuYW1lVHlwZT0iUGVyc29uYWwiPlplbG1hbm92LCBFZmltPC9jcmVhdG9yTmFtZT4KICAgICAgPGdpdmVuTmFtZT5FZmltPC9naXZlbk5hbWU+CiAgICAgIDxmYW1pbHlOYW1lPlplbG1hbm92PC9mYW1pbHlOYW1lPgogICAgPC9jcmVhdG9yPgogIDwvY3JlYXRvcnM+CiAgPHRpdGxlcz4KICAgIDx0aXRsZT5NYXRoZW1hdGljYWwgUHJvb2YgQmV0d2VlbiBHZW5lcmF0aW9uczwvdGl0bGU+CiAgPC90aXRsZXM+CiAgPHB1Ymxpc2hlcj5hclhpdjwvcHVibGlzaGVyPgogIDxwdWJsaWNhdGlvblllYXI+MjAyMjwvcHVibGljYXRpb25ZZWFyPgogIDxzdWJqZWN0cz4KICAgIDxzdWJqZWN0IHhtbDpsYW5nPSJlbiIgc3ViamVjdFNjaGVtZT0iYXJYaXYiPkhpc3RvcnkgYW5kIE92ZXJ2aWV3IChtYXRoLkhPKTwvc3ViamVjdD4KICAgIDxzdWJqZWN0IHhtbDpsYW5nPSJlbiIgc3ViamVjdFNjaGVtZT0iYXJYaXYiPkxvZ2ljIGluIENvbXB1dGVyIFNjaWVuY2UgKGNzLkxPKTwvc3ViamVjdD4KICAgIDxzdWJqZWN0IHN1YmplY3RTY2hlbWU9IkZpZWxkcyBvZiBTY2llbmNlIGFuZCBUZWNobm9sb2d5IChGT1MpIj5GT1M6IE1hdGhlbWF0aWNzPC9zdWJqZWN0PgogICAgPHN1YmplY3Qgc3ViamVjdFNjaGVtZT0iRmllbGRzIG9mIFNjaWVuY2UgYW5kIFRlY2hub2xvZ3kgKEZPUykiPkZPUzogQ29tcHV0ZXIgYW5kIGluZm9ybWF0aW9uIHNjaWVuY2VzPC9zdWJqZWN0PgogIDwvc3ViamVjdHM+CiAgPGRhdGVzPgogICAgPGRhdGUgZGF0ZVR5cGU9IlN1Ym1pdHRlZCIgZGF0ZUluZm9ybWF0aW9uPSJ2MSI+MjAyMi0wNy0wOFQxNDo0MjozM1o8L2RhdGU+CiAgICA8ZGF0ZSBkYXRlVHlwZT0iVXBkYXRlZCIgZGF0ZUluZm9ybWF0aW9uPSJ2MSI+MjAyMi0wNy0xM1QwMDoxNDoyNFo8L2RhdGU+CiAgICA8ZGF0ZSBkYXRlVHlwZT0iQXZhaWxhYmxlIiBkYXRlSW5mb3JtYXRpb249InYxIj4yMDIyLTA3PC9kYXRlPgogIDwvZGF0ZXM+CiAgPHJlc291cmNlVHlwZSByZXNvdXJjZVR5cGVHZW5lcmFsPSJQcmVwcmludCI+QXJ0aWNsZTwvcmVzb3VyY2VUeXBlPgogIDx2ZXJzaW9uPjE8L3ZlcnNpb24+CiAgPHJpZ2h0c0xpc3Q+CiAgICA8cmlnaHRzIHJpZ2h0c1VSST0iaHR0cDovL2FyeGl2Lm9yZy9saWNlbnNlcy9ub25leGNsdXNpdmUtZGlzdHJpYi8xLjAvIj5hclhpdi5vcmcgcGVycGV0dWFsLCBub24tZXhjbHVzaXZlIGxpY2Vuc2U8L3JpZ2h0cz4KICA8L3JpZ2h0c0xpc3Q+CiAgPGRlc2NyaXB0aW9ucz4KICAgIDxkZXNjcmlwdGlvbiBkZXNjcmlwdGlvblR5cGU9IkFic3RyYWN0Ij5BIHByb29mIGlzIG9uZSBvZiB0aGUgbW9zdCBpbXBvcnRhbnQgY29uY2VwdHMgb2YgbWF0aGVtYXRpY3MuIEhvd2V2ZXIsIHRoZXJlIGlzIGEgc3RyaWtpbmcgZGlmZmVyZW5jZSBiZXR3ZWVuIGhvdyBhIHByb29mIGlzIGRlZmluZWQgaW4gdGhlb3J5IGFuZCBob3cgaXQgaXMgdXNlZCBpbiBwcmFjdGljZS4gVGhpcyBwdXRzIHRoZSB1bmlxdWUgc3RhdHVzIG9mIG1hdGhlbWF0aWNzIGFzIGV4YWN0IHNjaWVuY2UgaW50byBwZXJpbC4gTm93IG1heSBiZSB0aGUgdGltZSB0byByZWNvbmNpbGUgdGhlb3J5IGFuZCBwcmFjdGljZSwgaS5lLiBwcmVjaXNpb24gYW5kIGludHVpdGlvbiwgdGhyb3VnaCB0aGUgYWR2ZW50IG9mIGNvbXB1dGVyIHByb29mIGFzc2lzdGFudHMuIEZvciB0aGUgbW9zdCB0aW1lIHRoaXMgaGFzIGJlZW4gYSB0b3BpYyBmb3IgZXhwZXJ0cyBpbiBzcGVjaWFsaXplZCBjb21tdW5pdGllcy4gSG93ZXZlciwgbWF0aGVtYXRpY2FsIHByb29mcyBoYXZlIGJlY29tZSBpbmNyZWFzaW5nbHkgc29waGlzdGljYXRlZCwgc3RyZXRjaGluZyB0aGUgYm91bmRhcmllcyBvZiB3aGF0IGlzIGh1bWFubHkgY29tcHJlaGVuc2libGUsIHNvIHRoYXQgbGVhZGluZyBtYXRoZW1hdGljaWFucyBoYXZlIGFza2VkIGZvciBmb3JtYWwgdmVyaWZpY2F0aW9uIG9mIHRoZWlyIHByb29mcy4gQXQgdGhlIHNhbWUgdGltZSwgbWFqb3IgdGhlb3JlbXMgaW4gbWF0aGVtYXRpY3MgaGF2ZSByZWNlbnRseSBiZWVuIGNvbXB1dGVyLXZlcmlmaWVkIGJ5IHBlb3BsZSBmcm9tIG91dHNpZGUgb2YgdGhlc2UgY29tbXVuaXRpZXMsIGV2ZW4gYnkgYmVnaW5uaW5nIHN0dWRlbnRzLiBUaGlzIGFydGljbGUgaW52ZXN0aWdhdGVzIHRoZSBnYXAgYmV0d2VlbiB0aGUgZGlmZmVyZW50IGRlZmluaXRpb25zIG9mIGEgcHJvb2YgYW5kIHBvc3NpYmlsaXRpZXMgdG8gYnVpbGQgYnJpZGdlcy4gSXQgaXMgd3JpdHRlbiBhcyBhIHBvbGVtaWMgb3IgYSBjb2xsYWdlIGJ5IGRpZmZlcmVudCBtZW1iZXJzIG9mIHRoZSBjb21tdW5pdGllcyBpbiBtYXRoZW1hdGljcyBhbmQgY29tcHV0ZXIgc2NpZW5jZSBhdCBkaWZmZXJlbnQgc3RhZ2VzIG9mIHRoZWlyIGNhcmVlcnMsIGNoYWxsZW5naW5nIHdlbGwta25vd24gcHJlY29uY2VwdGlvbnMgYW5kIGV4cGxvcmluZyBuZXcgcGVyc3BlY3RpdmVzLjwvZGVzY3JpcHRpb24+CiAgICA8ZGVzY3JpcHRpb24gZGVzY3JpcHRpb25UeXBlPSJPdGhlciI+MTcgcGFnZXMsIDEgZmlndXJlPC9kZXNjcmlwdGlvbj4KICA8L2Rlc2NyaXB0aW9ucz4KPC9yZXNvdXJjZT4=","url":"https://arxiv.org/abs/2207.04779","contentUrl":null,"metadataVersion":1,"schemaVersion":"http://datacite.org/schema/kernel-4","source":"mds","isActive":true,"state":"findable","reason":null,"viewCount":0,"viewsOverTime":[],"downloadCount":0,"downloadsOverTime":[],"referenceCount":0,"citationCount":0,"citationsOverTime":[],"partCount":0,"partOfCount":0,"versionCount":0,"versionOfCount":0,"created":"2022-07-12T01:41:56.000Z","registered":"2022-07-12T01:41:57.000Z","published":"2022","updated":"2022-07-13T01:24:20.000Z"},"relationships":{"client":{"data":{"id":"arxiv.content","type":"clients"}},"provider":{"data":{"id":"arxiv","type":"providers"}},"media":{"data":{"id":"10.48550/arxiv.2207.04779","type":"media"}},"references":{"data":[]},"citations":{"data":[]},"parts":{"data":[]},"partOf":{"data":[]},"versions":{"data":[]},"versionOf":{"data":[]}}}} +{"data":[{"id":"10.48550/arxiv.2207.04779","type":"dois","attributes":{"doi":"10.48550/arxiv.2207.04779","identifiers":[{"identifier":"2207.04779","identifierType":"arXiv"}],"creators":[{"name":"Bayer, Jonas","nameType":"Personal","givenName":"Jonas","familyName":"Bayer","affiliation":[],"nameIdentifiers":[]},{"name":"Benzmüller, Christoph","nameType":"Personal","givenName":"Christoph","familyName":"Benzmüller","affiliation":[],"nameIdentifiers":[]},{"name":"Buzzard, Kevin","nameType":"Personal","givenName":"Kevin","familyName":"Buzzard","affiliation":[],"nameIdentifiers":[]},{"name":"David, Marco","nameType":"Personal","givenName":"Marco","familyName":"David","affiliation":[],"nameIdentifiers":[]},{"name":"Lamport, Leslie","nameType":"Personal","givenName":"Leslie","familyName":"Lamport","affiliation":[],"nameIdentifiers":[]},{"name":"Matiyasevich, Yuri","nameType":"Personal","givenName":"Yuri","familyName":"Matiyasevich","affiliation":[],"nameIdentifiers":[]},{"name":"Paulson, Lawrence","nameType":"Personal","givenName":"Lawrence","familyName":"Paulson","affiliation":[],"nameIdentifiers":[]},{"name":"Schleicher, Dierk","nameType":"Personal","givenName":"Dierk","familyName":"Schleicher","affiliation":[],"nameIdentifiers":[]},{"name":"Stock, Benedikt","nameType":"Personal","givenName":"Benedikt","familyName":"Stock","affiliation":[],"nameIdentifiers":[]},{"name":"Zelmanov, Efim","nameType":"Personal","givenName":"Efim","familyName":"Zelmanov","affiliation":[],"nameIdentifiers":[]}],"titles":[{"title":"Mathematical Proof Between Generations"}],"publisher":"arXiv","container":{},"publicationYear":2022,"subjects":[{"lang":"en","subject":"History and Overview (math.HO)","subjectScheme":"arXiv"},{"lang":"en","subject":"Logic in Computer Science (cs.LO)","subjectScheme":"arXiv"},{"subject":"FOS: Mathematics","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Mathematics","schemeUri":"http://www.oecd.org/science/inno/38235147.pdf","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Computer and information sciences","subjectScheme":"Fields of Science and Technology (FOS)"},{"subject":"FOS: Computer and information sciences","schemeUri":"http://www.oecd.org/science/inno/38235147.pdf","subjectScheme":"Fields of Science and Technology (FOS)"}],"contributors":[],"dates":[{"date":"2022-07-08T14:42:33Z","dateType":"Submitted","dateInformation":"v1"},{"date":"2024-03-05T01:15:18Z","dateType":"Updated","dateInformation":"v1"},{"date":"2022-07","dateType":"Available","dateInformation":"v1"},{"date":"2022","dateType":"Issued"}],"language":null,"types":{"ris":"RPRT","bibtex":"article","citeproc":"article-journal","schemaOrg":"ScholarlyArticle","resourceType":"Article","resourceTypeGeneral":"Text"},"relatedIdentifiers":[{"relationType":"IsVersionOf","relatedIdentifier":"10.1090/noti2860","relatedIdentifierType":"DOI"}],"relatedItems":[],"sizes":[],"formats":[],"version":"1","rightsList":[{"rights":"arXiv.org perpetual, non-exclusive license","rightsUri":"http://arxiv.org/licenses/nonexclusive-distrib/1.0/"}],"descriptions":[{"description":"A proof is one of the most important concepts of mathematics. However, there is a striking difference between how a proof is defined in theory and how it is used in practice. This puts the unique status of mathematics as exact science into peril. Now may be the time to reconcile theory and practice, i.e. precision and intuition, through the advent of computer proof assistants. For the most time this has been a topic for experts in specialized communities. However, mathematical proofs have become increasingly sophisticated, stretching the boundaries of what is humanly comprehensible, so that leading mathematicians have asked for formal verification of their proofs. At the same time, major theorems in mathematics have recently been computer-verified by people from outside of these communities, even by beginning students. This article investigates the gap between the different definitions of a proof and possibilities to build bridges. It is written as a polemic or a collage by different members of the communities in mathematics and computer science at different stages of their careers, challenging well-known preconceptions and exploring new perspectives.","descriptionType":"Abstract"},{"description":"17 pages, 1 figure","descriptionType":"Other"}],"geoLocations":[],"fundingReferences":[],"url":"https://arxiv.org/abs/2207.04779","contentUrl":null,"metadataVersion":2,"schemaVersion":"http://datacite.org/schema/kernel-4","source":"mds","isActive":true,"state":"findable","reason":null,"viewCount":0,"downloadCount":0,"referenceCount":0,"citationCount":0,"partCount":0,"partOfCount":0,"versionCount":0,"versionOfCount":1,"created":"2022-07-12T01:41:56Z","registered":"2022-07-12T01:41:57Z","published":null,"updated":"2024-03-05T11:33:47Z"},"relationships":{"client":{"data":{"id":"arxiv.content","type":"clients"}}}}],"meta":{"total":1,"totalPages":1,"page":1,"states":[{"id":"findable","title":"Findable","count":1}],"resourceTypes":[{"id":"text","title":"Text","count":1}],"created":[{"id":"2022","title":"2022","count":1}],"published":[{"id":"2022","title":"2022","count":1}],"registered":[{"id":"2022","title":"2022","count":1}],"providers":[{"id":"arxiv","title":"arXiv","count":1}],"clients":[{"id":"arxiv.content","title":"arXiv","count":1}],"affiliations":[],"prefixes":[{"id":"10.48550","title":"10.48550","count":1}],"certificates":[],"licenses":[],"schemaVersions":[{"id":"4","title":"Schema 4","count":1}],"linkChecksStatus":[],"subjects":[{"id":"FOS: Computer and information sciences","title":"Fos: Computer And Information Sciences","count":1},{"id":"FOS: Mathematics","title":"Fos: Mathematics","count":1},{"id":"History and Overview (math.HO)","title":"History And Overview (Math.Ho)","count":1},{"id":"Logic in Computer Science (cs.LO)","title":"Logic In Computer Science (Cs.Lo)","count":1}],"fieldsOfScience":[{"id":"computer_and_information_sciences","title":"Computer and information sciences","count":1},{"id":"mathematics","title":"Mathematics","count":1}],"citations":[],"views":[],"downloads":[]},"links":{"self":"https://api.datacite.org/dois?query=10.48550/arxiv.2207.04779"}} From e35f859e06def64f44de426be01a12f74e9b363f Mon Sep 17 00:00:00 2001 From: "Gantner, Florian Klaus" Date: Tue, 16 Apr 2024 12:02:48 +0200 Subject: [PATCH 177/230] datacite api test for no results count (cherry picked from commit 9cd1a1093d08d74da6773112645dfd79b69dfdd0) --- ...DataCiteImportMetadataSourceServiceIT.java | 19 +++++++++++++++++++ .../dspace/app/rest/dataCite-noResults.json | 1 + 2 files changed, 20 insertions(+) create mode 100644 dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-noResults.json diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DataCiteImportMetadataSourceServiceIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DataCiteImportMetadataSourceServiceIT.java index 83ebc40c7966..c1481f0573c4 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/DataCiteImportMetadataSourceServiceIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/DataCiteImportMetadataSourceServiceIT.java @@ -146,4 +146,23 @@ private ArrayList getRecords() { return records; } + @Test + public void dataCiteImportMetadataNoResultsTest() throws Exception { + context.turnOffAuthorisationSystem(); + CloseableHttpClient originalHttpClient = liveImportClientImpl.getHttpClient(); + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + try (InputStream dataciteResp = getClass().getResourceAsStream("dataCite-noResults.json")) { + String dataciteTextResp = IOUtils.toString(dataciteResp, Charset.defaultCharset()); + liveImportClientImpl.setHttpClient(httpClient); + CloseableHttpResponse response = mockResponse(dataciteTextResp, 200, "OK"); + when(httpClient.execute(ArgumentMatchers.any())).thenReturn(response); + context.restoreAuthSystemState(); + int tot = dataCiteServiceImpl.getRecordsCount("nocontent"); + assertEquals(0, tot); + Collection importRecords = dataCiteServiceImpl.getRecords("nocontent", 0 , -1); + assertEquals(0, importRecords.size()); + } finally { + liveImportClientImpl.setHttpClient(originalHttpClient); + } + } } diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-noResults.json b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-noResults.json new file mode 100644 index 000000000000..c54fbe3636da --- /dev/null +++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/dataCite-noResults.json @@ -0,0 +1 @@ +{"data":[],"meta":{"total":0,"totalPages":0,"page":1},"links":{"self":"https://api.datacite.org/dois?query=nocontent"}} From 17c68323dbffea126add945ea18a1e2ad65cfe73 Mon Sep 17 00:00:00 2001 From: "Gantner, Florian Klaus" Date: Fri, 10 May 2024 18:08:19 +0200 Subject: [PATCH 178/230] avoid empty data to create phantom records for datacite import (cherry picked from commit 9667a3374d0aab18c91f53f59f8d6dc05e2df429) --- .../DataCiteImportMetadataSourceServiceImpl.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java index 298c30ec39a5..6c65d96b375d 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java @@ -143,12 +143,16 @@ public Collection getRecords(String query, int start, int count) t Iterator iterator = dataNode.iterator(); while (iterator.hasNext()) { JsonNode singleDoiNode = iterator.next(); - String json = singleDoiNode.at("/attributes").toString(); - records.add(transformSourceRecords(json)); + JsonNode singleDoiNodeAttribute = singleDoiNode.at("/attributes"); + if (!singleDoiNodeAttribute.isMissingNode()) { + records.add(transformSourceRecords(singleDoiNodeAttribute.toString())); + } } } else { - String json = dataNode.at("/attributes").toString(); - records.add(transformSourceRecords(json)); + JsonNode singleDoiNodeAttribute = dataNode.at("/attributes"); + if (!singleDoiNodeAttribute.isMissingNode()) { + records.add(transformSourceRecords(singleDoiNodeAttribute.toString())); + } } return records; From 1128b0eb10aba8170b1e9987eded3e75746eb0f5 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Mon, 13 May 2024 16:20:29 +0200 Subject: [PATCH 179/230] remove outdated comment as RSS feeds are supported in DS 7.3+ --- dspace/config/dspace.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index 0b7cd6ee44ae..3063572514aa 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -1276,8 +1276,6 @@ plugin.named.org.dspace.content.license.LicenseArgumentFormatter = \ org.dspace.content.license.SimpleDSpaceObjectLicenseFormatter = eperson #### Syndication Feed (RSS) Settings ###### -# TODO: UNSUPPORTED in DSpace 7.0. Will be added in a later release - # URLs returned by the feed will point at the global handle server # (e.g. https://hdl.handle.net/123456789/1). Set to true to use local server # URLs (i.e. https://myserver.myorg/handle/123456789/1) From 2309496f67f940ccdabd6a4b46b05bff3935004c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Fri, 19 Apr 2024 09:13:57 +0200 Subject: [PATCH 180/230] Correct relationship direction for persons in the project submission step. (cherry picked from commit ee2abfaf8801a252fd7033de7849220fb79ddab7) --- dspace/config/submission-forms.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace/config/submission-forms.xml b/dspace/config/submission-forms.xml index 39a4778356c0..07ebdbd1c281 100644 --- a/dspace/config/submission-forms.xml +++ b/dspace/config/submission-forms.xml @@ -516,7 +516,7 @@ - isProjectOfPerson + isPersonOfProject person true From b0995cdf6c7aa1df38cd9b230966240acc2c785d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Fri, 19 Apr 2024 09:15:43 +0200 Subject: [PATCH 181/230] Set correct metadata field for virtual metadata of persons in projects. (cherry picked from commit ff7d96b82ca832cc3a5342350eeccc29943e83b7) --- dspace/config/spring/api/virtual-metadata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace/config/spring/api/virtual-metadata.xml b/dspace/config/spring/api/virtual-metadata.xml index efab52c1b7c3..dee96eca7c0c 100644 --- a/dspace/config/spring/api/virtual-metadata.xml +++ b/dspace/config/spring/api/virtual-metadata.xml @@ -77,7 +77,7 @@ - + - + + on the filters defined in item-filters.xml, eg. + Of course, you can use a filter on the VersionedDOIIdentifierProvider as well. + --> - From 2d150cb86cefbc84ed7e3de9a9c5230abe5c934a Mon Sep 17 00:00:00 2001 From: Pascal-Nicolas Becker Date: Tue, 4 Jun 2024 00:03:47 +0200 Subject: [PATCH 202/230] Cleanup doi filters We can set filters in identifier-service.xml. Setting them in modules/identifiers.cfg is just overidding the other one. To keep things simple, we should avoid having two different filters for the same issue. The filter configured in spring is working for any new DOI, while the one we take out here, is just working for items being run through the install item service. (cherry picked from commit 59aaf3e57cceca6cf6e5e878a94c2dc3889a7929) --- dspace/config/modules/identifiers.cfg | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/dspace/config/modules/identifiers.cfg b/dspace/config/modules/identifiers.cfg index 2660646af394..aff37c89c56b 100644 --- a/dspace/config/modules/identifiers.cfg +++ b/dspace/config/modules/identifiers.cfg @@ -15,17 +15,12 @@ # Default: false #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 -# so that the identifier itself persists in case it is considered for registration in the future. -# See doi-filter and other example filters in item-filters.xml. -# Default (always_true_filter) -#identifiers.submission.filter.install = doi-filter - # This optional configuration property can be set to a filter name, in case there are some initial rules to apply # when first deciding whether a DOI should be be created for a new workspace item with a PENDING status. # This filter is only applied if identifiers.submission.register is true. # This filter is updated as submission data is saved. +# If you're looking for the filter that decides whether a DOI of an installed item should be queued for registration +# at DataCite, please check the filter in the identifier service spring configuration. # Default: (always_true_filter) #identifiers.submission.filter.workspace = always_true_filter From fe76579d04f0e88d0c6e3516066e81df133e0e34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 19:51:43 +0000 Subject: [PATCH 203/230] Bump org.apache.commons:commons-configuration2 from 2.9.0 to 2.10.1 Bumps org.apache.commons:commons-configuration2 from 2.9.0 to 2.10.1. --- updated-dependencies: - dependency-name: org.apache.commons:commons-configuration2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] (cherry picked from commit df7220bd9814e2e31f1000ebc6074395c27a196c) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f7ce30b30df1..8f213db2a55c 100644 --- a/pom.xml +++ b/pom.xml @@ -1486,7 +1486,7 @@ org.apache.commons commons-configuration2 - 2.9.0 + 2.10.1 org.apache.commons From 0d4d065d457155ab6a3c7bfd479504af75c10a8f Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Thu, 23 May 2024 16:32:56 +0200 Subject: [PATCH 204/230] Create a temporary version of the ConfigurationPlaceholderConfigurer to overcome bu in 2.10 (cherry picked from commit d44d76ea03aca7490a11e9a1d9c52fdc669feb1c) --- .../util/DSpaceConfigurationInitializer.java | 6 +-- ...aceConfigurationPlaceholderConfigurer.java | 5 +- .../DSpaceConfigurationPropertySource.java | 54 +++++++++++++++++++ 3 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java diff --git a/dspace-api/src/test/java/org/dspace/util/DSpaceConfigurationInitializer.java b/dspace-api/src/test/java/org/dspace/util/DSpaceConfigurationInitializer.java index e2e0355f123a..e5a8adb2fdf7 100644 --- a/dspace-api/src/test/java/org/dspace/util/DSpaceConfigurationInitializer.java +++ b/dspace-api/src/test/java/org/dspace/util/DSpaceConfigurationInitializer.java @@ -8,7 +8,7 @@ package org.dspace.util; import org.apache.commons.configuration2.Configuration; -import org.apache.commons.configuration2.spring.ConfigurationPropertySource; +import org.dspace.servicemanager.config.DSpaceConfigurationPropertySource; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.springframework.context.ApplicationContextInitializer; @@ -38,8 +38,8 @@ public void initialize(final ConfigurableApplicationContext applicationContext) Configuration configuration = configurationService.getConfiguration(); // Create an Apache Commons Configuration Property Source from our configuration - ConfigurationPropertySource apacheCommonsConfigPropertySource = - new ConfigurationPropertySource(configuration.getClass().getName(), configuration); + DSpaceConfigurationPropertySource apacheCommonsConfigPropertySource = + new DSpaceConfigurationPropertySource(configuration.getClass().getName(), configuration); // Prepend it to the Environment's list of PropertySources // NOTE: This is added *first* in the list so that settings in DSpace's diff --git a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPlaceholderConfigurer.java b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPlaceholderConfigurer.java index b85450dcd039..caa715e21bfb 100644 --- a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPlaceholderConfigurer.java +++ b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPlaceholderConfigurer.java @@ -8,7 +8,6 @@ package org.dspace.servicemanager.config; import org.apache.commons.configuration2.Configuration; -import org.apache.commons.configuration2.spring.ConfigurationPropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.MutablePropertySources; @@ -27,8 +26,8 @@ public class DSpaceConfigurationPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer { public DSpaceConfigurationPlaceholderConfigurer(Configuration configuration) { - ConfigurationPropertySource apacheCommonsConfigPropertySource = - new ConfigurationPropertySource(configuration.getClass().getName(), configuration); + DSpaceConfigurationPropertySource apacheCommonsConfigPropertySource = + new DSpaceConfigurationPropertySource(configuration.getClass().getName(), configuration); MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addLast(apacheCommonsConfigPropertySource); setPropertySources(propertySources); diff --git a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java new file mode 100644 index 000000000000..9bbf821766da --- /dev/null +++ b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dspace.servicemanager.config; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.configuration2.Configuration; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.core.env.EnumerablePropertySource; + +/** + * Allow use of Apache Commons Configuration Objects as Spring PropertySources. + * This class is a copy of the ConfigurationPropertySource class in the Apache Commons Configuration + * project needed until to fix the issue https://issues.apache.org/jira/browse/CONFIGURATION-846 + */ +public class DSpaceConfigurationPropertySource extends EnumerablePropertySource { + + protected DSpaceConfigurationPropertySource(final String name) { + super(name); + } + + public DSpaceConfigurationPropertySource(final String name, final Configuration source) { + super(name, source); + } + + @Override + public Object getProperty(final String name) { + final String[] propValue = source.getStringArray(name); + return propValue != null && propValue.length == 1 ? propValue[0] : propValue; + } + + @Override + public String[] getPropertyNames() { + final List keys = new ArrayList<>(); + source.getKeys().forEachRemaining(keys::add); + return keys.toArray(ArrayUtils.EMPTY_STRING_ARRAY); + } +} From 4b5248fe1515fc39a5f42d206d3faf4c801ab340 Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Mon, 27 May 2024 11:49:00 +0200 Subject: [PATCH 205/230] DURACOM-267 update commons-configuration2 fix according to the community feedback (cherry picked from commit f2d4ffc49c457a4f919a4bf2ef4171ea49246103) --- .../config/DSpaceConfigurationPropertySource.java | 10 ++++++++-- pom.xml | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java index 9bbf821766da..a904e04c5a08 100644 --- a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java +++ b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java @@ -26,7 +26,7 @@ /** * Allow use of Apache Commons Configuration Objects as Spring PropertySources. - * This class is a copy of the ConfigurationPropertySource class in the Apache Commons Configuration + * This class is a temporary copy of the ConfigurationPropertySource class in the Apache Commons Configuration * project needed until to fix the issue https://issues.apache.org/jira/browse/CONFIGURATION-846 */ public class DSpaceConfigurationPropertySource extends EnumerablePropertySource { @@ -42,7 +42,13 @@ public DSpaceConfigurationPropertySource(final String name, final Configuration @Override public Object getProperty(final String name) { final String[] propValue = source.getStringArray(name); - return propValue != null && propValue.length == 1 ? propValue[0] : propValue; + if (propValue == null || propValue.length == 0) { + return null; + } else if (propValue.length == 1) { + return propValue[0]; + } else { + return propValue; + } } @Override diff --git a/pom.xml b/pom.xml index 8f213db2a55c..ae83442235e0 100644 --- a/pom.xml +++ b/pom.xml @@ -432,6 +432,8 @@ + + **/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java **/src/test/resources/** **/src/test/data/** **/src/main/license/** From b9e6af675878c489b27a8171e18ea431d1d26170 Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Fri, 31 May 2024 19:47:12 +0200 Subject: [PATCH 206/230] DURACOM-267 improve handling of empty configuration property (cherry picked from commit 0422b8786f9fb9d39f51403da94f69a77c20044c) --- .../DSpaceConfigurationPropertySource.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java index a904e04c5a08..d3394399301f 100644 --- a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java +++ b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationPropertySource.java @@ -41,13 +41,17 @@ public DSpaceConfigurationPropertySource(final String name, final Configuration @Override public Object getProperty(final String name) { - final String[] propValue = source.getStringArray(name); - if (propValue == null || propValue.length == 0) { - return null; - } else if (propValue.length == 1) { - return propValue[0]; + if (source.getProperty(name) != null) { + final String[] propValue = source.getStringArray(name); + if (propValue == null || propValue.length == 0) { + return ""; + } else if (propValue.length == 1) { + return propValue[0]; + } else { + return propValue; + } } else { - return propValue; + return null; } } From 7fc74bdc567c91137484255979ee4f6f4387db22 Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Mon, 3 Jun 2024 10:07:06 +0200 Subject: [PATCH 207/230] DURACOM-267 assure that our custom DSpaceConfigurationPropertySource is used also for the spring context created by the DSpace kernel (cherry picked from commit 4fcf995b699b287f7e773ad8ca420cd68cae1e12) --- .../app/rest/utils/DSpaceConfigurationInitializer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java index 56b8ae32dce1..9291a436c787 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java @@ -8,7 +8,7 @@ package org.dspace.app.rest.utils; import org.apache.commons.configuration2.Configuration; -import org.apache.commons.configuration2.spring.ConfigurationPropertySource; +import org.dspace.servicemanager.config.DSpaceConfigurationPropertySource; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.slf4j.Logger; @@ -38,8 +38,8 @@ public void initialize(final ConfigurableApplicationContext applicationContext) Configuration configuration = configurationService.getConfiguration(); // Create an Apache Commons Configuration Property Source from our configuration - ConfigurationPropertySource apacheCommonsConfigPropertySource = - new ConfigurationPropertySource(configuration.getClass().getName(), configuration); + DSpaceConfigurationPropertySource apacheCommonsConfigPropertySource = + new DSpaceConfigurationPropertySource(configuration.getClass().getName(), configuration); // Prepend it to the Environment's list of PropertySources // NOTE: This is added *first* in the list so that settings in DSpace's ConfigurationService *override* From c5d139c9e1dc71482d1a9112b01ad718c317bfae Mon Sep 17 00:00:00 2001 From: nwoodward Date: Mon, 3 Jun 2024 12:53:44 -0500 Subject: [PATCH 208/230] updates creativecommons.org links to https --- .../impl/CCLicenseAddPatchOperation.java | 2 +- .../rest/CCLicenseAddPatchOperationIT.java | 4 +-- .../rest/CCLicenseRemovePatchOperationIT.java | 4 +-- .../org/dspace/app/rest/cinii-second.xml | 4 +-- .../org/dspace/license/cc-license-rdf.xml | 36 +++++++++---------- dspace/config/dspace.cfg | 2 +- dspace/config/submission-forms.xml | 12 +++---- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/CCLicenseAddPatchOperation.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/CCLicenseAddPatchOperation.java index ec4dff9f6c51..602ae5e9690b 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/CCLicenseAddPatchOperation.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/CCLicenseAddPatchOperation.java @@ -26,7 +26,7 @@ * Example: * curl -X PATCH http://${dspace.server.url}/api/submission/workspaceitems/31599 -H "Content-Type: * application/json" -d '[{ "op": "add", "path": "/sections/cclicense/uri", - * "value":"http://creativecommons.org/licenses/by-nc-sa/3.0/us/"}]' + * "value":"https://creativecommons.org/licenses/by-nc-sa/3.0/us/"}]' * */ public class CCLicenseAddPatchOperation extends AddPatchOperation { diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseAddPatchOperationIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseAddPatchOperationIT.java index f07c816b9c98..eb49661259cc 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseAddPatchOperationIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseAddPatchOperationIT.java @@ -63,7 +63,7 @@ public void patchSubmissionCCLicense() throws Exception { List ops = new ArrayList<>(); AddOperation addOperation = new AddOperation("/sections/cclicense/uri", - "http://creativecommons.org/licenses/by-nc-sa/4.0/"); + "https://creativecommons.org/licenses/by-nc-sa/4.0/"); ops.add(addOperation); String patchBody = getPatchContent(ops); @@ -74,7 +74,7 @@ public void patchSubmissionCCLicense() throws Exception { .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.sections.cclicense", allOf( - hasJsonPath("$.uri", is("http://creativecommons.org/licenses/by-nc-sa/4.0/")), + hasJsonPath("$.uri", is("https://creativecommons.org/licenses/by-nc-sa/4.0/")), hasJsonPath("$.rights", is("Attribution-NonCommercial-ShareAlike 4.0 International")), hasJsonPath("$.file.name", is("license_rdf")) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseRemovePatchOperationIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseRemovePatchOperationIT.java index 8e01678899a5..dd2b99d158b9 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseRemovePatchOperationIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseRemovePatchOperationIT.java @@ -64,7 +64,7 @@ public void patchRemoveSubmissionCCLicense() throws Exception { // First add a license and verify it is added List ops = new ArrayList<>(); AddOperation addOperation = new AddOperation("/sections/cclicense/uri", - "http://creativecommons.org/licenses/by-nc-sa/4.0/"); + "https://creativecommons.org/licenses/by-nc-sa/4.0/"); ops.add(addOperation); String patchBody = getPatchContent(ops); @@ -75,7 +75,7 @@ public void patchRemoveSubmissionCCLicense() throws Exception { .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.sections.cclicense", allOf( - hasJsonPath("$.uri", is("http://creativecommons.org/licenses/by-nc-sa/4.0/")), + hasJsonPath("$.uri", is("https://creativecommons.org/licenses/by-nc-sa/4.0/")), hasJsonPath("$.rights", is("Attribution-NonCommercial-ShareAlike 4.0 International")), hasJsonPath("$.file.name", is("license_rdf")) diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/cinii-second.xml b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/cinii-second.xml index 8eb68ff047fc..cf1845ca5636 100644 --- a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/cinii-second.xml +++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/cinii-second.xml @@ -57,7 +57,7 @@ 322 331 - © 2022 The Author(s). Published by National Institute for Materials Science in partnership with Taylor & Francis Group. This is an Open Access article distributed under the terms of the Creative Commons Attribution License (http://creativecommons.org/licenses/by/4.0/), which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. + © 2022 The Author(s). Published by National Institute for Materials Science in partnership with Taylor & Francis Group. This is an Open Access article distributed under the terms of the Creative Commons Attribution License (https://creativecommons.org/licenses/by/4.0/), which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. @@ -74,4 +74,4 @@ oai:irdb.nii.ac.jp:01257:0005348137 - \ No newline at end of file + diff --git a/dspace-server-webapp/src/test/resources/org/dspace/license/cc-license-rdf.xml b/dspace-server-webapp/src/test/resources/org/dspace/license/cc-license-rdf.xml index 5ff75ee4c747..2051406b550d 100644 --- a/dspace-server-webapp/src/test/resources/org/dspace/license/cc-license-rdf.xml +++ b/dspace-server-webapp/src/test/resources/org/dspace/license/cc-license-rdf.xml @@ -1,31 +1,31 @@ - http://creativecommons.org/licenses/by-nc-sa/4.0/ + https://creativecommons.org/licenses/by-nc-sa/4.0/ Attribution-NonCommercial-ShareAlike 4.0 International false - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. + Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index fc0f516c3aa1..fc840ef00354 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -1011,7 +1011,7 @@ cc.license.classfilter = publicdomain, recombo, mark # Jurisdiction of the creative commons license -- is it ported or not? # Use the key from the url seen in the response from the api call, -# http://api.creativecommons.org/rest/1.5/support/jurisdictions +# https://api.creativecommons.org/rest/1.5/support/jurisdictions # Commented out means the license is unported. # (e.g. nz = New Zealand, uk = England and Wales, jp = Japan) # or set value none for user-selected jurisdiction diff --git a/dspace/config/submission-forms.xml b/dspace/config/submission-forms.xml index 07ebdbd1c281..0b1e049c81ca 100644 --- a/dspace/config/submission-forms.xml +++ b/dspace/config/submission-forms.xml @@ -1549,27 +1549,27 @@ Attribution (CC-BY) - http://creativecommons.org/licenses/by/4.0/ + https://creativecommons.org/licenses/by/4.0/ Attribution, No Derivative Works (CC-BY-ND) - http://creativecommons.org/licenses/by-nd/4.0/ + https://creativecommons.org/licenses/by-nd/4.0/ Attribution, Share-alike (CC-BY-SA) - http://creativecommons.org/licenses/by-sa/4.0/ + https://creativecommons.org/licenses/by-sa/4.0/ Attribution, Non-commercial (CC-BY-NC) - http://creativecommons.org/licenses/by-nc/4.0/ + https://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/ + https://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/ + https://creativecommons.org/licenses/by-nc-sa/4.0/ From 4cd3b75e67e04aae1dd25be13a4d532e74940642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Fri, 3 May 2024 14:08:50 -0400 Subject: [PATCH 209/230] Fixed classpath issue in test_database target (cherry picked from commit 6937c19973f0810a4b1eb646bb0eaefdded9cae6) --- dspace/src/main/config/build.xml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/dspace/src/main/config/build.xml b/dspace/src/main/config/build.xml index 8b33522d2b14..940287c9d166 100644 --- a/dspace/src/main/config/build.xml +++ b/dspace/src/main/config/build.xml @@ -764,8 +764,25 @@ Common usage: + + + + + + + + + + + + + + + + + Date: Tue, 4 Jun 2024 09:43:10 -0500 Subject: [PATCH 210/230] Ensure work directory is cleaned up whether zip file is created successfully or an error occurs. (cherry picked from commit b7f764746c8a88d8db3ec3cf989b6aa3eda8e087) --- .../app/itemexport/ItemExportServiceImpl.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java index a884f9b07564..7c80e1ea7dc6 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java @@ -490,7 +490,7 @@ public void exportAsZip(Context context, Iterator items, File wkDir = new File(workDir); if (!wkDir.exists() && !wkDir.mkdirs()) { - logError("Unable to create working direcory"); + logError("Unable to create working directory"); } File dnDir = new File(destDirName); @@ -498,11 +498,18 @@ public void exportAsZip(Context context, Iterator items, logError("Unable to create destination directory"); } - // export the items using normal export method - exportItem(context, items, workDir, seqStart, migrate, excludeBitstreams); + try { + // export the items using normal export method (this exports items to our workDir) + exportItem(context, items, workDir, seqStart, migrate, excludeBitstreams); - // now zip up the export directory created above - zip(workDir, destDirName + System.getProperty("file.separator") + zipFileName); + // now zip up the workDir directory created above + zip(workDir, destDirName + System.getProperty("file.separator") + zipFileName); + } finally { + // Cleanup workDir created above, if it still exists + if (wkDir.exists()) { + deleteDirectory(wkDir); + } + } } @Override From 26658b666517f9da71de5e1ff706dce692da6350 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 16 May 2024 16:36:35 +0200 Subject: [PATCH 211/230] evaluate surname and given-name if authname is not present (cherry picked from commit 8b5f0445373e5ce60be2b12fd1d487f54f74e350) --- .../contributor/AuthorMetadataContributor.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/AuthorMetadataContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/AuthorMetadataContributor.java index 26063dc7441d..62b7fe81e399 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/AuthorMetadataContributor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/AuthorMetadataContributor.java @@ -71,7 +71,7 @@ public Collection contributeMetadata(Element element) { } /** - * Retrieve the the ScopusID, orcid, author name and affiliationID + * Retrieve the ScopusID, orcid, author name and affiliationID * metadata associated with the given element object. * If the value retrieved from the element is empty * it is set PLACEHOLDER_PARENT_METADATA_VALUE @@ -82,11 +82,19 @@ public Collection contributeMetadata(Element element) { private List getMetadataOfAuthors(Element element) throws JaxenException { List metadatums = new ArrayList(); Element authname = element.getChild("authname", NAMESPACE); + Element surname = element.getChild("surname", NAMESPACE); + Element givenName = element.getChild("given-name", NAMESPACE); Element scopusId = element.getChild("authid", NAMESPACE); Element orcid = element.getChild("orcid", NAMESPACE); Element afid = element.getChild("afid", NAMESPACE); - addMetadatum(metadatums, getMetadata(getElementValue(authname), this.authname)); + if (authname != null) { + addMetadatum(metadatums, getMetadata(getElementValue(authname), this.authname)); + } else { + addMetadatum(metadatums, getMetadata(getElementValue(surname) + ", " + + getElementValue(givenName), this.authname)); + } + addMetadatum(metadatums, getMetadata(getElementValue(scopusId), this.scopusId)); addMetadatum(metadatums, getMetadata(getElementValue(orcid), this.orcid)); addMetadatum(metadatums, getMetadata(StringUtils.isNotBlank(afid.getValue()) @@ -170,4 +178,4 @@ public void setAffiliation(MetadataFieldConfig affiliation) { this.affiliation = affiliation; } -} \ No newline at end of file +} From 6e5c5089abe776b0e3b8b364ec10393855275429 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 16 May 2024 16:37:48 +0200 Subject: [PATCH 212/230] Update scopus-empty-resp.xml (cherry picked from commit 4b2ea66f19324d204058084434ff99a71fd6588e) --- .../resources/org/dspace/app/rest/scopus-empty-resp.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scopus-empty-resp.xml b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scopus-empty-resp.xml index b2b4264b5c34..3e0ecbead350 100644 --- a/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scopus-empty-resp.xml +++ b/dspace-server-webapp/src/test/resources/org/dspace/app/rest/scopus-empty-resp.xml @@ -3,9 +3,11 @@ 0 0 0 - - + + Result set was empty - \ No newline at end of file + From 2b1270197e2d4af1d7051a2d75c501d00d3fc318 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 16 May 2024 16:40:04 +0200 Subject: [PATCH 213/230] improve handling of 0 hits responses of Scopus API (cherry picked from commit b12bd6ce565bb95fcb470a4ea156abd0a6ca531f) --- ...ScopusImportMetadataSourceServiceImpl.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/importer/external/scopus/service/ScopusImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/scopus/service/ScopusImportMetadataSourceServiceImpl.java index 944d467e3156..e61ca0528681 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/scopus/service/ScopusImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/scopus/service/ScopusImportMetadataSourceServiceImpl.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -24,6 +25,8 @@ import javax.el.MethodNotFoundException; import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.dspace.content.Item; import org.dspace.importer.external.datamodel.ImportRecord; import org.dspace.importer.external.datamodel.Query; @@ -62,6 +65,8 @@ public class ScopusImportMetadataSourceServiceImpl extends AbstractImportMetadat @Autowired private LiveImportClient liveImportClient; + private final static Logger log = LogManager.getLogger(); + public LiveImportClient getLiveImportClient() { return liveImportClient; } @@ -200,6 +205,9 @@ public Integer call() throws Exception { Map requestParams = getRequestParameters(query, null, null, null); params.put(URI_PARAMETERS, requestParams); String response = liveImportClient.executeHttpGetRequest(timeout, url, params); + if (StringUtils.isEmpty(response)) { + return 0; + } SAXBuilder saxBuilder = new SAXBuilder(); // disallow DTD parsing to ensure no XXE attacks can occur @@ -245,6 +253,10 @@ public List call() throws Exception { Map requestParams = getRequestParameters(queryString, viewMode, null, null); params.put(URI_PARAMETERS, requestParams); String response = liveImportClient.executeHttpGetRequest(timeout, url, params); + if (StringUtils.isEmpty(response)) { + return results; + } + List elements = splitToRecords(response); for (Element record : elements) { results.add(transformSourceRecords(record)); @@ -304,6 +316,10 @@ public List call() throws Exception { Map requestParams = getRequestParameters(queryString, viewMode, start, count); params.put(URI_PARAMETERS, requestParams); String response = liveImportClient.executeHttpGetRequest(timeout, url, params); + if (StringUtils.isEmpty(response)) { + return results; + } + List elements = splitToRecords(response); for (Element record : elements) { results.add(transformSourceRecords(record)); @@ -349,6 +365,10 @@ public List call() throws Exception { Map requestParams = getRequestParameters(queryString, viewMode, start, count); params.put(URI_PARAMETERS, requestParams); String response = liveImportClient.executeHttpGetRequest(timeout, url, params); + if (StringUtils.isEmpty(response)) { + return results; + } + List elements = splitToRecords(response); for (Element record : elements) { results.add(transformSourceRecords(record)); @@ -383,10 +403,16 @@ private List splitToRecords(String recordsSrc) { saxBuilder.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true); Document document = saxBuilder.build(new StringReader(recordsSrc)); Element root = document.getRootElement(); - List records = root.getChildren("entry",Namespace.getNamespace("http://www.w3.org/2005/Atom")); + String totalResults = root.getChildText("totalResults", Namespace.getNamespace("http://a9.com/-/spec/opensearch/1.1/")); + if (totalResults != null && "0".equals(totalResults)) { + log.debug("got Scopus API with empty response"); + return Collections.emptyList(); + } + List records = root.getChildren("entry", Namespace.getNamespace("http://www.w3.org/2005/Atom")); return records; } catch (JDOMException | IOException e) { - return new ArrayList(); + log.warn("got unexpected XML response from Scopus API: " + e.getMessage()); + return Collections.emptyList(); } } @@ -422,4 +448,4 @@ public void setInstKey(String instKey) { this.instKey = instKey; } -} \ No newline at end of file +} From 8e56fdd95b2054a49606103554f5bea1366fce21 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 16 May 2024 16:41:31 +0200 Subject: [PATCH 214/230] fixed failed test (cherry picked from commit 6989cb6f15761ac453ada2b5ce69b6d2dbbd3e78) --- .../app/rest/ScopusImportMetadataSourceServiceIT.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScopusImportMetadataSourceServiceIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScopusImportMetadataSourceServiceIT.java index b9310e3adba6..7f6cb53ce400 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScopusImportMetadataSourceServiceIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScopusImportMetadataSourceServiceIT.java @@ -96,7 +96,7 @@ public void scopusImportMetadataGetRecordsCountTest() throws Exception { } @Test - public void scopusImportMetadataGetRecordsEmptyResponceTest() throws Exception { + public void scopusImportMetadataGetRecordsEmptyResponseTest() throws Exception { context.turnOffAuthorisationSystem(); String originApiKey = scopusServiceImpl.getApiKey(); if (StringUtils.isBlank(originApiKey)) { @@ -113,8 +113,7 @@ public void scopusImportMetadataGetRecordsEmptyResponceTest() throws Exception { context.restoreAuthSystemState(); Collection recordsImported = scopusServiceImpl.getRecords("roma", 0, 20); - ImportRecord importedRecord = recordsImported.iterator().next(); - assertTrue(importedRecord.getValueList().isEmpty()); + assertTrue(recordsImported.isEmpty()); } finally { liveImportClientImpl.setHttpClient(originalHttpClient); scopusServiceImpl.setApiKey(originApiKey); @@ -229,4 +228,4 @@ private ArrayList getRecords() { return records; } -} \ No newline at end of file +} From 8d82457eb7b3f5f96fa164c0ca5905bde34a4649 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Mon, 27 May 2024 00:17:53 +0200 Subject: [PATCH 215/230] 115434: Added relatedEntityType parameter to byLabel endpoint to differentiate relationships with same label and different entity types (cherry picked from commit 8512fab392c99d774197c026abbdfc941764ae9d) --- .../RelationshipRestRepository.java | 35 +++++++++--- .../rest/RelationshipRestRepositoryIT.java | 55 +++++++++++++++++++ 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index 21f43ddacd63..6be4f390daa9 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -29,9 +29,11 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.DSpaceObject; +import org.dspace.content.EntityType; import org.dspace.content.Item; import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityTypeService; import org.dspace.content.service.ItemService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; @@ -60,6 +62,9 @@ public class RelationshipRestRepository extends DSpaceRestRepository findByLabel(@Parameter(value = "label", required = true) String label, @Parameter(value = "dso", required = false) UUID dsoId, + @Parameter(value = "relatedEntityType") String relatedEntityType, Pageable pageable) throws SQLException { Context context = obtainContext(); @@ -352,14 +359,28 @@ public Page findByLabel(@Parameter(value = "label", required = if (item == null) { throw new ResourceNotFoundException("The request DSO with id: " + dsoId + " was not found"); } + + EntityType dsoEntityType = itemService.getEntityType(context, item); + + if (dsoEntityType == null) { + throw new UnprocessableEntityException(String.format( + "The request DSO with id: %s doesn't have an entity type", dsoId)); + } + for (RelationshipType relationshipType : relationshipTypeList) { - boolean isLeft = false; - if (relationshipType.getLeftwardType().equalsIgnoreCase(label)) { - isLeft = true; + if (relatedEntityType == null || + relationshipType.getRightType().getLabel().equals(dsoEntityType.getLabel()) && + relationshipType.getLeftType().getLabel().equals(relatedEntityType) || + relationshipType.getRightType().getLabel().equals(relatedEntityType) && + relationshipType.getLeftType().getLabel().equals(dsoEntityType.getLabel())) { + boolean isLeft = relationshipType.getLeftwardType().equalsIgnoreCase(label); + total += + relationshipService.countByItemAndRelationshipType(context, item, relationshipType, isLeft); + relationships.addAll( + relationshipService.findByItemAndRelationshipType(context, item, relationshipType, + isLeft, pageable.getPageSize(), + Math.toIntExact(pageable.getOffset()))); } - total += relationshipService.countByItemAndRelationshipType(context, item, relationshipType, isLeft); - relationships.addAll(relationshipService.findByItemAndRelationshipType(context, item, relationshipType, - isLeft, pageable.getPageSize(), Math.toIntExact(pageable.getOffset()))); } } else { for (RelationshipType relationshipType : relationshipTypeList) { @@ -377,7 +398,7 @@ public Page findByLabel(@Parameter(value = "label", required = * of potentially related items we need to know which of these other items * are already in a specific relationship with the focus item and, * by exclusion which ones are not yet related. - * + * * @param typeId The relationship type id to apply as a filter to the returned relationships * @param label The name of the relation as defined from the side of the 'focusItem' * @param focusUUID The uuid of the item to be checked on the side defined by 'relationshipLabel' diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index d8e53c770c70..d126c0352d0c 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -2323,6 +2323,61 @@ public void findRelationshipByLabelTest() throws Exception { ; } + @Test + public void findRelationshipByLabelWithRelatedEntityTypeTest() throws Exception { + context.turnOffAuthorisationSystem(); + RelationshipType isAuthorOfPublicationRelationshipTypePublication = relationshipTypeService + .findbyTypesAndTypeName(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + RelationshipType isAuthorOfPublicationRelationshipTypeOrgUnit = relationshipTypeService + .findbyTypesAndTypeName(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "OrgUnit"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + // We're creating a Relationship of type isAuthorOfPublication between a Publication and a Person + Relationship relationship1 = RelationshipBuilder + .createRelationshipBuilder(context, publication1, author1, isAuthorOfPublicationRelationshipTypePublication) + .build(); + + // We're creating a Relationship of type isAuthorOfPublication between a Publication and an OrgUnit + Relationship relationship2 = RelationshipBuilder + .createRelationshipBuilder(context, publication1, orgUnit1, isAuthorOfPublicationRelationshipTypeOrgUnit) + .build(); + context.restoreAuthSystemState(); + + // Perform a GET request to the searchByLabel endpoint, asking for Relationships of type isAuthorOfPublication + // With an extra parameter namely DSO which resolves to the publication used by both relationships. + // Both relationships should be returned if we don't specify the DSO's related entity type + getClient().perform(get("/api/core/relationships/search/byLabel") + .param("label", "isAuthorOfPublication") + .param("dso", publication1.getID().toString()) + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page", is(PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2)))) + .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( + RelationshipMatcher.matchRelationship(relationship1), + RelationshipMatcher.matchRelationship(relationship2) + ))) + ; + + // Perform a GET request to the searchByLabel endpoint, asking for Relationships of type isAuthorOfPublication + // With an extra parameter namely DSO which resolves to the publication used by both relationships. + // Only the Person relationship should be returned if we specify the DSO's related entity type + getClient().perform(get("/api/core/relationships/search/byLabel") + .param("label", "isAuthorOfPublication") + .param("dso", publication1.getID().toString()) + .param("relatedEntityType", "Person") + .param("projection", "full")) + + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page", is(PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1)))) + .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( + RelationshipMatcher.matchRelationship(relationship1) + ))) + ; + } + @Test public void putRelationshipWithNonexistentID() throws Exception { context.turnOffAuthorisationSystem(); From 7789304ebe531fe16ddad7af798998249f0197ba Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 7 Jun 2024 20:53:48 +0200 Subject: [PATCH 216/230] 115434: Added test proving that different values for relatedEntityType return different results (cherry picked from commit bbae1fb0d110e2c1e7ad63bc01ac1084590ad62c) --- .../app/rest/RelationshipRestRepositoryIT.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index d126c0352d0c..aad26ba2c11f 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -2376,6 +2376,22 @@ public void findRelationshipByLabelWithRelatedEntityTypeTest() throws Exception RelationshipMatcher.matchRelationship(relationship1) ))) ; + + // Perform a GET request to the searchByLabel endpoint, asking for Relationships of type isAuthorOfPublication + // With an extra parameter namely DSO which resolves to the publication used by both relationships. + // Only the OrgUnit relationship should be returned if we specify the DSO's related entity type + getClient().perform(get("/api/core/relationships/search/byLabel") + .param("label", "isAuthorOfPublication") + .param("dso", publication1.getID().toString()) + .param("relatedEntityType", "OrgUnit") + .param("projection", "full")) + + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page", is(PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1)))) + .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( + RelationshipMatcher.matchRelationship(relationship2) + ))) + ; } @Test From 928dad1c5cbbbe95b69cf4b3d6f533e72a25d221 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 29 Apr 2024 11:21:08 -0500 Subject: [PATCH 217/230] Ensure List is not empty before returning first value (cherry picked from commit 068bcdf3af2a74218cfb77fdb944e7384de3db75) --- .../dspace/content/DSpaceObjectServiceImpl.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index 2119959073f0..f47ed47d4c0d 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -314,20 +314,26 @@ public List addMetadata(Context context, T dso, MetadataField met @Override public MetadataValue addMetadata(Context context, T dso, MetadataField metadataField, String language, String value, String authority, int confidence) throws SQLException { - return addMetadata(context, dso, metadataField, language, Arrays.asList(value), Arrays.asList(authority), - Arrays.asList(confidence)).get(0); + List metadataValues = + addMetadata(context, dso, metadataField, language, Arrays.asList(value), Arrays.asList(authority), + Arrays.asList(confidence)); + return CollectionUtils.isNotEmpty(metadataValues) ? metadataValues.get(0) : null; } @Override public MetadataValue addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, String value) throws SQLException { - return addMetadata(context, dso, schema, element, qualifier, lang, Arrays.asList(value)).get(0); + List metadataValues = + addMetadata(context, dso, schema, element, qualifier, lang, Arrays.asList(value)); + return CollectionUtils.isNotEmpty(metadataValues) ? metadataValues.get(0) : null; } @Override public MetadataValue addMetadata(Context context, T dso, MetadataField metadataField, String language, String value) throws SQLException { - return addMetadata(context, dso, metadataField, language, Arrays.asList(value)).get(0); + List metadataValues = + addMetadata(context, dso, metadataField, language, Arrays.asList(value)); + return CollectionUtils.isNotEmpty(metadataValues) ? metadataValues.get(0) : null; } @Override From 8407c571db341d7620cfd1bf8a73dce1ed1be229 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 24 May 2024 09:19:25 -0500 Subject: [PATCH 218/230] Throw IllegalArgumentException if addMetadata() called without values. Add unit tests to prove it works (cherry picked from commit ed918a8d0c51e9c2071991b876f832fe85d1b8f1) --- .../content/DSpaceObjectServiceImpl.java | 21 ++++++++++++++++ .../java/org/dspace/content/ItemTest.java | 24 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index f47ed47d4c0d..4e3fa42162ce 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -242,10 +242,31 @@ public List addMetadata(Context context, T dso, MetadataField met } + /** + * Add metadata value(s) to a MetadataField of a DSpace Object + * @param context current DSpace context + * @param dso DSpaceObject to modify + * @param metadataField MetadataField to add values to + * @param lang Language code to add + * @param values One or more metadata values to add + * @param authorities One or more authorities to add + * @param confidences One or more confidences to add (for authorities) + * @param placeSupplier Supplier of "place" for new metadata values + * @return List of newly added metadata values + * @throws SQLException if database error occurs + * @throws IllegalArgumentException for an empty list of values + */ public List addMetadata(Context context, T dso, MetadataField metadataField, String lang, List values, List authorities, List confidences, Supplier placeSupplier) throws SQLException { + // Throw an error if we are attempting to add empty values + if (values == null || values.isEmpty()) { + throw new IllegalArgumentException("Cannot add empty values to a new metadata field " + + metadataField.toString() + " on object with uuid = " + + dso.getID().toString() + " and type = " + getTypeText(dso)); + } + boolean authorityControlled = metadataAuthorityService.isAuthorityControlled(metadataField); boolean authorityRequired = metadataAuthorityService.isAuthorityRequired(metadataField); List newMetadata = new ArrayList<>(); diff --git a/dspace-api/src/test/java/org/dspace/content/ItemTest.java b/dspace-api/src/test/java/org/dspace/content/ItemTest.java index ada9bbc15905..de9919f4e3d5 100644 --- a/dspace-api/src/test/java/org/dspace/content/ItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/ItemTest.java @@ -537,6 +537,17 @@ public void testAddMetadata_5args_1() throws SQLException { assertThat("testAddMetadata_5args_1 11", dc.get(1).getValue(), equalTo(values[1])); } + @Test(expected = IllegalArgumentException.class) + public void testAddMetadata_5args_no_values() throws Exception { + String schema = "dc"; + String element = "contributor"; + String qualifier = "author"; + String lang = Item.ANY; + String[] values = {}; + itemService.addMetadata(context, it, schema, element, qualifier, lang, Arrays.asList(values)); + fail("IllegalArgumentException expected"); + } + /** * Test of addMetadata method, of class Item. */ @@ -614,6 +625,19 @@ public void testAddMetadata_7args_1_noauthority() throws SQLException { assertThat("testAddMetadata_7args_1 15", dc.get(1).getConfidence(), equalTo(-1)); } + @Test(expected = IllegalArgumentException.class) + public void testAddMetadata_7args_no_values() throws Exception { + String schema = "dc"; + String element = "contributor"; + String qualifier = "author"; + String lang = Item.ANY; + List values = new ArrayList(); + List authorities = new ArrayList(); + List confidences = new ArrayList(); + itemService.addMetadata(context, it, schema, element, qualifier, lang, values, authorities, confidences); + fail("IllegalArgumentException expected"); + } + /** * Test of addMetadata method, of class Item. */ From 30dafa09d0da90d55fa8898abdfb948cfcd74fa9 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 24 May 2024 09:54:42 -0500 Subject: [PATCH 219/230] Fix testAddMetadata_5args_2 to no longer be *identical* to testAddMetadata_5args_1. It appears this second test was meant to test a different addMetadata() method which accepts a single Value instead of a List (cherry picked from commit 25f722ed980fe13a7244f90f3799efcaa9ba6f7c) --- .../test/java/org/dspace/content/ItemTest.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/dspace-api/src/test/java/org/dspace/content/ItemTest.java b/dspace-api/src/test/java/org/dspace/content/ItemTest.java index de9919f4e3d5..e3337d9d92a7 100644 --- a/dspace-api/src/test/java/org/dspace/content/ItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/ItemTest.java @@ -639,7 +639,7 @@ public void testAddMetadata_7args_no_values() throws Exception { } /** - * Test of addMetadata method, of class Item. + * This is the same as testAddMetadata_5args_1 except it is adding a *single* value as a String, not a List. */ @Test public void testAddMetadata_5args_2() throws SQLException { @@ -647,24 +647,18 @@ public void testAddMetadata_5args_2() throws SQLException { String element = "contributor"; String qualifier = "author"; String lang = Item.ANY; - List values = Arrays.asList("value0", "value1"); - itemService.addMetadata(context, it, schema, element, qualifier, lang, values); + String value = "value0"; + itemService.addMetadata(context, it, schema, element, qualifier, lang, value); List dc = itemService.getMetadata(it, schema, element, qualifier, lang); assertThat("testAddMetadata_5args_2 0", dc, notNullValue()); - assertTrue("testAddMetadata_5args_2 1", dc.size() == 2); + assertTrue("testAddMetadata_5args_2 1", dc.size() == 1); assertThat("testAddMetadata_5args_2 2", dc.get(0).getMetadataField().getMetadataSchema().getName(), equalTo(schema)); assertThat("testAddMetadata_5args_2 3", dc.get(0).getMetadataField().getElement(), equalTo(element)); assertThat("testAddMetadata_5args_2 4", dc.get(0).getMetadataField().getQualifier(), equalTo(qualifier)); assertThat("testAddMetadata_5args_2 5", dc.get(0).getLanguage(), equalTo(lang)); - assertThat("testAddMetadata_5args_2 6", dc.get(0).getValue(), equalTo(values.get(0))); - assertThat("testAddMetadata_5args_2 7", dc.get(1).getMetadataField().getMetadataSchema().getName(), - equalTo(schema)); - assertThat("testAddMetadata_5args_2 8", dc.get(1).getMetadataField().getElement(), equalTo(element)); - assertThat("testAddMetadata_5args_2 9", dc.get(1).getMetadataField().getQualifier(), equalTo(qualifier)); - assertThat("testAddMetadata_5args_2 10", dc.get(1).getLanguage(), equalTo(lang)); - assertThat("testAddMetadata_5args_2 11", dc.get(1).getValue(), equalTo(values.get(1))); + assertThat("testAddMetadata_5args_2 6", dc.get(0).getValue(), equalTo(value)); } /** From 872af3315590a70ae72466ba8bdef7741b365489 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 24 May 2024 12:01:03 -0500 Subject: [PATCH 220/230] Fix bug in MetadataImport where it could call addMetadata() with empty values. Minor refactors to MetadataImportIT to make findItemByName more efficient. (cherry picked from commit f8ac8edc4970086c74e5d5f7b492199bd9bf3ba7) --- .../dspace/app/bulkedit/MetadataImport.java | 10 ++++--- .../dspace/app/bulkedit/MetadataImportIT.java | 27 ++++++++++--------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java index af6976acb14a..ad46cb95c353 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java @@ -825,8 +825,10 @@ protected void compareAndUpdate(Context c, Item item, String[] fromCSV, boolean addRelationships(c, item, element, values); } else { itemService.clearMetadata(c, item, schema, element, qualifier, language); - itemService.addMetadata(c, item, schema, element, qualifier, - language, values, authorities, confidences); + if (!values.isEmpty()) { + itemService.addMetadata(c, item, schema, element, qualifier, + language, values, authorities, confidences); + } itemService.update(c, item); } } @@ -1121,8 +1123,8 @@ protected void add(Context c, String[] fromCSV, String md, BulkEditChange change .getAuthoritySeparator() + dcv.getConfidence(); } - // Add it - if ((value != null) && (!"".equals(value))) { + // Add it, if value is not blank + if (value != null && StringUtils.isNotBlank(value)) { changes.registerAdd(dcv); } } diff --git a/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataImportIT.java b/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataImportIT.java index e50f7913ad70..ae079df560ed 100644 --- a/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataImportIT.java +++ b/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataImportIT.java @@ -9,12 +9,12 @@ import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertTrue; +import static junit.framework.TestCase.fail; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; -import java.sql.SQLException; import java.util.List; import org.apache.commons.cli.ParseException; @@ -218,9 +218,10 @@ public void personMetadataImportTest() throws Exception { @Test public void metadataImportRemovingValueTest() throws Exception { - context.turnOffAuthorisationSystem(); - Item item = ItemBuilder.createItem(context,personCollection).withAuthor("TestAuthorToRemove").withTitle("title") + String itemTitle = "Testing removing author"; + Item item = ItemBuilder.createItem(context,personCollection).withAuthor("TestAuthorToRemove") + .withTitle(itemTitle) .build(); context.restoreAuthSystemState(); @@ -232,19 +233,21 @@ public void metadataImportRemovingValueTest() throws Exception { String[] csv = {"id,collection,dc.title,dc.contributor.author[*]", item.getID().toString() + "," + personCollection.getHandle() + "," + item.getName() + ","}; performImportScript(csv); - item = findItemByName("title"); + item = findItemByName(itemTitle); assertEquals(0, itemService.getMetadata(item, "dc", "contributor", "author", Item.ANY).size()); } - private Item findItemByName(String name) throws SQLException { - Item importedItem = null; - List allItems = IteratorUtils.toList(itemService.findAll(context)); - for (Item item : allItems) { - if (item.getName().equals(name)) { - importedItem = item; - } + private Item findItemByName(String name) throws Exception { + List items = + IteratorUtils.toList(itemService.findByMetadataField(context, "dc", "title", null, name)); + + if (items != null && !items.isEmpty()) { + // Just return first matching Item. Tests should ensure name/title is unique. + return items.get(0); + } else { + fail("Could not find expected Item with dc.title = '" + name + "'"); + return null; } - return importedItem; } public void performImportScript(String[] csv) throws Exception { From c890199cfe314b2192fe098ad6ccb3ada7570687 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 24 May 2024 13:51:46 -0500 Subject: [PATCH 221/230] Add tests to verify behavior of addMetadata() when encountering virtual metadata (cherry picked from commit 2eb7dbca6ba349da70ccbf52f65a3b3ad70acbb2) --- .../java/org/dspace/content/ItemTest.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/dspace-api/src/test/java/org/dspace/content/ItemTest.java b/dspace-api/src/test/java/org/dspace/content/ItemTest.java index e3337d9d92a7..aaa28769dca6 100644 --- a/dspace-api/src/test/java/org/dspace/content/ItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/ItemTest.java @@ -13,6 +13,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -638,6 +640,51 @@ public void testAddMetadata_7args_no_values() throws Exception { fail("IllegalArgumentException expected"); } + @Test + public void testAddMetadata_list_with_virtual_metadata() throws Exception { + String schema = "dc"; + String element = "contributor"; + String qualifier = "author"; + String lang = Item.ANY; + // Create two fake virtual metadata ("virtual::[relationship-id]") values + List values = new ArrayList<>(Arrays.asList("uuid-1", "uuid-2")); + List authorities = new ArrayList<>(Arrays.asList(Constants.VIRTUAL_AUTHORITY_PREFIX + "relationship-1", + Constants.VIRTUAL_AUTHORITY_PREFIX + "relationship-2")); + List confidences = new ArrayList<>(Arrays.asList(-1, -1)); + + // Virtual metadata values will be IGNORED. No metadata should be added as we are calling addMetadata() + // with two virtual metadata values. + List valuesAdded = itemService.addMetadata(context, it, schema, element, qualifier, lang, + values, authorities, confidences); + assertNotNull(valuesAdded); + assertTrue(valuesAdded.isEmpty()); + + // Now, update tests values to append a third value which is NOT virtual metadata + String newValue = "new-metadata-value"; + String newAuthority = "auth0"; + Integer newConfidence = 0; + values.add(newValue); + authorities.add(newAuthority); + confidences.add(newConfidence); + + // Call addMetadata again, and this time only one value (the new, non-virtual metadata) should be added + valuesAdded = itemService.addMetadata(context, it, schema, element, qualifier, lang, + values, authorities, confidences); + assertNotNull(valuesAdded); + assertEquals(1, valuesAdded.size()); + + // Get metadata and ensure new value is the ONLY ONE for this metadata field + List dc = itemService.getMetadata(it, schema, element, qualifier, lang); + assertNotNull(dc); + assertEquals(1, dc.size()); + assertEquals(schema, dc.get(0).getMetadataField().getMetadataSchema().getName()); + assertEquals(element, dc.get(0).getMetadataField().getElement()); + assertEquals(qualifier, dc.get(0).getMetadataField().getQualifier()); + assertEquals(newValue, dc.get(0).getValue()); + assertNull(dc.get(0).getAuthority()); + assertEquals(-1, dc.get(0).getConfidence()); + } + /** * This is the same as testAddMetadata_5args_1 except it is adding a *single* value as a String, not a List. */ @@ -720,6 +767,42 @@ public void testAddMetadata_7args_2_noauthority() throws SQLException { assertThat("testAddMetadata_7args_2 8", dc.get(0).getConfidence(), equalTo(-1)); } + @Test + public void testAddMetadata_single_virtual_metadata() throws Exception { + String schema = "dc"; + String element = "contributor"; + String qualifier = "author"; + String lang = Item.ANY; + // Create a single fake virtual metadata ("virtual::[relationship-id]") value + String value = "uuid-1"; + String authority = Constants.VIRTUAL_AUTHORITY_PREFIX + "relationship-1"; + Integer confidence = -1; + + // Virtual metadata values will be IGNORED. No metadata should be added as we are calling addMetadata() + // with a virtual metadata value. + MetadataValue valuesAdded = itemService.addMetadata(context, it, schema, element, qualifier, lang, + value, authority, confidence); + // Returned object will be null when no metadata was added + assertNull(valuesAdded); + + // Verify this metadata field does NOT exist on the item + List mv = itemService.getMetadata(it, schema, element, qualifier, lang); + assertNotNull(mv); + assertTrue(mv.isEmpty()); + + // Also try calling addMetadata() with MetadataField object + MetadataField metadataField = metadataFieldService.findByElement(context, schema, element, qualifier); + valuesAdded = itemService.addMetadata(context, it, metadataField, lang, value, authority, confidence); + // Returned object should still be null + assertNull(valuesAdded); + + // Verify this metadata field does NOT exist on the item + mv = itemService.getMetadata(it, schema, element, qualifier, lang); + assertNotNull(mv); + assertTrue(mv.isEmpty()); + } + + /** * Test of clearMetadata method, of class Item. */ From 0f74cb22bf1e5eedec766cb9e8b85ff9d35d2f2e Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 6 Jun 2024 11:44:28 -0500 Subject: [PATCH 222/230] Avoid inline display of HTML/JS bitstreams. Add JS to list of known formats so that it can be recognized by DSpace. (cherry picked from commit 356a0281867989cd1bf6345f9d369f9c992791c8) --- .../org/dspace/app/rest/BitstreamRestController.java | 8 +++++++- dspace/config/dspace.cfg | 5 +++++ dspace/config/registries/bitstream-formats.xml | 9 +++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java index 9b5ede37c85f..e3d6076844fe 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java @@ -209,7 +209,13 @@ private boolean checkFormatForContentDisposition(BitstreamFormat format) { if (format == null) { return false; } - List formats = List.of((configurationService.getArrayProperty("webui.content_disposition_format"))); + // Default to always downloading HTML/JavaScript files. These formats can embed JavaScript which would be run + // in the user's browser when loaded inline. This could be the basis for an XSS attack. + // RTF is also added because most browsers attempt to display it as plain text. + String [] defaultFormats = { "text/html", "text/javascript", "text/richtext" }; + + List formats = List.of(configurationService.getArrayProperty("webui.content_disposition_format", + defaultFormats)); boolean download = formats.contains(format.getMIMEType()); if (!download) { for (String ext : format.getExtensions()) { diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index fc840ef00354..1d108d5c3345 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -1373,6 +1373,11 @@ webui.content_disposition_threshold = 8388608 # Set which mimetypes, file extensions will NOT be opened inline # Files with these mimetypes/extensions will always be downloaded, # regardless of the threshold above +# We HIGHLY RECOMMEND forcing HTML / Javascript to always download. +# If a bitstream contained malicious Javascript, it would be executed in a user's browser when opened inline. +webui.content_disposition_format = text/html +webui.content_disposition_format = text/javascript +# RTF is always downloaded because most browsers attempt to display it as plain text. webui.content_disposition_format = text/richtext #### Multi-file HTML document/site settings ##### diff --git a/dspace/config/registries/bitstream-formats.xml b/dspace/config/registries/bitstream-formats.xml index 3515773fd742..fe0943e015e0 100644 --- a/dspace/config/registries/bitstream-formats.xml +++ b/dspace/config/registries/bitstream-formats.xml @@ -827,4 +827,13 @@ avif + + text/javascript + JavaScript + JavaScript + 1 + false + js + + From 7143c97248e89416d8b491593a546879394875a2 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 6 Jun 2024 15:55:01 -0500 Subject: [PATCH 223/230] Fix failing IT by increasing number of formats by one (cherry picked from commit c61b7033f2ce63ceec6d867679216cccdaf10aec) --- .../org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java index fd128269308d..d28202af659b 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java @@ -56,7 +56,7 @@ public class BitstreamFormatRestRepositoryIT extends AbstractControllerIntegrati @Autowired private BitstreamFormatConverter bitstreamFormatConverter; - private final int DEFAULT_AMOUNT_FORMATS = 85; + private final int DEFAULT_AMOUNT_FORMATS = 86; @Test public void findAllPaginationTest() throws Exception { From 7ba150f4fc8121b44587c642be71e7c37a553cc0 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 10 Jun 2024 09:58:52 -0500 Subject: [PATCH 224/230] Add XML to the list of formats to always download (cherry picked from commit 39975e45cfff8aa70c7c0896c6f1cdff8d3e6fbf) --- .../java/org/dspace/app/rest/BitstreamRestController.java | 4 ++-- dspace/config/dspace.cfg | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java index e3d6076844fe..d70c0904b3c2 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java @@ -209,10 +209,10 @@ private boolean checkFormatForContentDisposition(BitstreamFormat format) { if (format == null) { return false; } - // Default to always downloading HTML/JavaScript files. These formats can embed JavaScript which would be run + // Default to always downloading HTML/JavaScript/XML files. These formats can embed JavaScript which may be run // in the user's browser when loaded inline. This could be the basis for an XSS attack. // RTF is also added because most browsers attempt to display it as plain text. - String [] defaultFormats = { "text/html", "text/javascript", "text/richtext" }; + String [] defaultFormats = { "text/html", "text/javascript", "text/xml", "text/richtext" }; List formats = List.of(configurationService.getArrayProperty("webui.content_disposition_format", defaultFormats)); diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index 1d108d5c3345..0554d76866fd 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -1373,10 +1373,11 @@ webui.content_disposition_threshold = 8388608 # Set which mimetypes, file extensions will NOT be opened inline # Files with these mimetypes/extensions will always be downloaded, # regardless of the threshold above -# We HIGHLY RECOMMEND forcing HTML / Javascript to always download. -# If a bitstream contained malicious Javascript, it would be executed in a user's browser when opened inline. +# We HIGHLY RECOMMEND forcing HTML / Javascript / XML to always download. +# If one of these bitstreams contains malicious Javascript, it may be executed in a user's browser when opened inline. webui.content_disposition_format = text/html webui.content_disposition_format = text/javascript +webui.content_disposition_format = text/xml # RTF is always downloaded because most browsers attempt to display it as plain text. webui.content_disposition_format = text/richtext From 7951c8e428819972a3c3d80fd8f1fb0ae2cd3284 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 10 Jun 2024 10:09:33 -0500 Subject: [PATCH 225/230] Add a test to prove the default settings are to always download these formats (cherry picked from commit e6bfb833eed8228aa8f9ab66ec3277284d747b0d) --- .../app/rest/BitstreamRestControllerIT.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java index ae1b62c1b1b6..cef087c363f3 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java @@ -1247,7 +1247,6 @@ public void closeInputStreamsDownloadWithCoverPage() throws Exception { Mockito.verify(inputStreamSpy, times(1)).close(); } - @Test public void checkContentDispositionOfFormats() throws Exception { configurationService.setProperty("webui.content_disposition_format", new String[] { @@ -1285,6 +1284,35 @@ public void checkContentDispositionOfFormats() throws Exception { verifyBitstreamDownload(html, "text/html;charset=UTF-8", false); } + @Test + public void checkDefaultContentDispositionFormats() throws Exception { + // This test is similar to the above test, but it verifies that our *default settings* for + // webui.content_disposition_format are protecting us from loading specific formats *inline*. + context.turnOffAuthorisationSystem(); + Community community = CommunityBuilder.createCommunity(context).build(); + Collection collection = CollectionBuilder.createCollection(context, community).build(); + Item item = ItemBuilder.createItem(context, collection).build(); + String content = "Test Content"; + Bitstream html; + Bitstream js; + Bitstream xml; + try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) { + html = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("text/html").build(); + js = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("text/javascript").build(); + xml = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("text/xml").build(); + } + context.restoreAuthSystemState(); + + // By default, HTML, JS & XML should all download. This protects us from possible XSS attacks, as + // each of these formats can embed JavaScript which may execute when the file is loaded *inline*. + verifyBitstreamDownload(html, "text/html;charset=UTF-8", true); + verifyBitstreamDownload(js, "text/javascript;charset=UTF-8", true); + verifyBitstreamDownload(xml, "text/xml;charset=UTF-8", true); + } + private void verifyBitstreamDownload(Bitstream file, String contentType, boolean shouldDownload) throws Exception { String token = getAuthToken(admin.getEmail(), password); String header = getClient(token).perform(get("/api/core/bitstreams/" + file.getID() + "/content") From c30ff35448fe2da77d922f3b9db20500066b343d Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 10 Jun 2024 11:51:11 -0500 Subject: [PATCH 226/230] For additional security, ensure "unknown" formats are always downloaded. Update test to prove behavior. (cherry picked from commit 6da072de9e43d52e43eb9b312446a9359638f3c7) --- .../app/rest/BitstreamRestController.java | 15 ++++++++++++--- .../app/rest/BitstreamRestControllerIT.java | 17 +++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java index d70c0904b3c2..b85c009c7be8 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java @@ -204,10 +204,19 @@ private boolean isNotAnErrorResponse(HttpServletResponse response) { || responseCode.equals(Response.Status.Family.REDIRECTION); } + /** + * Check if a Bitstream of the specified format should always be downloaded (i.e. "content-disposition: attachment") + * or can be served inline (i.e. "content-disposition: inline"). + *

+ * NOTE that downloading via "attachment" is more secure, as the user's browser will not attempt to process or + * display the file. But, downloading via "inline" may be seen as more user-friendly for common formats. + * @param format BitstreamFormat + * @return true if always download ("attachment"). false if can be served inline ("inline") + */ private boolean checkFormatForContentDisposition(BitstreamFormat format) { - // never automatically download undefined formats - if (format == null) { - return false; + // Undefined or Unknown formats should ALWAYS be downloaded for additional security. + if (format == null || format.getSupportLevel() == BitstreamFormat.UNKNOWN) { + return true; } // Default to always downloading HTML/JavaScript/XML files. These formats can embed JavaScript which may be run // in the user's browser when loaded inline. This could be the basis for an XSS attack. diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java index cef087c363f3..502429679f62 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java @@ -1296,6 +1296,7 @@ public void checkDefaultContentDispositionFormats() throws Exception { Bitstream html; Bitstream js; Bitstream xml; + Bitstream unknown; try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) { html = BitstreamBuilder.createBitstream(context, item, is) .withMimeType("text/html").build(); @@ -1303,6 +1304,8 @@ public void checkDefaultContentDispositionFormats() throws Exception { .withMimeType("text/javascript").build(); xml = BitstreamBuilder.createBitstream(context, item, is) .withMimeType("text/xml").build(); + unknown = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("application/octet-stream").build(); } context.restoreAuthSystemState(); @@ -1311,6 +1314,8 @@ public void checkDefaultContentDispositionFormats() throws Exception { verifyBitstreamDownload(html, "text/html;charset=UTF-8", true); verifyBitstreamDownload(js, "text/javascript;charset=UTF-8", true); verifyBitstreamDownload(xml, "text/xml;charset=UTF-8", true); + // Unknown file formats should also always download + verifyBitstreamDownload(unknown, "application/octet-stream;charset=UTF-8", true); } private void verifyBitstreamDownload(Bitstream file, String contentType, boolean shouldDownload) throws Exception { @@ -1321,11 +1326,15 @@ private void verifyBitstreamDownload(Bitstream file, String contentType, boolean .andExpect(content().contentType(contentType)) .andReturn().getResponse().getHeader("content-disposition"); if (shouldDownload) { - assertTrue(header.contains("attachment")); - assertFalse(header.contains("inline")); + assertTrue("Content-Disposition should contain 'attachment' for " + contentType, + header.contains("attachment")); + assertFalse("Content-Disposition should NOT contain 'inline' for " + contentType, + header.contains("inline")); } else { - assertTrue(header.contains("inline")); - assertFalse(header.contains("attachment")); + assertTrue("Content-Disposition should contain 'inline' for " + contentType, + header.contains("inline")); + assertFalse("Content-Disposition should NOT contain 'attachment' for " + contentType, + header.contains("attachment")); } } } From 3bcd33d92a8f3e1dab958d332b2030fc1b272d8a Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 10 Jun 2024 14:52:21 -0500 Subject: [PATCH 227/230] To avoid misconfiguration, hardcode HTML, XML, RDF, JS to download only. Add a new wildcard setting to allow sites to force all files to download only. (cherry picked from commit a091d343b9c1e491ca0fc005fd18bc1c75f8e830) --- .../app/rest/BitstreamRestController.java | 29 ++++++--- .../app/rest/BitstreamRestControllerIT.java | 60 ++++++++++++++++--- dspace/config/dspace.cfg | 17 +++--- 3 files changed, 82 insertions(+), 24 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java index b85c009c7be8..22b18724b90b 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java @@ -20,6 +20,7 @@ import javax.ws.rs.core.Response; import org.apache.catalina.connector.ClientAbortException; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; import org.dspace.app.rest.converter.ConverterService; @@ -206,25 +207,37 @@ private boolean isNotAnErrorResponse(HttpServletResponse response) { /** * Check if a Bitstream of the specified format should always be downloaded (i.e. "content-disposition: attachment") - * or can be served inline (i.e. "content-disposition: inline"). + * or can be opened inline (i.e. "content-disposition: inline"). *

* NOTE that downloading via "attachment" is more secure, as the user's browser will not attempt to process or * display the file. But, downloading via "inline" may be seen as more user-friendly for common formats. * @param format BitstreamFormat - * @return true if always download ("attachment"). false if can be served inline ("inline") + * @return true if always download ("attachment"). false if can be opened inline ("inline") */ private boolean checkFormatForContentDisposition(BitstreamFormat format) { // Undefined or Unknown formats should ALWAYS be downloaded for additional security. if (format == null || format.getSupportLevel() == BitstreamFormat.UNKNOWN) { return true; } - // Default to always downloading HTML/JavaScript/XML files. These formats can embed JavaScript which may be run - // in the user's browser when loaded inline. This could be the basis for an XSS attack. - // RTF is also added because most browsers attempt to display it as plain text. - String [] defaultFormats = { "text/html", "text/javascript", "text/xml", "text/richtext" }; - List formats = List.of(configurationService.getArrayProperty("webui.content_disposition_format", - defaultFormats)); + // Load additional formats configured to require download + List configuredFormats = List.of(configurationService. + getArrayProperty("webui.content_disposition_format")); + + // If configuration includes "*", then all formats will always be downloaded. + if (configuredFormats.contains("*")) { + return true; + } + + // Define a download list of formats which DSpace forces to ALWAYS be downloaded. + // These formats can embed JavaScript which may be run in the user's browser if the file is opened inline. + // Therefore, DSpace blocks opening these formats inline as it could be used for an XSS attack. + List downloadOnlyFormats = List.of("text/html", "text/javascript", "text/xml", "rdf"); + + // Combine our two lists + List formats = ListUtils.union(downloadOnlyFormats, configuredFormats); + + // See if the passed in format's MIME type or file extension is listed. boolean download = formats.contains(format.getMIMEType()); if (!download) { for (String ext : format.getExtensions()) { diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java index 502429679f62..855fedbaa2ab 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java @@ -1263,7 +1263,7 @@ public void checkContentDispositionOfFormats() throws Exception { Bitstream rtf; Bitstream xml; Bitstream txt; - Bitstream html; + Bitstream csv; try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) { rtf = BitstreamBuilder.createBitstream(context, item, is) .withMimeType("text/richtext").build(); @@ -1271,8 +1271,8 @@ public void checkContentDispositionOfFormats() throws Exception { .withMimeType("text/xml").build(); txt = BitstreamBuilder.createBitstream(context, item, is) .withMimeType("text/plain").build(); - html = BitstreamBuilder.createBitstream(context, item, is) - .withMimeType("text/html").build(); + csv = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("text/csv").build(); } context.restoreAuthSystemState(); @@ -1281,12 +1281,12 @@ public void checkContentDispositionOfFormats() throws Exception { verifyBitstreamDownload(xml, "text/xml;charset=UTF-8", true); verifyBitstreamDownload(txt, "text/plain;charset=UTF-8", true); // this format is not configured and should open inline - verifyBitstreamDownload(html, "text/html;charset=UTF-8", false); + verifyBitstreamDownload(csv, "text/csv;charset=UTF-8", false); } @Test - public void checkDefaultContentDispositionFormats() throws Exception { - // This test is similar to the above test, but it verifies that our *default settings* for + public void checkHardcodedContentDispositionFormats() throws Exception { + // This test is similar to the above test, but it verifies that our *hardcoded settings* for // webui.content_disposition_format are protecting us from loading specific formats *inline*. context.turnOffAuthorisationSystem(); Community community = CommunityBuilder.createCommunity(context).build(); @@ -1295,17 +1295,25 @@ public void checkDefaultContentDispositionFormats() throws Exception { String content = "Test Content"; Bitstream html; Bitstream js; + Bitstream rdf; Bitstream xml; Bitstream unknown; + Bitstream svg; try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) { html = BitstreamBuilder.createBitstream(context, item, is) .withMimeType("text/html").build(); js = BitstreamBuilder.createBitstream(context, item, is) - .withMimeType("text/javascript").build(); + .withMimeType("text/javascript").build(); + // NOTE: RDF has a MIME Type with a "charset" in our bitstream-formats.xml + rdf = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("application/rdf+xml; charset=utf-8").build(); xml = BitstreamBuilder.createBitstream(context, item, is) .withMimeType("text/xml").build(); unknown = BitstreamBuilder.createBitstream(context, item, is) .withMimeType("application/octet-stream").build(); + svg = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("image/svg+xml").build(); + } context.restoreAuthSystemState(); @@ -1313,11 +1321,49 @@ public void checkDefaultContentDispositionFormats() throws Exception { // each of these formats can embed JavaScript which may execute when the file is loaded *inline*. verifyBitstreamDownload(html, "text/html;charset=UTF-8", true); verifyBitstreamDownload(js, "text/javascript;charset=UTF-8", true); + verifyBitstreamDownload(rdf, "application/rdf+xml;charset=UTF-8", true); verifyBitstreamDownload(xml, "text/xml;charset=UTF-8", true); // Unknown file formats should also always download verifyBitstreamDownload(unknown, "application/octet-stream;charset=UTF-8", true); + // SVG does NOT currently exist as a recognized format in DSpace's bitstream-formats.xml, but it's another + // format that allows embedded JavaScript. This test is a reminder that SVGs should NOT be opened inline. + verifyBitstreamDownload(svg, "application/octet-stream;charset=UTF-8", true); + } + + @Test + public void checkWildcardContentDispositionFormats() throws Exception { + // Setting "*" should result in all formats being downloaded (nothing will be opened inline) + configurationService.setProperty("webui.content_disposition_format", "*"); + + context.turnOffAuthorisationSystem(); + Community community = CommunityBuilder.createCommunity(context).build(); + Collection collection = CollectionBuilder.createCollection(context, community).build(); + Item item = ItemBuilder.createItem(context, collection).build(); + String content = "Test Content"; + Bitstream csv; + Bitstream jpg; + Bitstream mpg; + Bitstream pdf; + try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) { + csv = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("text/csv").build(); + jpg = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("image/jpeg").build(); + mpg = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("video/mpeg").build(); + pdf = BitstreamBuilder.createBitstream(context, item, is) + .withMimeType("application/pdf").build(); + } + context.restoreAuthSystemState(); + + // All formats should be download only + verifyBitstreamDownload(csv, "text/csv;charset=UTF-8", true); + verifyBitstreamDownload(jpg, "image/jpeg;charset=UTF-8", true); + verifyBitstreamDownload(mpg, "video/mpeg;charset=UTF-8", true); + verifyBitstreamDownload(pdf, "application/pdf;charset=UTF-8", true); } + private void verifyBitstreamDownload(Bitstream file, String contentType, boolean shouldDownload) throws Exception { String token = getAuthToken(admin.getEmail(), password); String header = getClient(token).perform(get("/api/core/bitstreams/" + file.getID() + "/content") diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index 0554d76866fd..c21fb54655b8 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -1370,15 +1370,14 @@ webui.content_disposition_threshold = 8388608 #### Content Attachment Disposition Formats #### # -# Set which mimetypes, file extensions will NOT be opened inline -# Files with these mimetypes/extensions will always be downloaded, -# regardless of the threshold above -# We HIGHLY RECOMMEND forcing HTML / Javascript / XML to always download. -# If one of these bitstreams contains malicious Javascript, it may be executed in a user's browser when opened inline. -webui.content_disposition_format = text/html -webui.content_disposition_format = text/javascript -webui.content_disposition_format = text/xml -# RTF is always downloaded because most browsers attempt to display it as plain text. +# Set which mimetypes or file extensions will NOT be opened inline. +# Files with these mimetypes/extensions will always be downloaded, regardless of the threshold above. +# NOTE: For security reasons, some file formats (e.g. HTML, XML, RDF, JS) will always be downloaded regardless +# of the settings here. This blocks these formats from executing embedded JavaScript when opened inline. +# For additional security, you may choose to set this to "*" to force all formats to always be downloaded +# (i.e. disables all formats from opening inline within the user's browser). +# +# By default, RTF is always downloaded because most browsers attempt to display it as plain text. webui.content_disposition_format = text/richtext #### Multi-file HTML document/site settings ##### From 12c3cc5b3eb6c4d0339595b0efa236e16075b0dd Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 9 Jul 2024 13:35:16 -0500 Subject: [PATCH 228/230] Update LICENSES_THIRD_PARTY (and related configs) for 7.6.2 release --- LICENSES_THIRD_PARTY | 610 +++++++++--------- pom.xml | 6 +- .../license/LICENSES_THIRD_PARTY.properties | 85 +-- 3 files changed, 326 insertions(+), 375 deletions(-) diff --git a/LICENSES_THIRD_PARTY b/LICENSES_THIRD_PARTY index e494c80c5d6e..791009e4c3ae 100644 --- a/LICENSES_THIRD_PARTY +++ b/LICENSES_THIRD_PARTY @@ -26,24 +26,23 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.12.261 - https://aws.amazon.com/sdkforjava) * JMES Path Query library (com.amazonaws:jmespath-java:1.12.261 - https://aws.amazon.com/sdkforjava) * HPPC Collections (com.carrotsearch:hppc:0.8.1 - http://labs.carrotsearch.com/hppc.html/hppc) - * com.drewnoakes:metadata-extractor (com.drewnoakes:metadata-extractor:2.18.0 - https://drewnoakes.com/code/exif/) + * com.drewnoakes:metadata-extractor (com.drewnoakes:metadata-extractor:2.19.0 - https://drewnoakes.com/code/exif/) * parso (com.epam:parso:2.0.14 - https://github.com/epam/parso) - * Esri Geometry API for Java (com.esri.geometry:esri-geometry-api:2.2.0 - https://github.com/Esri/geometry-api-java) - * ClassMate (com.fasterxml:classmate:1.3.0 - http://github.com/cowtowncoder/java-classmate) - * Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.13.4 - http://github.com/FasterXML/jackson) - * Jackson-core (com.fasterxml.jackson.core:jackson-core:2.13.4 - https://github.com/FasterXML/jackson-core) - * jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.13.4.2 - http://github.com/FasterXML/jackson) + * ClassMate (com.fasterxml:classmate:1.6.0 - https://github.com/FasterXML/java-classmate) + * Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.16.0 - https://github.com/FasterXML/jackson) + * Jackson-core (com.fasterxml.jackson.core:jackson-core:2.16.0 - https://github.com/FasterXML/jackson-core) + * jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.16.0 - https://github.com/FasterXML/jackson) * Jackson dataformat: CBOR (com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.12.6 - http://github.com/FasterXML/jackson-dataformats-binary) - * Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.13.3 - http://github.com/FasterXML/jackson-dataformats-binary) + * Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.15.2 - https://github.com/FasterXML/jackson-dataformats-binary) * Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.1 - https://github.com/FasterXML/jackson-dataformats-text) * Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.5 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.1 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310) * Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.5 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310) * Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.5 - https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * Java UUID Generator (com.fasterxml.uuid:java-uuid-generator:4.0.1 - https://github.com/cowtowncoder/java-uuid-generator) - * Woodstox (com.fasterxml.woodstox:woodstox-core:6.2.4 - https://github.com/FasterXML/woodstox) - * zjsonpatch (com.flipkart.zjsonpatch:zjsonpatch:0.4.6 - https://github.com/flipkart-incubator/zjsonpatch/) - * Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.9.2 - https://github.com/ben-manes/caffeine) + * Woodstox (com.fasterxml.woodstox:woodstox-core:6.5.1 - https://github.com/FasterXML/woodstox) + * zjsonpatch (com.flipkart.zjsonpatch:zjsonpatch:0.4.16 - https://github.com/flipkart-incubator/zjsonpatch/) + * Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.9.3 - https://github.com/ben-manes/caffeine) * btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf) * jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils) * jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils) @@ -54,7 +53,7 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * JCIP Annotations under Apache License (com.github.stephenc.jcip:jcip-annotations:1.0-1 - http://stephenc.github.com/jcip-annotations) * Google APIs Client Library for Java (com.google.api-client:google-api-client:1.23.0 - https://github.com/google/google-api-java-client/google-api-client) * Google Analytics API v3-rev145-1.23.0 (com.google.apis:google-api-services-analytics:v3-rev145-1.23.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-analytics) - * FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.1 - http://findbugs.sourceforge.net/) + * FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/) * Gson (com.google.code.gson:gson:2.9.0 - https://github.com/google/gson/gson) * error-prone annotations (com.google.errorprone:error_prone_annotations:2.18.0 - https://errorprone.info/error_prone_annotations) * Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess) @@ -64,25 +63,24 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * Google HTTP Client Library for Java (com.google.http-client:google-http-client:1.23.0 - https://github.com/google/google-http-java-client/google-http-client) * GSON extensions to the Google HTTP Client Library for Java. (com.google.http-client:google-http-client-gson:1.41.7 - https://github.com/googleapis/google-http-java-client/google-http-client-gson) * Jackson 2 extensions to the Google HTTP Client Library for Java. (com.google.http-client:google-http-client-jackson2:1.23.0 - https://github.com/google/google-http-java-client/google-http-client-jackson2) + * J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/) * J2ObjC Annotations (com.google.j2objc:j2objc-annotations:2.8 - https://github.com/google/j2objc/) * Google OAuth Client Library for Java (com.google.oauth-client:google-oauth-client:1.33.3 - https://github.com/googleapis/google-oauth-java-client/google-oauth-client) * ConcurrentLinkedHashMap (com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2 - http://code.google.com/p/concurrentlinkedhashmap) * libphonenumber (com.googlecode.libphonenumber:libphonenumber:8.11.1 - https://github.com/google/libphonenumber/) - * Jackcess (com.healthmarketscience.jackcess:jackcess:4.0.2 - https://jackcess.sourceforge.io) - * Jackcess Encrypt (com.healthmarketscience.jackcess:jackcess-encrypt:4.0.1 - http://jackcessencrypt.sf.net) - * project ':json-path' (com.jayway.jsonpath:json-path:2.6.0 - https://github.com/jayway/JsonPath) - * project ':json-path-assert' (com.jayway.jsonpath:json-path-assert:2.6.0 - https://github.com/jayway/JsonPath) + * Jackcess (com.healthmarketscience.jackcess:jackcess:4.0.5 - https://jackcess.sourceforge.io) + * Jackcess Encrypt (com.healthmarketscience.jackcess:jackcess-encrypt:4.0.2 - http://jackcessencrypt.sf.net) + * json-path (com.jayway.jsonpath:json-path:2.9.0 - https://github.com/jayway/JsonPath) + * json-path-assert (com.jayway.jsonpath:json-path-assert:2.9.0 - https://github.com/jayway/JsonPath) * Disruptor Framework (com.lmax:disruptor:3.4.2 - http://lmax-exchange.github.com/disruptor) - * builder-commons (com.lyncode:builder-commons:1.0.2 - http://nexus.sonatype.org/oss-repository-hosting.html/builder-commons) - * MaxMind DB Reader (com.maxmind.db:maxmind-db:1.2.2 - http://dev.maxmind.com/) - * MaxMind GeoIP2 API (com.maxmind.geoip2:geoip2:2.11.0 - http://dev.maxmind.com/geoip/geoip2/web-services) + * MaxMind DB Reader (com.maxmind.db:maxmind-db:2.1.0 - http://dev.maxmind.com/) + * MaxMind GeoIP2 API (com.maxmind.geoip2:geoip2:2.17.0 - https://dev.maxmind.com/geoip?lang=en) * Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt:7.9 - https://bitbucket.org/connect2id/nimbus-jose-jwt) - * opencsv (com.opencsv:opencsv:5.6 - http://opencsv.sf.net) + * opencsv (com.opencsv:opencsv:5.9 - http://opencsv.sf.net) * java-libpst (com.pff:java-libpst:0.9.3 - https://github.com/rjohnsondev/java-libpst) * rome (com.rometools:rome:1.19.0 - http://rometools.com/rome) * rome-modules (com.rometools:rome-modules:1.19.0 - http://rometools.com/rome-modules) * rome-utils (com.rometools:rome-utils:1.19.0 - http://rometools.com/rome-utils) - * fastinfoset (com.sun.xml.fastinfoset:FastInfoset:1.2.15 - http://fi.java.net) * T-Digest (com.tdunning:t-digest:3.1 - https://github.com/tdunning/t-digest) * config (com.typesafe:config:1.3.3 - https://github.com/lightbend/config) * ssl-config-core (com.typesafe:ssl-config-core_2.13:0.3.8 - https://github.com/lightbend/ssl-config) @@ -94,17 +92,17 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * akka-stream (com.typesafe.akka:akka-stream_2.13:2.5.31 - https://akka.io/) * scala-logging (com.typesafe.scala-logging:scala-logging_2.13:3.9.2 - https://github.com/lightbend/scala-logging) * JSON library from Android SDK (com.vaadin.external.google:android-json:0.0.20131108.vaadin1 - http://developer.android.com/sdk) - * SparseBitSet (com.zaxxer:SparseBitSet:1.2 - https://github.com/brettwooldridge/SparseBitSet) + * SparseBitSet (com.zaxxer:SparseBitSet:1.3 - https://github.com/brettwooldridge/SparseBitSet) * Apache Commons BeanUtils (commons-beanutils:commons-beanutils:1.9.4 - https://commons.apache.org/proper/commons-beanutils/) - * Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/) - * Apache Commons Codec (commons-codec:commons-codec:1.10 - http://commons.apache.org/proper/commons-codec/) + * Apache Commons CLI (commons-cli:commons-cli:1.6.0 - https://commons.apache.org/proper/commons-cli/) + * Apache Commons Codec (commons-codec:commons-codec:1.16.0 - https://commons.apache.org/proper/commons-codec/) * Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/) - * Commons Digester (commons-digester:commons-digester:1.8.1 - http://commons.apache.org/digester/) + * Commons Digester (commons-digester:commons-digester:2.1 - http://commons.apache.org/digester/) * Apache Commons FileUpload (commons-fileupload:commons-fileupload:1.5 - https://commons.apache.org/proper/commons-fileupload/) - * Apache Commons IO (commons-io:commons-io:2.7 - https://commons.apache.org/proper/commons-io/) + * Apache Commons IO (commons-io:commons-io:2.15.1 - https://commons.apache.org/proper/commons-io/) * Commons Lang (commons-lang:commons-lang:2.6 - http://commons.apache.org/lang/) - * Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/) - * Apache Commons Validator (commons-validator:commons-validator:1.5.0 - http://commons.apache.org/proper/commons-validator/) + * Apache Commons Logging (commons-logging:commons-logging:1.3.0 - https://commons.apache.org/proper/commons-logging/) + * Apache Commons Validator (commons-validator:commons-validator:1.7 - http://commons.apache.org/proper/commons-validator/) * GeoJson POJOs for Jackson (de.grundid.opendatalab:geojson-jackson:1.14 - https://github.com/opendatalab-de/geojson-jackson) * OpenAIRE Funders Model (eu.openaire:funders-model:2.0.0 - https://api.openaire.eu) * Metrics Core (io.dropwizard.metrics:metrics-core:4.1.5 - https://metrics.dropwizard.io/metrics-core) @@ -112,18 +110,24 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * Metrics Integration for Jetty 9.3 and higher (io.dropwizard.metrics:metrics-jetty9:4.1.5 - https://metrics.dropwizard.io/metrics-jetty9) * Metrics Integration with JMX (io.dropwizard.metrics:metrics-jmx:4.1.5 - https://metrics.dropwizard.io/metrics-jmx) * JVM Integration for Metrics (io.dropwizard.metrics:metrics-jvm:4.1.5 - https://metrics.dropwizard.io/metrics-jvm) - * micrometer-core (io.micrometer:micrometer-core:1.9.11 - https://github.com/micrometer-metrics/micrometer) - * Netty/Buffer (io.netty:netty-buffer:4.1.68.Final - https://netty.io/netty-buffer/) - * Netty/Codec (io.netty:netty-codec:4.1.68.Final - https://netty.io/netty-codec/) + * micrometer-core (io.micrometer:micrometer-core:1.9.17 - https://github.com/micrometer-metrics/micrometer) + * Netty/Buffer (io.netty:netty-buffer:4.1.106.Final - https://netty.io/netty-buffer/) + * Netty/Buffer (io.netty:netty-buffer:4.1.99.Final - https://netty.io/netty-buffer/) + * Netty/Codec (io.netty:netty-codec:4.1.106.Final - https://netty.io/netty-codec/) + * Netty/Codec (io.netty:netty-codec:4.1.99.Final - https://netty.io/netty-codec/) * Netty/Codec/HTTP (io.netty:netty-codec-http:4.1.53.Final - https://netty.io/netty-codec-http/) * Netty/Codec/Socks (io.netty:netty-codec-socks:4.1.53.Final - https://netty.io/netty-codec-socks/) - * Netty/Common (io.netty:netty-common:4.1.68.Final - https://netty.io/netty-common/) - * Netty/Handler (io.netty:netty-handler:4.1.68.Final - https://netty.io/netty-handler/) + * Netty/Common (io.netty:netty-common:4.1.106.Final - https://netty.io/netty-common/) + * Netty/Common (io.netty:netty-common:4.1.99.Final - https://netty.io/netty-common/) + * Netty/Handler (io.netty:netty-handler:4.1.106.Final - https://netty.io/netty-handler/) + * Netty/Handler (io.netty:netty-handler:4.1.99.Final - https://netty.io/netty-handler/) * Netty/Handler/Proxy (io.netty:netty-handler-proxy:4.1.53.Final - https://netty.io/netty-handler-proxy/) - * Netty/Resolver (io.netty:netty-resolver:4.1.68.Final - https://netty.io/netty-resolver/) - * Netty/Transport (io.netty:netty-transport:4.1.68.Final - https://netty.io/netty-transport/) - * Netty/Transport/Native/Epoll (io.netty:netty-transport-native-epoll:4.1.68.Final - https://netty.io/netty-transport-native-epoll/) - * Netty/Transport/Native/Unix/Common (io.netty:netty-transport-native-unix-common:4.1.68.Final - https://netty.io/netty-transport-native-unix-common/) + * Netty/Resolver (io.netty:netty-resolver:4.1.99.Final - https://netty.io/netty-resolver/) + * Netty/Transport (io.netty:netty-transport:4.1.106.Final - https://netty.io/netty-transport/) + * Netty/Transport (io.netty:netty-transport:4.1.99.Final - https://netty.io/netty-transport/) + * Netty/Transport/Native/Epoll (io.netty:netty-transport-native-epoll:4.1.99.Final - https://netty.io/netty-transport-native-epoll/) + * Netty/Transport/Native/Unix/Common (io.netty:netty-transport-native-unix-common:4.1.106.Final - https://netty.io/netty-transport-native-unix-common/) + * Netty/Transport/Native/Unix/Common (io.netty:netty-transport-native-unix-common:4.1.99.Final - https://netty.io/netty-transport-native-unix-common/) * OpenTracing API (io.opentracing:opentracing-api:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-api) * OpenTracing-noop (io.opentracing:opentracing-noop:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-noop) * OpenTracing-util (io.opentracing:opentracing-util:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-util) @@ -141,52 +145,57 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * swagger-parser-v2-converter (io.swagger.parser.v3:swagger-parser-v2-converter:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v2-converter) * swagger-parser-v3 (io.swagger.parser.v3:swagger-parser-v3:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v3) * Jakarta Bean Validation API (jakarta.validation:jakarta.validation-api:2.0.2 - https://beanvalidation.org) - * JSR107 API and SPI (javax.cache:cache-api:1.1.0 - https://github.com/jsr107/jsr107spec) + * JSR107 API and SPI (javax.cache:cache-api:1.1.1 - https://github.com/jsr107/jsr107spec) * javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/) * Bean Validation API (javax.validation:validation-api:2.0.1.Final - http://beanvalidation.org) * jdbm (jdbm:jdbm:1.0 - no url defined) - * Joda-Time (joda-time:joda-time:2.9.2 - http://www.joda.org/joda-time/) + * Joda-Time (joda-time:joda-time:2.12.5 - https://www.joda.org/joda-time/) * Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.11.13 - https://bytebuddy.net/byte-buddy) * Byte Buddy agent (net.bytebuddy:byte-buddy-agent:1.11.13 - https://bytebuddy.net/byte-buddy-agent) * eigenbase-properties (net.hydromatic:eigenbase-properties:1.1.5 - http://github.com/julianhyde/eigenbase-properties) * json-unit-core (net.javacrumbs.json-unit:json-unit-core:2.19.0 - https://github.com/lukas-krecan/JsonUnit/json-unit-core) * "Java Concurrency in Practice" book annotations (net.jcip:jcip-annotations:1.0 - http://jcip.net/) * ASM based accessors helper used by json-smart (net.minidev:accessors-smart:1.2 - http://www.minidev.net/) - * ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.4.7 - https://urielch.github.io/) + * ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.5.0 - https://urielch.github.io/) * JSON Small and Fast Parser (net.minidev:json-smart:2.3 - http://www.minidev.net/) - * JSON Small and Fast Parser (net.minidev:json-smart:2.4.7 - https://urielch.github.io/) + * JSON Small and Fast Parser (net.minidev:json-smart:2.5.0 - https://urielch.github.io/) * Abdera Core (org.apache.abdera:abdera-core:1.1.3 - http://abdera.apache.org/abdera-core) * I18N Libraries (org.apache.abdera:abdera-i18n:1.1.3 - http://abdera.apache.org) - * Apache Ant Core (org.apache.ant:ant:1.10.11 - https://ant.apache.org/) - * Apache Ant Launcher (org.apache.ant:ant-launcher:1.10.11 - https://ant.apache.org/) - * Apache Commons BCEL (org.apache.bcel:bcel:6.6.0 - https://commons.apache.org/proper/commons-bcel) - * Calcite Core (org.apache.calcite:calcite-core:1.27.0 - https://calcite.apache.org) - * Calcite Linq4j (org.apache.calcite:calcite-linq4j:1.27.0 - https://calcite.apache.org) - * Apache Calcite Avatica (org.apache.calcite.avatica:avatica-core:1.18.0 - https://calcite.apache.org/avatica) - * Apache Commons Collections (org.apache.commons:commons-collections4:4.1 - http://commons.apache.org/proper/commons-collections/) - * Apache Commons Compress (org.apache.commons:commons-compress:1.21 - https://commons.apache.org/proper/commons-compress/) - * Apache Commons Configuration (org.apache.commons:commons-configuration2:2.8.0 - https://commons.apache.org/proper/commons-configuration/) - * Apache Commons CSV (org.apache.commons:commons-csv:1.9.0 - https://commons.apache.org/proper/commons-csv/) - * Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.9.0 - https://commons.apache.org/dbcp/) + * Apache Ant Core (org.apache.ant:ant:1.10.14 - https://ant.apache.org/) + * Apache Ant Launcher (org.apache.ant:ant-launcher:1.10.14 - https://ant.apache.org/) + * Apache Commons BCEL (org.apache.bcel:bcel:6.7.0 - https://commons.apache.org/proper/commons-bcel) + * Calcite Core (org.apache.calcite:calcite-core:1.35.0 - https://calcite.apache.org) + * Calcite Linq4j (org.apache.calcite:calcite-linq4j:1.35.0 - https://calcite.apache.org) + * Apache Calcite Avatica (org.apache.calcite.avatica:avatica-core:1.23.0 - https://calcite.apache.org/avatica) + * Apache Calcite Avatica Metrics (org.apache.calcite.avatica:avatica-metrics:1.23.0 - https://calcite.apache.org/avatica) + * Apache Commons Collections (org.apache.commons:commons-collections4:4.4 - https://commons.apache.org/proper/commons-collections/) + * Apache Commons Compress (org.apache.commons:commons-compress:1.26.0 - https://commons.apache.org/proper/commons-compress/) + * Apache Commons Configuration (org.apache.commons:commons-configuration2:2.10.1 - https://commons.apache.org/proper/commons-configuration/) + * Apache Commons CSV (org.apache.commons:commons-csv:1.10.0 - https://commons.apache.org/proper/commons-csv/) + * Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.11.0 - https://commons.apache.org/dbcp/) * Apache Commons Exec (org.apache.commons:commons-exec:1.3 - http://commons.apache.org/proper/commons-exec/) - * Apache Commons Lang (org.apache.commons:commons-lang3:3.12.0 - https://commons.apache.org/proper/commons-lang/) + * Apache Commons Exec (org.apache.commons:commons-exec:1.4.0 - https://commons.apache.org/proper/commons-exec/) + * Apache Commons Lang (org.apache.commons:commons-lang3:3.14.0 - https://commons.apache.org/proper/commons-lang/) * Apache Commons Math (org.apache.commons:commons-math3:3.6.1 - http://commons.apache.org/proper/commons-math/) - * Apache Commons Pool (org.apache.commons:commons-pool2:2.11.1 - https://commons.apache.org/proper/commons-pool/) + * Apache Commons Pool (org.apache.commons:commons-pool2:2.12.0 - https://commons.apache.org/proper/commons-pool/) * Apache Commons Text (org.apache.commons:commons-text:1.10.0 - https://commons.apache.org/proper/commons-text) * Curator Client (org.apache.curator:curator-client:2.13.0 - http://curator.apache.org/curator-client) * Curator Framework (org.apache.curator:curator-framework:2.13.0 - http://curator.apache.org/curator-framework) * Curator Recipes (org.apache.curator:curator-recipes:2.13.0 - http://curator.apache.org/curator-recipes) - * Apache Hadoop Annotations (org.apache.hadoop:hadoop-annotations:3.2.2 - no url defined) - * Apache Hadoop Auth (org.apache.hadoop:hadoop-auth:3.2.2 - no url defined) - * Apache Hadoop Common (org.apache.hadoop:hadoop-common:3.2.2 - no url defined) - * Apache Hadoop HDFS Client (org.apache.hadoop:hadoop-hdfs-client:3.2.2 - no url defined) + * Apache Hadoop Annotations (org.apache.hadoop:hadoop-annotations:3.2.4 - no url defined) + * Apache Hadoop Auth (org.apache.hadoop:hadoop-auth:3.2.4 - no url defined) + * Apache Hadoop Common (org.apache.hadoop:hadoop-common:3.2.4 - no url defined) + * Apache Hadoop HDFS Client (org.apache.hadoop:hadoop-hdfs-client:3.2.4 - no url defined) * htrace-core4 (org.apache.htrace:htrace-core4:4.1.0-incubating - http://incubator.apache.org/projects/htrace.html) - * Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.13 - http://hc.apache.org/httpcomponents-client) + * Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.14 - http://hc.apache.org/httpcomponents-client-ga) * Apache HttpClient Cache (org.apache.httpcomponents:httpclient-cache:4.2.6 - http://hc.apache.org/httpcomponents-client) - * Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.15 - http://hc.apache.org/httpcomponents-core-ga) - * Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.5.13 - http://hc.apache.org/httpcomponents-client) - * Apache James :: Mime4j :: Core (org.apache.james:apache-mime4j-core:0.8.4 - http://james.apache.org/mime4j/apache-mime4j-core) - * Apache James :: Mime4j :: DOM (org.apache.james:apache-mime4j-dom:0.8.4 - http://james.apache.org/mime4j/apache-mime4j-dom) + * Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.16 - http://hc.apache.org/httpcomponents-core-ga) + * Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.5.14 - http://hc.apache.org/httpcomponents-client-ga) + * Apache HttpClient (org.apache.httpcomponents.client5:httpclient5:5.1.3 - https://hc.apache.org/httpcomponents-client-5.0.x/5.1.3/httpclient5/) + * Apache HttpComponents Core HTTP/1.1 (org.apache.httpcomponents.core5:httpcore5:5.1.3 - https://hc.apache.org/httpcomponents-core-5.1.x/5.1.3/httpcore5/) + * Apache HttpComponents Core HTTP/2 (org.apache.httpcomponents.core5:httpcore5-h2:5.1.3 - https://hc.apache.org/httpcomponents-core-5.1.x/5.1.3/httpcore5-h2/) + * Apache James :: Mime4j :: Core (org.apache.james:apache-mime4j-core:0.8.10 - http://james.apache.org/mime4j/apache-mime4j-core) + * Apache James :: Mime4j :: DOM (org.apache.james:apache-mime4j-dom:0.8.11 - http://james.apache.org/mime4j/apache-mime4j-dom) * Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:2.13.0 - http://jena.apache.org/apache-jena-libs/) * Apache Jena - ARQ (SPARQL 1.1 Query Engine) (org.apache.jena:jena-arq:2.13.0 - http://jena.apache.org/jena-arq/) * Apache Jena - Core (org.apache.jena:jena-core:2.13.0 - http://jena.apache.org/jena-core/) @@ -196,86 +205,86 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * Kerby-kerb Util (org.apache.kerby:kerb-util:1.0.1 - http://directory.apache.org/kerby/kerby-kerb/kerb-util) * Kerby ASN1 Project (org.apache.kerby:kerby-asn1:1.0.1 - http://directory.apache.org/kerby/kerby-common/kerby-asn1) * Kerby PKIX Project (org.apache.kerby:kerby-pkix:1.0.1 - http://directory.apache.org/kerby/kerby-pkix) - * Apache Log4j 1.x Compatibility API (org.apache.logging.log4j:log4j-1.2-api:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-1.2-api/) - * Apache Log4j API (org.apache.logging.log4j:log4j-api:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-api/) - * Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-core/) - * Apache Log4j JUL Adapter (org.apache.logging.log4j:log4j-jul:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-jul/) - * Apache Log4j Layout for JSON template (org.apache.logging.log4j:log4j-layout-template-json:2.17.1 - https://logging.apache.org/log4j/2.x/log4j-layout-template-json/) - * Apache Log4j SLF4J Binding (org.apache.logging.log4j:log4j-slf4j-impl:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/) - * Apache Log4j Web (org.apache.logging.log4j:log4j-web:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-web/) - * Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-common) - * Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-icu) - * Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji) - * Lucene Nori Korean Morphological Analyzer (org.apache.lucene:lucene-analyzers-nori:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-nori) - * Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic) - * Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn) - * Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-stempel) - * Lucene Memory (org.apache.lucene:lucene-backward-codecs:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-backward-codecs) - * Lucene Classification (org.apache.lucene:lucene-classification:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-classification) - * Lucene codecs (org.apache.lucene:lucene-codecs:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-codecs) - * Lucene Core (org.apache.lucene:lucene-core:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-core) - * Lucene Expressions (org.apache.lucene:lucene-expressions:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-expressions) - * Lucene Grouping (org.apache.lucene:lucene-grouping:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-grouping) - * Lucene Highlighter (org.apache.lucene:lucene-highlighter:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-highlighter) - * Lucene Join (org.apache.lucene:lucene-join:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-join) - * Lucene Memory (org.apache.lucene:lucene-memory:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-memory) - * Lucene Miscellaneous (org.apache.lucene:lucene-misc:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-misc) - * Lucene Queries (org.apache.lucene:lucene-queries:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-queries) - * Lucene QueryParsers (org.apache.lucene:lucene-queryparser:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-queryparser) - * Lucene Sandbox (org.apache.lucene:lucene-sandbox:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-sandbox) - * Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-spatial-extras) - * Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-spatial3d) - * Lucene Suggest (org.apache.lucene:lucene-suggest:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-suggest) - * Apache FontBox (org.apache.pdfbox:fontbox:2.0.28 - http://pdfbox.apache.org/) + * Apache Log4j 1.x Compatibility API (org.apache.logging.log4j:log4j-1.2-api:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-1.2-api/) + * Apache Log4j API (org.apache.logging.log4j:log4j-api:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-api/) + * Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-core/) + * Apache Log4j JUL Adapter (org.apache.logging.log4j:log4j-jul:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-jul/) + * Apache Log4j Layout for JSON template (org.apache.logging.log4j:log4j-layout-template-json:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-layout-template-json/) + * Apache Log4j SLF4J Binding (org.apache.logging.log4j:log4j-slf4j-impl:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-slf4j-impl/) + * Apache Log4j Web (org.apache.logging.log4j:log4j-web:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-web/) + * Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-common) + * Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-icu) + * Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji) + * Lucene Nori Korean Morphological Analyzer (org.apache.lucene:lucene-analyzers-nori:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-nori) + * Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic) + * Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn) + * Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-stempel) + * Lucene Memory (org.apache.lucene:lucene-backward-codecs:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-backward-codecs) + * Lucene Classification (org.apache.lucene:lucene-classification:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-classification) + * Lucene codecs (org.apache.lucene:lucene-codecs:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-codecs) + * Lucene Core (org.apache.lucene:lucene-core:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-core) + * Lucene Expressions (org.apache.lucene:lucene-expressions:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-expressions) + * Lucene Grouping (org.apache.lucene:lucene-grouping:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-grouping) + * Lucene Highlighter (org.apache.lucene:lucene-highlighter:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-highlighter) + * Lucene Join (org.apache.lucene:lucene-join:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-join) + * Lucene Memory (org.apache.lucene:lucene-memory:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-memory) + * Lucene Miscellaneous (org.apache.lucene:lucene-misc:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-misc) + * Lucene Queries (org.apache.lucene:lucene-queries:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-queries) + * Lucene QueryParsers (org.apache.lucene:lucene-queryparser:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-queryparser) + * Lucene Sandbox (org.apache.lucene:lucene-sandbox:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-sandbox) + * Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-spatial-extras) + * Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-spatial3d) + * Lucene Suggest (org.apache.lucene:lucene-suggest:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-suggest) + * Apache FontBox (org.apache.pdfbox:fontbox:2.0.31 - http://pdfbox.apache.org/) * PDFBox JBIG2 ImageIO plugin (org.apache.pdfbox:jbig2-imageio:3.0.4 - https://www.apache.org/jbig2-imageio/) * Apache JempBox (org.apache.pdfbox:jempbox:1.8.17 - http://www.apache.org/pdfbox-parent/jempbox/) - * Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.28 - https://www.apache.org/pdfbox-parent/pdfbox/) - * Apache PDFBox tools (org.apache.pdfbox:pdfbox-tools:2.0.27 - https://www.apache.org/pdfbox-parent/pdfbox-tools/) - * Apache XmpBox (org.apache.pdfbox:xmpbox:2.0.27 - https://www.apache.org/pdfbox-parent/xmpbox/) - * Apache POI - Common (org.apache.poi:poi:5.2.3 - https://poi.apache.org/) - * Apache POI - API based on OPC and OOXML schemas (org.apache.poi:poi-ooxml:5.2.3 - https://poi.apache.org/) - * Apache POI (org.apache.poi:poi-ooxml-lite:5.2.3 - https://poi.apache.org/) - * Apache POI (org.apache.poi:poi-scratchpad:5.2.3 - https://poi.apache.org/) - * Apache Solr Core (org.apache.solr:solr-core:8.11.2 - https://lucene.apache.org/solr-parent/solr-core) - * Apache Solr Solrj (org.apache.solr:solr-solrj:8.11.2 - https://lucene.apache.org/solr-parent/solr-solrj) + * Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.31 - https://www.apache.org/pdfbox-parent/pdfbox/) + * Apache PDFBox tools (org.apache.pdfbox:pdfbox-tools:2.0.31 - https://www.apache.org/pdfbox-parent/pdfbox-tools/) + * Apache XmpBox (org.apache.pdfbox:xmpbox:2.0.31 - https://www.apache.org/pdfbox-parent/xmpbox/) + * Apache POI - Common (org.apache.poi:poi:5.2.5 - https://poi.apache.org/) + * Apache POI - API based on OPC and OOXML schemas (org.apache.poi:poi-ooxml:5.2.5 - https://poi.apache.org/) + * Apache POI (org.apache.poi:poi-ooxml-lite:5.2.5 - https://poi.apache.org/) + * Apache POI (org.apache.poi:poi-scratchpad:5.2.5 - https://poi.apache.org/) + * Apache Solr Core (org.apache.solr:solr-core:8.11.3 - https://lucene.apache.org/solr-parent/solr-core) + * Apache Solr Solrj (org.apache.solr:solr-solrj:8.11.3 - https://lucene.apache.org/solr-parent/solr-solrj) * Apache Standard Taglib Implementation (org.apache.taglibs:taglibs-standard-impl:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-impl) * Apache Standard Taglib Specification API (org.apache.taglibs:taglibs-standard-spec:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-spec) * Apache Thrift (org.apache.thrift:libthrift:0.9.2 - http://thrift.apache.org) - * Apache Tika core (org.apache.tika:tika-core:2.5.0 - https://tika.apache.org/) - * Apache Tika Apple parser module (org.apache.tika:tika-parser-apple-module:2.5.0 - https://tika.apache.org/tika-parser-apple-module/) - * Apache Tika audiovideo parser module (org.apache.tika:tika-parser-audiovideo-module:2.5.0 - https://tika.apache.org/tika-parser-audiovideo-module/) - * Apache Tika cad parser module (org.apache.tika:tika-parser-cad-module:2.5.0 - https://tika.apache.org/tika-parser-cad-module/) - * Apache Tika code parser module (org.apache.tika:tika-parser-code-module:2.5.0 - https://tika.apache.org/tika-parser-code-module/) - * Apache Tika crypto parser module (org.apache.tika:tika-parser-crypto-module:2.5.0 - https://tika.apache.org/tika-parser-crypto-module/) - * Apache Tika digest commons (org.apache.tika:tika-parser-digest-commons:2.5.0 - https://tika.apache.org/tika-parser-digest-commons/) - * Apache Tika font parser module (org.apache.tika:tika-parser-font-module:2.5.0 - https://tika.apache.org/tika-parser-font-module/) - * Apache Tika html parser module (org.apache.tika:tika-parser-html-module:2.5.0 - https://tika.apache.org/tika-parser-html-module/) - * Apache Tika image parser module (org.apache.tika:tika-parser-image-module:2.5.0 - https://tika.apache.org/tika-parser-image-module/) - * Apache Tika mail commons (org.apache.tika:tika-parser-mail-commons:2.5.0 - https://tika.apache.org/tika-parser-mail-commons/) - * Apache Tika mail parser module (org.apache.tika:tika-parser-mail-module:2.5.0 - https://tika.apache.org/tika-parser-mail-module/) - * Apache Tika Microsoft parser module (org.apache.tika:tika-parser-microsoft-module:2.5.0 - https://tika.apache.org/tika-parser-microsoft-module/) - * Apache Tika miscellaneous office format parser module (org.apache.tika:tika-parser-miscoffice-module:2.5.0 - https://tika.apache.org/tika-parser-miscoffice-module/) - * Apache Tika news parser module (org.apache.tika:tika-parser-news-module:2.5.0 - https://tika.apache.org/tika-parser-news-module/) - * Apache Tika OCR parser module (org.apache.tika:tika-parser-ocr-module:2.5.0 - https://tika.apache.org/tika-parser-ocr-module/) - * Apache Tika PDF parser module (org.apache.tika:tika-parser-pdf-module:2.5.0 - https://tika.apache.org/tika-parser-pdf-module/) - * Apache Tika package parser module (org.apache.tika:tika-parser-pkg-module:2.5.0 - https://tika.apache.org/tika-parser-pkg-module/) - * Apache Tika text parser module (org.apache.tika:tika-parser-text-module:2.5.0 - https://tika.apache.org/tika-parser-text-module/) - * Apache Tika WARC parser module (org.apache.tika:tika-parser-webarchive-module:2.5.0 - https://tika.apache.org/tika-parser-webarchive-module/) - * Apache Tika XML parser module (org.apache.tika:tika-parser-xml-module:2.5.0 - https://tika.apache.org/tika-parser-xml-module/) - * Apache Tika XMP commons (org.apache.tika:tika-parser-xmp-commons:2.5.0 - https://tika.apache.org/tika-parser-xmp-commons/) - * Apache Tika ZIP commons (org.apache.tika:tika-parser-zip-commons:2.5.0 - https://tika.apache.org/tika-parser-zip-commons/) - * Apache Tika standard parser package (org.apache.tika:tika-parsers-standard-package:2.5.0 - https://tika.apache.org/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/) - * tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:9.0.75 - https://tomcat.apache.org/) - * tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:9.0.75 - https://tomcat.apache.org/) - * tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:9.0.75 - https://tomcat.apache.org/) + * Apache Tika core (org.apache.tika:tika-core:2.9.2 - https://tika.apache.org/) + * Apache Tika Apple parser module (org.apache.tika:tika-parser-apple-module:2.9.2 - https://tika.apache.org/tika-parser-apple-module/) + * Apache Tika audiovideo parser module (org.apache.tika:tika-parser-audiovideo-module:2.9.2 - https://tika.apache.org/tika-parser-audiovideo-module/) + * Apache Tika cad parser module (org.apache.tika:tika-parser-cad-module:2.9.2 - https://tika.apache.org/tika-parser-cad-module/) + * Apache Tika code parser module (org.apache.tika:tika-parser-code-module:2.9.2 - https://tika.apache.org/tika-parser-code-module/) + * Apache Tika crypto parser module (org.apache.tika:tika-parser-crypto-module:2.9.2 - https://tika.apache.org/tika-parser-crypto-module/) + * Apache Tika digest commons (org.apache.tika:tika-parser-digest-commons:2.9.2 - https://tika.apache.org/tika-parser-digest-commons/) + * Apache Tika font parser module (org.apache.tika:tika-parser-font-module:2.9.2 - https://tika.apache.org/tika-parser-font-module/) + * Apache Tika html parser module (org.apache.tika:tika-parser-html-module:2.9.2 - https://tika.apache.org/tika-parser-html-module/) + * Apache Tika image parser module (org.apache.tika:tika-parser-image-module:2.9.2 - https://tika.apache.org/tika-parser-image-module/) + * Apache Tika mail commons (org.apache.tika:tika-parser-mail-commons:2.9.2 - https://tika.apache.org/tika-parser-mail-commons/) + * Apache Tika mail parser module (org.apache.tika:tika-parser-mail-module:2.9.2 - https://tika.apache.org/tika-parser-mail-module/) + * Apache Tika Microsoft parser module (org.apache.tika:tika-parser-microsoft-module:2.9.2 - https://tika.apache.org/tika-parser-microsoft-module/) + * Apache Tika miscellaneous office format parser module (org.apache.tika:tika-parser-miscoffice-module:2.9.2 - https://tika.apache.org/tika-parser-miscoffice-module/) + * Apache Tika news parser module (org.apache.tika:tika-parser-news-module:2.9.2 - https://tika.apache.org/tika-parser-news-module/) + * Apache Tika OCR parser module (org.apache.tika:tika-parser-ocr-module:2.9.2 - https://tika.apache.org/tika-parser-ocr-module/) + * Apache Tika PDF parser module (org.apache.tika:tika-parser-pdf-module:2.9.2 - https://tika.apache.org/tika-parser-pdf-module/) + * Apache Tika package parser module (org.apache.tika:tika-parser-pkg-module:2.9.2 - https://tika.apache.org/tika-parser-pkg-module/) + * Apache Tika text parser module (org.apache.tika:tika-parser-text-module:2.9.2 - https://tika.apache.org/tika-parser-text-module/) + * Apache Tika WARC parser module (org.apache.tika:tika-parser-webarchive-module:2.9.2 - https://tika.apache.org/tika-parser-webarchive-module/) + * Apache Tika XML parser module (org.apache.tika:tika-parser-xml-module:2.9.2 - https://tika.apache.org/tika-parser-xml-module/) + * Apache Tika XMP commons (org.apache.tika:tika-parser-xmp-commons:2.9.2 - https://tika.apache.org/tika-parser-xmp-commons/) + * Apache Tika ZIP commons (org.apache.tika:tika-parser-zip-commons:2.9.2 - https://tika.apache.org/tika-parser-zip-commons/) + * Apache Tika standard parser package (org.apache.tika:tika-parsers-standard-package:2.9.2 - https://tika.apache.org/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/) + * tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:9.0.83 - https://tomcat.apache.org/) + * tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:9.0.83 - https://tomcat.apache.org/) + * tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:9.0.83 - https://tomcat.apache.org/) * Apache Velocity - Engine (org.apache.velocity:velocity-engine-core:2.3 - http://velocity.apache.org/engine/devel/velocity-engine-core/) * Apache Velocity - JSR 223 Scripting (org.apache.velocity:velocity-engine-scripting:2.2 - http://velocity.apache.org/engine/devel/velocity-engine-scripting/) * Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.22 - http://ws.apache.org/axiom/) * Abdera Model (FOM) Implementation (org.apache.ws.commons.axiom:fom-impl:1.2.22 - http://ws.apache.org/axiom/implementations/fom-impl/) - * XmlBeans (org.apache.xmlbeans:xmlbeans:5.1.1 - https://xmlbeans.apache.org/) + * XmlBeans (org.apache.xmlbeans:xmlbeans:5.2.0 - https://xmlbeans.apache.org/) * Apache ZooKeeper - Server (org.apache.zookeeper:zookeeper:3.6.2 - http://zookeeper.apache.org/zookeeper) * Apache ZooKeeper - Jute (org.apache.zookeeper:zookeeper-jute:3.6.2 - http://zookeeper.apache.org/zookeeper-jute) - * org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.0 - https://github.com/apiguardian-team/apiguardian) + * org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.2 - https://github.com/apiguardian-team/apiguardian) * AssertJ fluent assertions (org.assertj:assertj-core:3.22.0 - https://assertj.github.io/doc/assertj-core/) * Evo Inflector (org.atteo:evo-inflector:1.3 - http://atteo.org/static/evo-inflector) * jose4j (org.bitbucket.b_c:jose4j:0.6.5 - https://bitbucket.org/b_c/jose4j/) @@ -284,49 +293,50 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * rfc3986-uri (org.dmfs:rfc3986-uri:0.8.1 - https://github.com/dmfs/uri-toolkit) * Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Apache :: JSTL module (org.eclipse.jetty:apache-jstl:9.4.15.v20190215 - http://tomcat.apache.org/taglibs/standard/) - * Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client) - * Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client) - * Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server) - * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) - * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) + * Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client) + * Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client) + * Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server) + * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) + * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) * Jetty :: Servlet Annotations (org.eclipse.jetty:jetty-annotations:9.4.15.v20190215 - http://www.eclipse.org/jetty) - * Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-client) - * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-continuation) - * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-continuation) - * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-deploy) - * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-http) - * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-io) - * Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-jmx) + * Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-client) + * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-continuation) + * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-continuation) + * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-deploy) + * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-http) + * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-io) + * Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-jmx) * Jetty :: JNDI Naming (org.eclipse.jetty:jetty-jndi:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Plus (org.eclipse.jetty:jetty-plus:9.4.15.v20190215 - http://www.eclipse.org/jetty) - * Jetty :: Rewrite Handler (org.eclipse.jetty:jetty-rewrite:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-rewrite) - * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-security) - * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-security) - * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-server) - * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-servlet) - * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-servlets) - * Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-util) - * Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-util-ajax) - * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-webapp) - * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-xml) - * Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-client) - * Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.51.v20230217 - https://eclipse.org/jetty/http2-parent/http2-common) - * Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-hpack) - * Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport) - * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.51.v20230217 - https://eclipse.org/jetty/http2-parent/http2-server) + * Jetty :: Rewrite Handler (org.eclipse.jetty:jetty-rewrite:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-rewrite) + * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-security) + * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-security) + * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-server) + * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-servlet) + * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-servlets) + * Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util) + * Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util-ajax) + * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-webapp) + * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-xml) + * Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-client) + * Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.54.v20240208 - https://eclipse.org/jetty/http2-parent/http2-common) + * Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-hpack) + * Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport) + * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.54.v20240208 - https://eclipse.org/jetty/http2-parent/http2-server) * Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas) - * Ehcache (org.ehcache:ehcache:3.4.0 - http://ehcache.org) - * flyway-core (org.flywaydb:flyway-core:8.4.4 - https://flywaydb.org/flyway-core) + * Ehcache (org.ehcache:ehcache:3.10.8 - http://ehcache.org) + * flyway-core (org.flywaydb:flyway-core:8.5.13 - https://flywaydb.org/flyway-core) * Ogg and Vorbis for Java, Core (org.gagravarr:vorbis-java-core:0.8 - https://github.com/Gagravarr/VorbisJava) * Apache Tika plugin for Ogg, Vorbis and FLAC (org.gagravarr:vorbis-java-tika:0.8 - https://github.com/Gagravarr/VorbisJava) - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * Hibernate Validator Engine (org.hibernate.validator:hibernate-validator:6.2.5.Final - http://hibernate.org/validator/hibernate-validator) * Hibernate Validator Portable Extension (org.hibernate.validator:hibernate-validator-cdi:6.2.5.Final - http://hibernate.org/validator/hibernate-validator-cdi) + * org.immutables.value-annotations (org.immutables:value-annotations:2.9.2 - http://immutables.org/value-annotations) * leveldb (org.iq80.leveldb:leveldb:0.12 - http://github.com/dain/leveldb/leveldb) * leveldb-api (org.iq80.leveldb:leveldb-api:0.12 - http://github.com/dain/leveldb/leveldb-api) - * Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/) + * Javassist (org.javassist:javassist:3.29.0-GA - http://www.javassist.org/) * Java Annotation Indexer (org.jboss:jandex:2.4.2.Final - http://www.jboss.org/jandex) * JBoss Logging 3 (org.jboss.logging:jboss-logging:3.4.3.Final - http://www.jboss.org) * JDOM (org.jdom:jdom2:2.0.6.1 - http://www.jdom.org) @@ -335,6 +345,7 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * jtwig-spring (org.jtwig:jtwig-spring:5.87.0.RELEASE - http://jtwig.org) * jtwig-spring-boot-starter (org.jtwig:jtwig-spring-boot-starter:5.87.0.RELEASE - http://jtwig.org) * jtwig-web (org.jtwig:jtwig-web:5.87.0.RELEASE - http://jtwig.org) + * Proj4J (org.locationtech.proj4j:proj4j:1.1.5 - https://github.com/locationtech/proj4j) * Spatial4J (org.locationtech.spatial4j:spatial4j:0.7 - https://projects.eclipse.org/projects/locationtech.spatial4j) * MockServer Java Client (org.mock-server:mockserver-client-java:5.11.2 - http://www.mock-server.com) * MockServer Core (org.mock-server:mockserver-core:5.11.2 - http://www.mock-server.com) @@ -346,12 +357,12 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-servlet-tester) * Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util) * Servlet Specification API (org.mortbay.jetty:servlet-api:2.5-20081211 - http://jetty.mortbay.org/servlet-api) - * jwarc (org.netpreserve:jwarc:0.19.0 - https://github.com/iipc/jwarc) + * jwarc (org.netpreserve:jwarc:0.29.0 - https://github.com/iipc/jwarc) * Objenesis (org.objenesis:objenesis:3.2 - http://objenesis.org/objenesis) * parboiled-core (org.parboiled:parboiled-core:1.3.1 - http://parboiled.org) * parboiled-java (org.parboiled:parboiled-java:1.3.1 - http://parboiled.org) * RRD4J (org.rrd4j:rrd4j:3.5 - https://github.com/rrd4j/rrd4j/) - * Scala Library (org.scala-lang:scala-library:2.13.9 - https://www.scala-lang.org/) + * Scala Library (org.scala-lang:scala-library:2.13.11 - https://www.scala-lang.org/) * Scala Compiler (org.scala-lang:scala-reflect:2.13.0 - https://www.scala-lang.org/) * scala-collection-compat (org.scala-lang.modules:scala-collection-compat_2.13:2.1.6 - http://www.scala-lang.org/) * scala-java8-compat (org.scala-lang.modules:scala-java8-compat_2.13:0.9.0 - http://www.scala-lang.org/) @@ -359,58 +370,55 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * scala-xml (org.scala-lang.modules:scala-xml_2.13:1.3.0 - http://www.scala-lang.org/) * JSONassert (org.skyscreamer:jsonassert:1.5.1 - https://github.com/skyscreamer/JSONassert) * JCL 1.2 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.36 - http://www.slf4j.org) - * Spring AOP (org.springframework:spring-aop:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Beans (org.springframework:spring-beans:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Context (org.springframework:spring-context:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Context Support (org.springframework:spring-context-support:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Core (org.springframework:spring-core:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Expression Language (SpEL) (org.springframework:spring-expression:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Commons Logging Bridge (org.springframework:spring-jcl:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring JDBC (org.springframework:spring-jdbc:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Object/Relational Mapping (org.springframework:spring-orm:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring TestContext Framework (org.springframework:spring-test:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Transaction (org.springframework:spring-tx:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Web (org.springframework:spring-web:5.3.27 - https://github.com/spring-projects/spring-framework) - * Spring Web MVC (org.springframework:spring-webmvc:5.3.27 - https://github.com/spring-projects/spring-framework) - * spring-boot (org.springframework.boot:spring-boot:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-actuator (org.springframework.boot:spring-boot-actuator:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-actuator-autoconfigure (org.springframework.boot:spring-boot-actuator-autoconfigure:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:2.7.12 - https://spring.io/projects/spring-boot) + * Spring AOP (org.springframework:spring-aop:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Beans (org.springframework:spring-beans:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Context (org.springframework:spring-context:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Context Support (org.springframework:spring-context-support:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Core (org.springframework:spring-core:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Expression Language (SpEL) (org.springframework:spring-expression:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Commons Logging Bridge (org.springframework:spring-jcl:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring JDBC (org.springframework:spring-jdbc:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Object/Relational Mapping (org.springframework:spring-orm:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring TestContext Framework (org.springframework:spring-test:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Transaction (org.springframework:spring-tx:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Web (org.springframework:spring-web:5.3.34 - https://github.com/spring-projects/spring-framework) + * Spring Web MVC (org.springframework:spring-webmvc:5.3.34 - https://github.com/spring-projects/spring-framework) + * spring-boot (org.springframework.boot:spring-boot:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-actuator (org.springframework.boot:spring-boot-actuator:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-actuator-autoconfigure (org.springframework.boot:spring-boot-actuator-autoconfigure:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:2.7.18 - https://spring.io/projects/spring-boot) * Spring Boot Configuration Processor (org.springframework.boot:spring-boot-configuration-processor:2.0.0.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-tools/spring-boot-configuration-processor) - * spring-boot-starter (org.springframework.boot:spring-boot-starter:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-actuator (org.springframework.boot:spring-boot-starter-actuator:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-aop (org.springframework.boot:spring-boot-starter-aop:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-cache (org.springframework.boot:spring-boot-starter-cache:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-data-rest (org.springframework.boot:spring-boot-starter-data-rest:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-log4j2 (org.springframework.boot:spring-boot-starter-log4j2:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-security (org.springframework.boot:spring-boot-starter-security:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-test (org.springframework.boot:spring-boot-test:2.7.12 - https://spring.io/projects/spring-boot) - * spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:2.7.12 - https://spring.io/projects/spring-boot) - * Spring Data Core (org.springframework.data:spring-data-commons:2.7.12 - https://www.spring.io/spring-data/spring-data-commons) - * Spring Data REST - Core (org.springframework.data:spring-data-rest-core:3.7.12 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-core) - * Spring Data REST - WebMVC (org.springframework.data:spring-data-rest-webmvc:3.7.12 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc) - * Spring HATEOAS (org.springframework.hateoas:spring-hateoas:1.5.4 - https://github.com/spring-projects/spring-hateoas) + * spring-boot-starter (org.springframework.boot:spring-boot-starter:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-actuator (org.springframework.boot:spring-boot-starter-actuator:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-aop (org.springframework.boot:spring-boot-starter-aop:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-cache (org.springframework.boot:spring-boot-starter-cache:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-data-rest (org.springframework.boot:spring-boot-starter-data-rest:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-log4j2 (org.springframework.boot:spring-boot-starter-log4j2:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-security (org.springframework.boot:spring-boot-starter-security:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-test (org.springframework.boot:spring-boot-test:2.7.18 - https://spring.io/projects/spring-boot) + * spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:2.7.18 - https://spring.io/projects/spring-boot) + * Spring Data Core (org.springframework.data:spring-data-commons:2.7.18 - https://www.spring.io/spring-data/spring-data-commons) + * Spring Data REST - Core (org.springframework.data:spring-data-rest-core:3.7.18 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-core) + * Spring Data REST - WebMVC (org.springframework.data:spring-data-rest-webmvc:3.7.18 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc) + * Spring HATEOAS (org.springframework.hateoas:spring-hateoas:1.5.6 - https://github.com/spring-projects/spring-hateoas) * Spring Plugin - Core (org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE - https://github.com/spring-projects/spring-plugin/spring-plugin-core) - * spring-security-config (org.springframework.security:spring-security-config:5.7.8 - https://spring.io/projects/spring-security) - * spring-security-core (org.springframework.security:spring-security-core:5.7.8 - https://spring.io/projects/spring-security) - * spring-security-crypto (org.springframework.security:spring-security-crypto:5.7.8 - https://spring.io/projects/spring-security) - * spring-security-test (org.springframework.security:spring-security-test:5.7.8 - https://spring.io/projects/spring-security) - * spring-security-web (org.springframework.security:spring-security-web:5.7.8 - https://spring.io/projects/spring-security) + * spring-security-config (org.springframework.security:spring-security-config:5.7.11 - https://spring.io/projects/spring-security) + * spring-security-core (org.springframework.security:spring-security-core:5.7.11 - https://spring.io/projects/spring-security) + * spring-security-crypto (org.springframework.security:spring-security-crypto:5.7.11 - https://spring.io/projects/spring-security) + * spring-security-test (org.springframework.security:spring-security-test:5.7.11 - https://spring.io/projects/spring-security) + * spring-security-web (org.springframework.security:spring-security-web:5.7.11 - https://spring.io/projects/spring-security) * SWORD v2 :: Common Server Library (org.swordapp:sword2-server:1.0 - http://www.swordapp.org/) - * snappy-java (org.xerial.snappy:snappy-java:1.1.7.6 - https://github.com/xerial/snappy-java) + * snappy-java (org.xerial.snappy:snappy-java:1.1.10.1 - https://github.com/xerial/snappy-java) * xml-matchers (org.xmlmatchers:xml-matchers:0.10 - http://code.google.com/p/xml-matchers/) - * org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.8.0 - https://www.xmlunit.org/) + * org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.10.0 - https://www.xmlunit.org/) * org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.9.1 - https://www.xmlunit.org/) * org.xmlunit:xmlunit-placeholders (org.xmlunit:xmlunit-placeholders:2.8.0 - https://www.xmlunit.org/xmlunit-placeholders/) * SnakeYAML (org.yaml:snakeyaml:1.30 - https://bitbucket.org/snakeyaml/snakeyaml) * software.amazon.ion:ion-java (software.amazon.ion:ion-java:1.0.2 - https://github.com/amznlabs/ion-java/) - * Xalan Java Serializer (xalan:serializer:2.7.2 - http://xml.apache.org/xalan-j/) - * xalan (xalan:xalan:2.7.0 - no url defined) - * Xalan Java (xalan:xalan:2.7.2 - http://xml.apache.org/xalan-j/) * Xerces2-j (xerces:xercesImpl:2.12.2 - https://xerces.apache.org/xerces2-j/) * XML Commons External Components XML APIs (xml-apis:xml-apis:1.4.01 - http://xml.apache.org/commons/components/external/) @@ -421,29 +429,28 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * coverity-escapers (com.coverity.security:coverity-escapers:1.1.1 - http://coverity.com/security) * Java Advanced Imaging Image I/O Tools API core (standalone) (com.github.jai-imageio:jai-imageio-core:1.4.0 - https://github.com/jai-imageio/jai-imageio-core) * JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.5.1 - http://github.com/jsonld-java/jsonld-java/jsonld-java/) - * curvesapi (com.github.virtuald:curvesapi:1.07 - https://github.com/virtuald/curvesapi) - * Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.11.0 - https://developers.google.com/protocol-buffers/protobuf-java/) + * curvesapi (com.github.virtuald:curvesapi:1.08 - https://github.com/virtuald/curvesapi) + * Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.15.0 - https://developers.google.com/protocol-buffers/protobuf-java/) * JZlib (com.jcraft:jzlib:1.1.3 - http://www.jcraft.com/jzlib/) - * dnsjava (dnsjava:dnsjava:2.1.7 - http://www.dnsjava.org) - * jaxen (jaxen:jaxen:1.1.6 - http://jaxen.codehaus.org/) + * dnsjava (dnsjava:dnsjava:2.1.9 - http://www.dnsjava.org) + * jaxen (jaxen:jaxen:2.0.0 - http://www.cafeconleche.org/jaxen/jaxen) * ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.5.1-1 - http://www.antlr.org/antlr4-runtime) - * commons-compiler (org.codehaus.janino:commons-compiler:3.0.9 - http://janino-compiler.github.io/commons-compiler/) - * janino (org.codehaus.janino:janino:3.0.9 - http://janino-compiler.github.io/janino/) + * commons-compiler (org.codehaus.janino:commons-compiler:3.1.8 - http://janino-compiler.github.io/commons-compiler/) + * janino (org.codehaus.janino:janino:3.1.8 - http://janino-compiler.github.io/janino/) * Stax2 API (org.codehaus.woodstox:stax2-api:4.2.1 - http://github.com/FasterXML/stax2-api) - * Hamcrest Date (org.exparity:hamcrest-date:2.0.7 - https://github.com/exparity/hamcrest-date) - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * Hamcrest Date (org.exparity:hamcrest-date:2.0.8 - https://github.com/exparity/hamcrest-date) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * Hamcrest (org.hamcrest:hamcrest:2.2 - http://hamcrest.org/JavaHamcrest/) - * Hamcrest All (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all) - * Hamcrest Core (org.hamcrest:hamcrest-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core) + * Hamcrest Core (org.hamcrest:hamcrest-core:2.2 - http://hamcrest.org/JavaHamcrest/) * HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.12 - http://hdrhistogram.github.io/HdrHistogram/) * JBibTeX (org.jbibtex:jbibtex:1.0.20 - http://www.jbibtex.org) * asm (org.ow2.asm:asm:8.0.1 - http://asm.ow2.io/) * asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/) - * asm-commons (org.ow2.asm:asm-commons:8.0.1 - http://asm.ow2.io/) + * asm-commons (org.ow2.asm:asm-commons:9.3 - http://asm.ow2.io/) * asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/) * asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/) - * PostgreSQL JDBC Driver (org.postgresql:postgresql:42.6.0 - https://jdbc.postgresql.org) + * PostgreSQL JDBC Driver (org.postgresql:postgresql:42.7.3 - https://jdbc.postgresql.org) * Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections) * JMatIO (org.tallison:jmatio:1.5 - https://github.com/tballison/jmatio) * XMLUnit for Java (xmlunit:xmlunit:1.3 - http://xmlunit.sourceforge.net/) @@ -454,12 +461,12 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines Common Development and Distribution License (CDDL): - * istack common utility code runtime (com.sun.istack:istack-commons-runtime:3.0.7 - http://java.net/istack-commons/istack-commons-runtime/) * JavaMail API (com.sun.mail:javax.mail:1.6.2 - http://javaee.github.io/javamail/javax.mail) * JavaMail API (no providers) (com.sun.mail:mailapi:1.6.2 - http://javaee.github.io/javamail/mailapi) * Old JAXB Core (com.sun.xml.bind:jaxb-core:2.3.0.1 - http://jaxb.java.net/jaxb-bundles/jaxb-core) * Old JAXB Runtime (com.sun.xml.bind:jaxb-impl:2.3.1 - http://jaxb.java.net/jaxb-bundles/jaxb-impl) * Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca) + * javax.transaction API (jakarta.transaction:jakarta.transaction-api:1.3.3 - https://projects.eclipse.org/projects/ee4j.jta) * jakarta.ws.rs-api (jakarta.ws.rs:jakarta.ws.rs-api:2.1.6 - https://github.com/eclipse-ee4j/jaxrs-api) * JavaBeans Activation Framework (JAF) (javax.activation:activation:1.1 - http://java.sun.com/products/javabeans/jaf/index.jsp) * JavaBeans Activation Framework API jar (javax.activation:javax.activation-api:1.2.0 - http://java.net/all/javax.activation-api/) @@ -474,12 +481,9 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator) * aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged) * javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:jakarta.inject:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/jakarta.inject) - * JAXB Runtime (org.glassfish.jaxb:jaxb-runtime:2.3.1 - http://jaxb.java.net/jaxb-runtime-parent/jaxb-runtime) - * TXW2 Runtime (org.glassfish.jaxb:txw2:2.3.1 - http://jaxb.java.net/jaxb-txw-parent/txw2) - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final - http://www.jboss.org/jboss-transaction-api_1.2_spec) - * Extended StAX API (org.jvnet.staxex:stax-ex:1.8 - http://stax-ex.java.net/) Cordra (Version 2) License Agreement: @@ -489,55 +493,62 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines Eclipse Distribution License, Version 1.0: + * Jakarta Activation (com.sun.activation:jakarta.activation:1.2.2 - https://github.com/eclipse-ee4j/jaf/jakarta.activation) + * istack common utility code runtime (com.sun.istack:istack-commons-runtime:3.0.12 - https://projects.eclipse.org/projects/ee4j/istack-commons/istack-commons-runtime) * Jakarta Activation API jar (jakarta.activation:jakarta.activation-api:1.2.2 - https://github.com/eclipse-ee4j/jaf/jakarta.activation-api) * Jakarta XML Binding API (jakarta.xml.bind:jakarta.xml.bind-api:2.3.3 - https://github.com/eclipse-ee4j/jaxb-api/jakarta.xml.bind-api) * javax.persistence-api (javax.persistence:javax.persistence-api:2.2 - https://github.com/javaee/jpa-spec) - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * JAXB Runtime (org.glassfish.jaxb:jaxb-runtime:2.3.9 - https://eclipse-ee4j.github.io/jaxb-ri/) + * TXW2 Runtime (org.glassfish.jaxb:txw2:2.3.9 - https://eclipse-ee4j.github.io/jaxb-ri/) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * Java Persistence API, Version 2.1 (org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final - http://hibernate.org) + * org.locationtech.jts:jts-core (org.locationtech.jts:jts-core:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-core) + * org.locationtech.jts.io:jts-io-common (org.locationtech.jts.io:jts-io-common:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-io/jts-io-common) Eclipse Public License: * System Rules (com.github.stefanbirkner:system-rules:1.19.0 - http://stefanbirkner.github.io/system-rules/) - * H2 Database Engine (com.h2database:h2:2.1.210 - https://h2database.com) + * H2 Database Engine (com.h2database:h2:2.2.224 - https://h2database.com) * Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca) + * javax.transaction API (jakarta.transaction:jakarta.transaction-api:1.3.3 - https://projects.eclipse.org/projects/ee4j.jta) * jakarta.ws.rs-api (jakarta.ws.rs:jakarta.ws.rs-api:2.1.6 - https://github.com/eclipse-ee4j/jaxrs-api) * javax.persistence-api (javax.persistence:javax.persistence-api:2.2 - https://github.com/javaee/jpa-spec) - * JUnit (junit:junit:4.13.1 - http://junit.org) + * JUnit (junit:junit:4.13.2 - http://junit.org) * AspectJ Weaver (org.aspectj:aspectjweaver:1.9.7 - https://www.eclipse.org/aspectj/) * Eclipse Compiler for Java(TM) (org.eclipse.jdt:ecj:3.14.0 - http://www.eclipse.org/jdt) * Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Apache :: JSTL module (org.eclipse.jetty:apache-jstl:9.4.15.v20190215 - http://tomcat.apache.org/taglibs/standard/) - * Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client) - * Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client) - * Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server) - * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) - * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) + * Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client) + * Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client) + * Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server) + * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) + * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) * Jetty :: Servlet Annotations (org.eclipse.jetty:jetty-annotations:9.4.15.v20190215 - http://www.eclipse.org/jetty) - * Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-client) - * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-continuation) - * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-continuation) - * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-deploy) - * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-http) - * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-io) - * Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-jmx) + * Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-client) + * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-continuation) + * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-continuation) + * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-deploy) + * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-http) + * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-io) + * Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-jmx) * Jetty :: JNDI Naming (org.eclipse.jetty:jetty-jndi:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Plus (org.eclipse.jetty:jetty-plus:9.4.15.v20190215 - http://www.eclipse.org/jetty) - * Jetty :: Rewrite Handler (org.eclipse.jetty:jetty-rewrite:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-rewrite) - * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-security) - * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-security) - * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-server) - * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-servlet) - * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-servlets) - * Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-util) - * Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-util-ajax) - * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-webapp) - * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-xml) - * Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-client) - * Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.51.v20230217 - https://eclipse.org/jetty/http2-parent/http2-common) - * Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-hpack) - * Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport) - * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.51.v20230217 - https://eclipse.org/jetty/http2-parent/http2-server) + * Jetty :: Rewrite Handler (org.eclipse.jetty:jetty-rewrite:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-rewrite) + * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-security) + * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-security) + * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-server) + * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-servlet) + * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-servlets) + * Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util) + * Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util-ajax) + * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-webapp) + * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-xml) + * Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-client) + * Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.54.v20240208 - https://eclipse.org/jetty/http2-parent/http2-common) + * Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-hpack) + * Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport) + * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.54.v20240208 - https://eclipse.org/jetty/http2-parent/http2-server) * Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas) * HK2 API module (org.glassfish.hk2:hk2-api:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api) * ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator) @@ -545,14 +556,24 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator) * aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged) * javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:jakarta.inject:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/jakarta.inject) - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * Java Persistence API, Version 2.1 (org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final - http://hibernate.org) + * org.locationtech.jts:jts-core (org.locationtech.jts:jts-core:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-core) + * org.locationtech.jts.io:jts-io-common (org.locationtech.jts.io:jts-io-common:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-io/jts-io-common) * Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty) * Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-servlet-tester) * Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util) + GENERAL PUBLIC LICENSE, version 3 (GPL-3.0): + + * juniversalchardet (com.github.albfernandez:juniversalchardet:2.4.0 - https://github.com/albfernandez/juniversalchardet) + + GNU LESSER GENERAL PUBLIC LICENSE, version 3 (LGPL-3.0): + + * juniversalchardet (com.github.albfernandez:juniversalchardet:2.4.0 - https://github.com/albfernandez/juniversalchardet) + GNU Lesser General Public License (LGPL): * btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf) @@ -569,9 +590,8 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * Hibernate ORM - hibernate-jpamodelgen (org.hibernate:hibernate-jpamodelgen:5.6.15.Final - https://hibernate.org/orm) * Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:5.1.2.Final - http://hibernate.org) * im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/) - * Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/) - * XOM (xom:xom:1.2.5 - http://xom.nu) - * XOM (xom:xom:1.3.7 - https://xom.nu) + * Javassist (org.javassist:javassist:3.29.0-GA - http://www.javassist.org/) + * XOM (xom:xom:1.3.9 - https://xom.nu) Go License: @@ -579,25 +599,29 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines Handle.Net Public License Agreement (Ver.2): - * Handle Server (net.handle:handle:9.3.0 - https://www.handle.net) + * Handle Server (net.handle:handle:9.3.1 - https://www.handle.net) + + ISC License: + + * Simple Magic (com.j256.simplemagic:simplemagic:1.17 - https://256stuff.com/sources/simplemagic/) MIT License: * better-files (com.github.pathikrit:better-files_2.13:3.9.1 - https://github.com/pathikrit/better-files) * Java SemVer (com.github.zafarkhaja:java-semver:0.9.0 - https://github.com/zafarkhaja/jsemver) - * dd-plist (com.googlecode.plist:dd-plist:1.25 - http://www.github.com/3breadt/dd-plist) - * DigitalCollections: IIIF API Library (de.digitalcollections.iiif:iiif-apis:0.3.9 - https://github.com/dbmdz/iiif-apis) + * dd-plist (com.googlecode.plist:dd-plist:1.28 - http://www.github.com/3breadt/dd-plist) + * DigitalCollections: IIIF API Library (de.digitalcollections.iiif:iiif-apis:0.3.10 - https://github.com/dbmdz/iiif-apis) * s3mock (io.findify:s3mock_2.13:0.2.6 - https://github.com/findify/s3mock) * JOpt Simple (net.sf.jopt-simple:jopt-simple:5.0.4 - http://jopt-simple.github.io/jopt-simple) - * Bouncy Castle S/MIME API (org.bouncycastle:bcmail-jdk15on:1.70 - https://www.bouncycastle.org/java.html) - * Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk15on:1.70 - https://www.bouncycastle.org/java.html) - * Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15on:1.70 - https://www.bouncycastle.org/java.html) - * Bouncy Castle ASN.1 Extension and Utility APIs (org.bouncycastle:bcutil-jdk15on:1.70 - https://www.bouncycastle.org/java.html) + * Bouncy Castle S/MIME API (org.bouncycastle:bcmail-jdk18on:1.77 - https://www.bouncycastle.org/java.html) + * Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk18on:1.78.1 - https://www.bouncycastle.org/java.html) + * Bouncy Castle Provider (org.bouncycastle:bcprov-jdk18on:1.78.1 - https://www.bouncycastle.org/java.html) + * Bouncy Castle ASN.1 Extension and Utility APIs (org.bouncycastle:bcutil-jdk18on:1.78.1 - https://www.bouncycastle.org/java.html) * org.brotli:dec (org.brotli:dec:0.1.2 - http://brotli.org/dec) - * Checker Qual (org.checkerframework:checker-qual:3.10.0 - https://checkerframework.org) - * Checker Qual (org.checkerframework:checker-qual:3.31.0 - https://checkerframework.org) - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * Checker Qual (org.checkerframework:checker-qual:3.23.0 - https://checkerframework.org) + * Checker Qual (org.checkerframework:checker-qual:3.42.0 - https://checkerframework.org/) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * mockito-core (org.mockito:mockito-core:3.12.4 - https://github.com/mockito/mockito) * mockito-inline (org.mockito:mockito-inline:3.12.4 - https://github.com/mockito/mockito) * ORCID - Model (org.orcid:orcid-model:3.0.2 - http://github.com/ORCID/orcid-model) @@ -608,34 +632,34 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines * toastr (org.webjars.bowergithub.codeseven:toastr:2.1.4 - http://webjars.org) * backbone (org.webjars.bowergithub.jashkenas:backbone:1.4.1 - https://www.webjars.org) * underscore (org.webjars.bowergithub.jashkenas:underscore:1.13.2 - https://www.webjars.org) - * jquery (org.webjars.bowergithub.jquery:jquery-dist:3.6.0 - https://www.webjars.org) - * urijs (org.webjars.bowergithub.medialize:uri.js:1.19.10 - https://www.webjars.org) - * bootstrap (org.webjars.bowergithub.twbs:bootstrap:4.6.1 - https://www.webjars.org) - * core-js (org.webjars.npm:core-js:3.30.1 - https://www.webjars.org) + * jquery (org.webjars.bowergithub.jquery:jquery-dist:3.7.1 - https://www.webjars.org) + * urijs (org.webjars.bowergithub.medialize:uri.js:1.19.11 - https://www.webjars.org) + * bootstrap (org.webjars.bowergithub.twbs:bootstrap:4.6.2 - https://www.webjars.org) + * core-js (org.webjars.npm:core-js:3.37.1 - https://www.webjars.org) * @json-editor/json-editor (org.webjars.npm:json-editor__json-editor:2.6.1 - https://www.webjars.org) Mozilla Public License: - * juniversalchardet (com.googlecode.juniversalchardet:juniversalchardet:1.0.3 - http://juniversalchardet.googlecode.com/) - * H2 Database Engine (com.h2database:h2:2.1.210 - https://h2database.com) + * juniversalchardet (com.github.albfernandez:juniversalchardet:2.4.0 - https://github.com/albfernandez/juniversalchardet) + * H2 Database Engine (com.h2database:h2:2.2.224 - https://h2database.com) * Saxon-HE (net.sf.saxon:Saxon-HE:9.8.0-14 - http://www.saxonica.com/) - * Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/) + * Javassist (org.javassist:javassist:3.29.0-GA - http://www.javassist.org/) * Mozilla Rhino (org.mozilla:rhino:1.7.7.2 - https://developer.mozilla.org/en/Rhino) Public Domain: - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.12 - http://hdrhistogram.github.io/HdrHistogram/) - * JSON in Java (org.json:json:20230227 - https://github.com/douglascrockford/JSON-java) + * JSON in Java (org.json:json:20231013 - https://github.com/douglascrockford/JSON-java) * LatencyUtils (org.latencyutils:LatencyUtils:2.0.3 - http://latencyutils.github.io/LatencyUtils/) * Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections) * XZ for Java (org.tukaani:xz:1.9 - https://tukaani.org/xz/java.html) UnRar License: - * Java Unrar (com.github.junrar:junrar:7.5.3 - https://github.com/junrar/junrar) + * Java Unrar (com.github.junrar:junrar:7.5.5 - https://github.com/junrar/junrar) Unicode/ICU License: @@ -643,10 +667,10 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines W3C license: - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) jQuery license: - * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) - * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) + * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) + * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) diff --git a/pom.xml b/pom.xml index ae83442235e0..3419757b56dc 100644 --- a/pom.xml +++ b/pom.xml @@ -705,7 +705,7 @@ Apache Software License, Version 2.0|The SAX License|The W3C License Apache Software License, Version 2.0|Similar to Apache License but with the acknowledgment clause removed - BSD License|The BSD License|BSD licence|BSD license|BSD|BSD-style license|New BSD License|New BSD license|Revised BSD License|BSD 2-Clause license|3-Clause BSD License|BSD 2-Clause|BSD 3-clause New License|BSD Licence 3|BSD-2-Clause|BSD-3-Clause|Modified BSD|The New BSD License|The BSD 3-Clause License (BSD3)|BSD License 3 + BSD License|The BSD License|BSD licence|BSD license|BSD|BSD-style license|New BSD License|New BSD license|Revised BSD License|BSD 2-Clause license|3-Clause BSD License|BSD 2-Clause|BSD 3-clause New License|BSD Licence 3|BSD-2-Clause|BSD-3-Clause|Modified BSD|The New BSD License|The BSD 3-Clause License (BSD3)|BSD License 3|BSD License 2.0 BSD License|DSpace BSD License|DSpace Sourcecode License @@ -726,7 +726,7 @@ Common Development and Distribution License (CDDL)|GNU General Public License, Version 2 with the Classpath Exception Eclipse Distribution License, Version 1.0|Eclipse Distribution License (EDL), Version 1.0|Eclipse Distribution License - v 1.0|Eclipse Distribution License v. 1.0|EDL 1.0 - Eclipse Public License|Eclipse Public License - Version 1.0|Eclipse Public License - v 1.0|EPL 1.0 license|Eclipse Public License (EPL), Version 1.0|Eclipse Public License 1.0|Eclipse Public License v1.0|Eclipse Public License, Version 1.0|EPL 1.0|EPL 2.0|Eclipse Public License - v 2.0 + Eclipse Public License|Eclipse Public License - Version 1.0|Eclipse Public License - v 1.0|EPL 1.0 license|Eclipse Public License (EPL), Version 1.0|Eclipse Public License 1.0|Eclipse Public License v1.0|Eclipse Public License, Version 1.0|EPL 1.0|EPL 2.0|Eclipse Public License - v 2.0|EPL-2.0|Eclipse Public License 2.0|Eclipse Public License v. 2.0|Eclipse Public License, Version 2.0 Eclipse Public License|Common Public License Version 1.0 @@ -739,7 +739,7 @@ MIT License|Bouncy Castle Licence MIT License|(MIT-style) netCDF C library license - Mozilla Public License|Mozilla Public License version 1.1|Mozilla Public License 1.1 (MPL 1.1)|MPL 1.1|Mozilla Public License Version 2.0|Mozilla Public License, Version 2.0 + Mozilla Public License|Mozilla Public License version 1.1|Mozilla Public License 1.1 (MPL 1.1)|MPL 1.1|Mozilla Public License Version 2.0|Mozilla Public License, Version 2.0|Mozilla Public License Version 1.1 Mozilla Public License|MPL 2.0, and EPL 1.0|MPL 2.0 diff --git a/src/main/license/LICENSES_THIRD_PARTY.properties b/src/main/license/LICENSES_THIRD_PARTY.properties index e893f9b85e31..0a50bdb011b0 100644 --- a/src/main/license/LICENSES_THIRD_PARTY.properties +++ b/src/main/license/LICENSES_THIRD_PARTY.properties @@ -13,89 +13,16 @@ # 1) PLEASE CHECK THE "[src]/LICENSES_THIRD_PARTY" FILE FOR SPECIFIC LICENSE NAMES! # 2) Also please add a link/URL to where you looked up the license -# http://asm.ow2.org/ -asm--asm--3.1=BSD License - -# http://www.h2database.com/html/license.html -com.h2database--h2--1.4.187=Mozilla Public License - -# https://projects.apache.org/projects/commons_jexl.html -commons-jexl--commons-jexl--1.0=Apache Software License, Version 2.0 - -concurrent--concurrent--1.3.4=Public Domain - -# http://dom4j.sourceforge.net/dom4j-1.6.1/license.html -dom4j--dom4j--1.6.1=BSD License - -# http://jakarta.apache.org/regexp/ -jakarta-regexp--jakarta-regexp--1.4=Apache Software License, Version 2.0 - -# https://java.net/projects/servlet-spec/ -javax.servlet--jsp-api--2.0=Common Development and Distribution License (CDDL) -javax.servlet--jstl--1.2=Common Development and Distribution License (CDDL) -javax.servlet--servlet-api--2.5=Common Development and Distribution License (CDDL) +# https://github.com/albfernandez/juniversalchardet/blob/main/LICENSE +com.github.albfernandez--juniversalchardet--2.4.0=Mozilla Public License # https://github.com/jankotek/JDBM3 jdbm--jdbm--1.0=Apache Software License, Version 2.0 -# https://github.com/hunterhacker/jdom/blob/master/LICENSE.txt -# http://www.jdom.org/docs/faq.html#a0030 -jdom--jdom--1.0=JDOM License (Apache-style license) -jdom--jdom--1.1.3=JDOM License (Apache-style license) - # https://github.com/stephenc/jcip-annotations/blob/master/LICENSE.txt net.jcip--jcip-annotations--1.0=Apache Software License, Version 2.0 -# http://ant.apache.org/ -org.apache.ant--ant--1.7.0=Apache Software License, Version 2.0 -org.apache.ant--ant-launcher--1.7.0=Apache Software License, Version 2.0 - -# http://zookeeper.apache.org/ -org.apache.zookeeper--zookeeper--3.4.6=Apache Software License, Version 2.0 - -# http://jettison.codehaus.org/ -org.codehaus.jettison--jettison--1.1=Apache Software License, Version 2.0 - -# DSpace Licenses are all BSD -org.dspace--handle--6.2=BSD License -org.dspace--jargon--1.4.25=BSD License -org.dspace--mets--1.5.2=BSD License -org.dspace--oclc-harvester2--0.1.12=BSD License - -# https://github.com/hibernate/hibernate-jpa-api -org.hibernate.javax.persistence--hibernate-jpa-2.0-api--1.0.1.Final=Eclipse Public License - -# Swingworker: https://java.net/projects/swingworker -org.jdesktop--swing-worker--1.1=GNU Lesser General Public License (LGPL) - -# https://java.net/projects/tiger-types -org.jvnet--tiger-types--1.4=Common Development and Distribution License (CDDL) - -# https://maven-repository.com/ -org.restlet.jee--org.restlet--2.1.1=Apache Software License, Version 2.0 -org.restlet.jee--org.restlet.ext.servlet--2.1.1=Apache Software License, Version 2.0 - -# http://swordapp.org/ -org.swordapp--sword-common--1.1=Apache Software License, Version 2.0 - -# Apache Jakarta ORO: http://svn.apache.org/repos/asf/jakarta/oro/trunk/LICENSE -oro--oro--2.0.8=Apache Software License, Version 2.0 - -# http://rometools.org/ -rome--rome--1.0=Apache Software License, Version 2.0 - -# https://tomcat.apache.org/taglibs/license.html -taglibs--standard--1.1.2=Apache Software License, Version 2.0 - -# Apache XML (xalan): http://xml.apache.org/xalan-j/#license -xalan--xalan--2.7.0=Apache Software License, Version 2.0 - -# Apache Xerces: http://xerces.apache.org/ -xerces--xmlParserAPIs--2.6.2=Apache Software License, Version 2.0 - -# Apache XML Commons: http://xerces.apache.org/xml-commons/licenses.html -xml-apis--xml-apis--1.4.01=Apache Software License, Version 2.0 -xml-apis--xmlParserAPIs--2.0.2=Apache Software License, Version 2.0 - -# http://www.xom.nu/ -xom--xom--1.1=GNU Lesser General Public License (LGPL) +# Jersey is dual licensed EPL and GPL. We use EPL +# https://eclipse-ee4j.github.io/jersey.github.io/license.html +org.glassfish.jersey.core--jersey-client--2.39.1=Eclipse Public License +org.glassfish.jersey.inject--jersey-hk2--2.39.1=Eclipse Public License From 98c661d8d07b3e3ae68d513252ab7f90ae72faf6 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 3 Jul 2024 14:17:05 -0500 Subject: [PATCH 229/230] Update redeployment of demo.dspace.org to use dspace-8_x branch. --- .github/workflows/reusable-docker-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml index 687474caed18..12aa0cfe2864 100644 --- a/.github/workflows/reusable-docker-build.yml +++ b/.github/workflows/reusable-docker-build.yml @@ -70,7 +70,7 @@ env: REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }} # Current DSpace maintenance branch (and architecture) which is deployed to demo.dspace.org / sandbox.dspace.org # (NOTE: No deployment branch specified for sandbox.dspace.org as it uses the default_branch) - DEPLOY_DEMO_BRANCH: 'dspace-7_x' + DEPLOY_DEMO_BRANCH: 'dspace-8_x' DEPLOY_ARCH: 'linux/amd64' jobs: From 08947bc34e60c93b2b0771b3fdb5347915cac28b Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 9 Jul 2024 14:10:01 -0500 Subject: [PATCH 230/230] [maven-release-plugin] prepare release dspace-7.6.2 --- dspace-api/pom.xml | 2 +- dspace-iiif/pom.xml | 2 +- dspace-oai/pom.xml | 2 +- dspace-rdf/pom.xml | 2 +- dspace-rest/pom.xml | 4 ++-- dspace-server-webapp/pom.xml | 2 +- dspace-services/pom.xml | 2 +- dspace-sword/pom.xml | 2 +- dspace-swordv2/pom.xml | 2 +- dspace/modules/additions/pom.xml | 2 +- dspace/modules/pom.xml | 2 +- dspace/modules/rest/pom.xml | 2 +- dspace/modules/server/pom.xml | 2 +- dspace/pom.xml | 2 +- pom.xml | 32 ++++++++++++++++---------------- 15 files changed, 31 insertions(+), 31 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 4c881cbd2465..a15a21e6bc07 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace-iiif/pom.xml b/dspace-iiif/pom.xml index 8cba90552481..58ea58687e05 100644 --- a/dspace-iiif/pom.xml +++ b/dspace-iiif/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index 748f6ad2deef..a76a878454e8 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -8,7 +8,7 @@ dspace-parent org.dspace - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index f118ebddb378..43e637587947 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml index 5688424a1c26..1192f9ed7cdd 100644 --- a/dspace-rest/pom.xml +++ b/dspace-rest/pom.xml @@ -3,7 +3,7 @@ org.dspace dspace-rest war - 7.6.2-SNAPSHOT + 7.6.2 DSpace (Deprecated) REST Webapp DSpace RESTful Web Services API. NOTE: this REST API is DEPRECATED. Please consider using the REST API in the dspace-server-webapp instead! @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 5395169950bc..feb8c2af6e4b 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace-services/pom.xml b/dspace-services/pom.xml index 98e0253a498d..20110a814459 100644 --- a/dspace-services/pom.xml +++ b/dspace-services/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 52783e3ec571..d9fd8843a542 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 8d618bdf5f81..2b6c75901e56 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -13,7 +13,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace/modules/additions/pom.xml b/dspace/modules/additions/pom.xml index 7e60e982ec45..0a4f43d84bf9 100644 --- a/dspace/modules/additions/pom.xml +++ b/dspace/modules/additions/pom.xml @@ -17,7 +17,7 @@ org.dspace modules - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace/modules/pom.xml b/dspace/modules/pom.xml index 5819158505fd..d4f47af66a00 100644 --- a/dspace/modules/pom.xml +++ b/dspace/modules/pom.xml @@ -11,7 +11,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 ../../pom.xml diff --git a/dspace/modules/rest/pom.xml b/dspace/modules/rest/pom.xml index 7797346c51db..3f4e99b482aa 100644 --- a/dspace/modules/rest/pom.xml +++ b/dspace/modules/rest/pom.xml @@ -13,7 +13,7 @@ org.dspace modules - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace/modules/server/pom.xml b/dspace/modules/server/pom.xml index 564f81593777..d5882c9270c1 100644 --- a/dspace/modules/server/pom.xml +++ b/dspace/modules/server/pom.xml @@ -13,7 +13,7 @@ just adding new jar in the classloader modules org.dspace - 7.6.2-SNAPSHOT + 7.6.2 .. diff --git a/dspace/pom.xml b/dspace/pom.xml index f9dc6126e60b..cc2968fab99f 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -16,7 +16,7 @@ org.dspace dspace-parent - 7.6.2-SNAPSHOT + 7.6.2 ../pom.xml diff --git a/pom.xml b/pom.xml index 3419757b56dc..0670e2cf4832 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.dspace dspace-parent pom - 7.6.2-SNAPSHOT + 7.6.2 DSpace Parent Project DSpace open source software is a turnkey institutional repository application. @@ -874,14 +874,14 @@ org.dspace dspace-rest - 7.6.2-SNAPSHOT + 7.6.2 jar classes org.dspace dspace-rest - 7.6.2-SNAPSHOT + 7.6.2 war @@ -1032,69 +1032,69 @@ org.dspace dspace-api - 7.6.2-SNAPSHOT + 7.6.2 org.dspace dspace-api test-jar - 7.6.2-SNAPSHOT + 7.6.2 test org.dspace.modules additions - 7.6.2-SNAPSHOT + 7.6.2 org.dspace dspace-sword - 7.6.2-SNAPSHOT + 7.6.2 org.dspace dspace-swordv2 - 7.6.2-SNAPSHOT + 7.6.2 org.dspace dspace-oai - 7.6.2-SNAPSHOT + 7.6.2 org.dspace dspace-services - 7.6.2-SNAPSHOT + 7.6.2 org.dspace dspace-server-webapp test-jar - 7.6.2-SNAPSHOT + 7.6.2 test org.dspace dspace-rdf - 7.6.2-SNAPSHOT + 7.6.2 org.dspace dspace-iiif - 7.6.2-SNAPSHOT + 7.6.2 org.dspace dspace-server-webapp - 7.6.2-SNAPSHOT + 7.6.2 jar classes org.dspace dspace-server-webapp - 7.6.2-SNAPSHOT + 7.6.2 war @@ -1940,7 +1940,7 @@ scm:git:git@github.com:DSpace/DSpace.git scm:git:git@github.com:DSpace/DSpace.git git@github.com:DSpace/DSpace.git - dspace-7_x + dspace-7.6.2