From d4e7f3d10be0ca560c6f043394c951add56369f1 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Tue, 24 Feb 2026 16:35:09 -0500 Subject: [PATCH 01/12] First load for this branch, refactor of storage driver endpoint. --- .../edu/harvard/iq/dataverse/api/Admin.java | 90 +-------- .../harvard/iq/dataverse/api/Dataverses.java | 191 +++++++++--------- .../edu/harvard/iq/dataverse/api/Info.java | 9 +- .../DeleteDataverseStorageDriverComman.java | 29 +++ .../GetDataverseStorageDriverCommand.java | 42 ++++ .../SetDataverseMetadataLanguageCommand.java | 1 - .../SetDataverseStorageDriverCommand.java | 44 ++++ 7 files changed, 220 insertions(+), 186 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseStorageDriverCommand.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseStorageDriverCommand.java diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 18f28569d7d..289b893e75f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -74,7 +74,6 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Map; -import java.util.Map.Entry; import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; @@ -2256,94 +2255,6 @@ public Response addRoleAssignementsToChildren(@Context ContainerRequestContext c "InheritParentRoleAssignments does not list any roles on this instance"); } - @GET - @AuthRequired - @Path("/dataverse/{alias}/storageDriver") - public Response getStorageDriver(@Context ContainerRequestContext crc, @PathParam("alias") String alias, - @QueryParam("getEffective") Boolean getEffective) throws WrappedResponse { - Dataverse dataverse = dataverseSvc.findByAlias(alias); - if (dataverse == null) { - return error(Response.Status.NOT_FOUND, "Could not find dataverse based on alias supplied: " + alias + "."); - } - try { - AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); - if (!user.isSuperuser()) { - return error(Response.Status.FORBIDDEN, "Superusers only."); - } - } catch (WrappedResponse wr) { - return wr.getResponse(); - } - - if (getEffective != null && getEffective) { - return ok(JsonPrinter.jsonStorageDriver(dataverse.getEffectiveStorageDriverId())); - } else { - return ok(JsonPrinter.jsonStorageDriver(dataverse.getStorageDriverId())); - } - } - - @PUT - @AuthRequired - @Path("/dataverse/{alias}/storageDriver") - public Response setStorageDriver(@Context ContainerRequestContext crc, @PathParam("alias") String alias, String label) throws WrappedResponse { - Dataverse dataverse = dataverseSvc.findByAlias(alias); - if (dataverse == null) { - return error(Response.Status.NOT_FOUND, "Could not find dataverse based on alias supplied: " + alias + "."); - } - try { - AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); - if (!user.isSuperuser()) { - return error(Response.Status.FORBIDDEN, "Superusers only."); - } - } catch (WrappedResponse wr) { - return wr.getResponse(); - } - for (Entry store: DataAccess.getStorageDriverLabels().entrySet()) { - if(store.getKey().equals(label)) { - dataverse.setStorageDriverId(store.getValue()); - return ok("Storage set to: " + store.getKey() + "/" + store.getValue()); - } - } - return error(Response.Status.BAD_REQUEST, - "No Storage Driver found for : " + label); - } - - @DELETE - @AuthRequired - @Path("/dataverse/{alias}/storageDriver") - public Response resetStorageDriver(@Context ContainerRequestContext crc, @PathParam("alias") String alias) throws WrappedResponse { - Dataverse dataverse = dataverseSvc.findByAlias(alias); - if (dataverse == null) { - return error(Response.Status.NOT_FOUND, "Could not find dataverse based on alias supplied: " + alias + "."); - } - try { - AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); - if (!user.isSuperuser()) { - return error(Response.Status.FORBIDDEN, "Superusers only."); - } - } catch (WrappedResponse wr) { - return wr.getResponse(); - } - dataverse.setStorageDriverId(""); - return ok("Storage reset to default: " + DataAccess.DEFAULT_STORAGE_DRIVER_IDENTIFIER); - } - - @GET - @AuthRequired - @Path("/dataverse/storageDrivers") - public Response listStorageDrivers(@Context ContainerRequestContext crc) throws WrappedResponse { - try { - AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); - if (!user.isSuperuser()) { - return error(Response.Status.FORBIDDEN, "Superusers only."); - } - } catch (WrappedResponse wr) { - return wr.getResponse(); - } - JsonObjectBuilder bld = jsonObjectBuilder(); - DataAccess.getStorageDriverLabels().entrySet().forEach(s -> bld.add(s.getKey(), s.getValue())); - return ok(bld); - } - @GET @AuthRequired @Path("/dataverse/{alias}/curationLabelSet") @@ -2820,4 +2731,5 @@ public Response rateLimitStats(@Context ContainerRequestContext crc, String csvData = cacheFactory.getStats(CacheFactoryBean.RATE_LIMIT_CACHE, deltaMinutesFilter != null ? String.valueOf(deltaMinutesFilter) : null); return Response.ok(csvData).header("Content-Disposition", "attachment; filename=\"data.csv\"").build(); } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index caf778be675..a5dcad8e946 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -2,8 +2,8 @@ import com.google.common.collect.Lists; import com.google.api.client.util.ArrayMap; + import edu.harvard.iq.dataverse.*; -import static edu.harvard.iq.dataverse.api.AbstractApiBean.error; import edu.harvard.iq.dataverse.api.auth.AuthRequired; import edu.harvard.iq.dataverse.api.datadeposit.SwordServiceBean; import edu.harvard.iq.dataverse.api.dto.*; @@ -16,15 +16,14 @@ import edu.harvard.iq.dataverse.authorization.groups.impl.explicit.ExplicitGroup; import edu.harvard.iq.dataverse.authorization.groups.impl.explicit.ExplicitGroupProvider; import edu.harvard.iq.dataverse.authorization.groups.impl.explicit.ExplicitGroupServiceBean; -import edu.harvard.iq.dataverse.authorization.groups.impl.ipaddress.ip.IpAddress; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.authorization.users.User; +import edu.harvard.iq.dataverse.dataaccess.DataAccess; import edu.harvard.iq.dataverse.dataset.DatasetType; import edu.harvard.iq.dataverse.dataverse.DataverseUtil; import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItem; import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItemServiceBean; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; -import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.impl.*; import edu.harvard.iq.dataverse.pidproviders.PidProvider; import edu.harvard.iq.dataverse.pidproviders.PidUtil; @@ -36,6 +35,7 @@ import edu.harvard.iq.dataverse.util.StringUtil; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.*; +import static edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder.jsonObjectBuilder; import edu.harvard.iq.dataverse.util.json.*; @@ -73,6 +73,7 @@ import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.StreamingOutput; + import org.glassfish.jersey.media.multipart.FormDataBodyPart; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; @@ -89,7 +90,6 @@ public class Dataverses extends AbstractApiBean { private static final Logger logger = Logger.getLogger(Dataverses.class.getCanonicalName()); - private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss"); @EJB ExplicitGroupServiceBean explicitGroupSvc; @@ -1330,97 +1330,6 @@ public Response listAssignments(@Context ContainerRequestContext crc, @PathParam ), getRequestUser(crc)); } - /** - * This code for setting a dataverse logo via API was started when initially - * investigating https://github.com/IQSS/dataverse/issues/3559 but it isn't - * finished so it's commented out. See also * "No functionality should be - * GUI-only. Make all functionality reachable via the API" at - * https://github.com/IQSS/dataverse/issues/3440 - */ -// File tempDir; -// -// TODO: Code duplicate in ThemeWidgetFragment. Maybe extract, make static and put some place else? -// Important: at least use JvmSettings.DOCROOT_DIRECTORY and not the hardcoded location! -// private void createTempDir(Dataverse editDv) { -// try { -// File tempRoot = java.nio.file.Files.createDirectories(Paths.get("../docroot/logos/temp")).toFile(); -// tempDir = java.nio.file.Files.createTempDirectory(tempRoot.toPath(), editDv.getId().toString()).toFile(); -// } catch (IOException e) { -// throw new RuntimeException("Error creating temp directory", e); // improve error handling -// } -// } -// -// private DataverseTheme initDataverseTheme(Dataverse editDv) { -// DataverseTheme dvt = new DataverseTheme(); -// dvt.setLinkColor(DEFAULT_LINK_COLOR); -// dvt.setLogoBackgroundColor(DEFAULT_LOGO_BACKGROUND_COLOR); -// dvt.setBackgroundColor(DEFAULT_BACKGROUND_COLOR); -// dvt.setTextColor(DEFAULT_TEXT_COLOR); -// dvt.setDataverse(editDv); -// return dvt; -// } -// -// @PUT -// @Path("{identifier}/logo") -// @Consumes(MediaType.MULTIPART_FORM_DATA) -// public Response setDataverseLogo(@PathParam("identifier") String dvIdtf, -// @FormDataParam("file") InputStream fileInputStream, -// @FormDataParam("file") FormDataContentDisposition contentDispositionHeader, -// @QueryParam("key") String apiKey) { -// boolean disabled = true; -// if (disabled) { -// return error(Status.FORBIDDEN, "Setting the dataverse logo via API needs more work."); -// } -// try { -// final DataverseRequest req = createDataverseRequest(findUserOrDie()); -// final Dataverse editDv = findDataverseOrDie(dvIdtf); -// -// logger.finer("entering fileUpload"); -// if (tempDir == null) { -// createTempDir(editDv); -// logger.finer("created tempDir"); -// } -// File uploadedFile; -// try { -// String fileName = contentDispositionHeader.getFileName(); -// -// uploadedFile = new File(tempDir, fileName); -// if (!uploadedFile.exists()) { -// uploadedFile.createNewFile(); -// } -// logger.finer("created file"); -// File file = null; -// file = FileUtil.inputStreamToFile(fileInputStream); -// if (file.length() > systemConfig.getUploadLogoSizeLimit()) { -// return error(Response.Status.BAD_REQUEST, "File is larger than maximum size: " + systemConfig.getUploadLogoSizeLimit() + "."); -// } -// java.nio.file.Files.copy(fileInputStream, uploadedFile.toPath(), StandardCopyOption.REPLACE_EXISTING); -// logger.finer("copied inputstream to file"); -// editDv.setDataverseTheme(initDataverseTheme(editDv)); -// editDv.getDataverseTheme().setLogo(fileName); -// -// } catch (IOException e) { -// logger.finer("caught IOException"); -// logger.throwing("ThemeWidgetFragment", "handleImageFileUpload", e); -// throw new RuntimeException("Error uploading logo file", e); // improve error handling -// } -// // If needed, set the default values for the logo -// if (editDv.getDataverseTheme().getLogoFormat() == null) { -// editDv.getDataverseTheme().setLogoFormat(DataverseTheme.ImageFormat.SQUARE); -// } -// logger.finer("end handelImageFileUpload"); -// UpdateDataverseThemeCommand cmd = new UpdateDataverseThemeCommand(editDv, uploadedFile, req); -// Dataverse saved = execCommand(cmd); -// -// /** -// * @todo delete the temp file: -// * docroot/logos/temp/1148114212463761832421/cc0.png -// */ -// return ok("logo uploaded: " + saved.getDataverseTheme().getLogo()); -// } catch (WrappedResponse ex) { -// return error(Status.BAD_REQUEST, "problem uploading logo: " + ex); -// } -// } @POST @AuthRequired @Path("{identifier}/assignments") @@ -2140,4 +2049,96 @@ public Response getRoleAssignmentHistory(@Context ContainerRequestContext crc, return getRoleAssignmentHistoryResponse(dataverse, authenticatedUser, false, headers); }, getRequestUser(crc)); } + + @GET + @AuthRequired + @Path("{identifier}/storageDriver") + public Response getStorageDriver(@Context ContainerRequestContext crc, @PathParam("identifier") String id, + @QueryParam("getEffective") Boolean getEffective) throws WrappedResponse { + + Dataverse dataverse = findDataverseOrDie(id); + + if (dataverse == null) { + return error(Response.Status.NOT_FOUND, "Could not find dataverse based on the identifier supplied: " + id + "."); + } + + return response(req -> { + String storageDriver = execCommand(new GetDataverseStorageDriverCommand(req, findDataverseOrDie(id), getEffective)); + return ok(JsonPrinter.jsonStorageDriver(storageDriver)); + }, getRequestUser(crc)); + + + + // try { + // AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); + // } catch (WrappedResponse wr) { + // return error(Response.Status.NOT_FOUND, wr.getMessage()); + // } + + // if (getEffective != null && getEffective) { + // return ok(JsonPrinter.jsonStorageDriver(dataverse.getEffectiveStorageDriverId())); + // } else { + // return ok(JsonPrinter.jsonStorageDriver(dataverse.getStorageDriverId())); + // } + } + + @PUT + @AuthRequired + @Path("{identifier}/storageDriver") + public Response setStorageDriver(@Context ContainerRequestContext crc, + @PathParam("identifier") String id, String label) throws WrappedResponse { + + Dataverse dataverse = findDataverseOrDie(id); + + if (dataverse == null) { + return error(Response.Status.NOT_FOUND, "Could not find dataverse based on the identifier supplied: " + id + "."); + } + + try { + AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); + DataverseRequest request = createDataverseRequest(user); + SetDataverseStorageDriverCommand setDriverCommand = new SetDataverseStorageDriverCommand(request, dataverse, label); + return ok(execCommand(setDriverCommand)); + + } catch (IllegalArgumentException iae) { + return error(Response.Status.NOT_FOUND, iae.getMessage()); + } + + } + + @DELETE + @AuthRequired + @Path("{identifier}/storageDriver") + public Response resetStorageDriver(@Context ContainerRequestContext crc, @PathParam("identifier") String id) throws WrappedResponse { + + Dataverse dataverse = findDataverseOrDie(id); + if (dataverse == null) { + return error(Response.Status.NOT_FOUND, "Could not find dataverse based on the identifier supplied: " + id + "."); + } + + try { + AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); + DataverseRequest request = createDataverseRequest(user); + DeleteDataverseStorageDriverComman deleteDriverCommand = new DeleteDataverseStorageDriverComman(request, dataverse); + return ok(execCommand(deleteDriverCommand)); + } catch (Exception e) { + return error(Response.Status.NOT_FOUND, e.getMessage()); + } + } + + @GET + @AuthRequired + @Path("{identifier}/allowedStorageDrivers") + public Response listStorageDrivers(@Context ContainerRequestContext crc) throws WrappedResponse { + + /* + * TODO: This endpoint will return the full list but there is a request by Jim Myers + * to only return the storage drivers that the dataverse can use. + */ + JsonObjectBuilder bld = jsonObjectBuilder(); + DataAccess.getStorageDriverLabels().entrySet().forEach(s -> bld.add(s.getKey(), s.getValue())); + return ok(bld); + } + } + \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Info.java b/src/main/java/edu/harvard/iq/dataverse/api/Info.java index 1aab185e6fb..be39b6681c6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Info.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Info.java @@ -1,13 +1,18 @@ package edu.harvard.iq.dataverse.api; +import static edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder.jsonObjectBuilder; + import java.util.logging.Logger; +import edu.harvard.iq.dataverse.api.auth.AuthRequired; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.customization.CustomizationConstants; +import edu.harvard.iq.dataverse.dataaccess.DataAccess; import jakarta.ws.rs.*; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.WebTarget; - +import jakarta.ws.rs.container.ContainerRequestContext; import edu.harvard.iq.dataverse.export.ExportService; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; @@ -19,6 +24,7 @@ import jakarta.json.Json; import jakarta.json.JsonObjectBuilder; import jakarta.json.JsonValue; +import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.openapi.annotations.Operation; @@ -165,4 +171,5 @@ private Response getSettingResponseByKey(SettingsServiceBean.Key key) { return notFound("Setting " + key + " not found"); } } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java new file mode 100644 index 00000000000..bba5ad2a542 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java @@ -0,0 +1,29 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import java.util.Map.Entry; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.dataaccess.DataAccess; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.authorization.Permission; + +@RequiredPermissions(Permission.EditDataverse) +public class DeleteDataverseStorageDriverComman extends AbstractCommand { + + private Dataverse dv; + + public DeleteDataverseStorageDriverComman(DataverseRequest aRequest, Dataverse dv) { + super(aRequest, dv); + this.dv = dv; + } + + @Override + public String execute(CommandContext ctxt) { + dv.setStorageDriverId(""); + return "Storage reset to default: " + DataAccess.DEFAULT_STORAGE_DRIVER_IDENTIFIER; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseStorageDriverCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseStorageDriverCommand.java new file mode 100644 index 00000000000..47378e0b542 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseStorageDriverCommand.java @@ -0,0 +1,42 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + + +import java.util.Collections; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.authorization.Permission; +import java.util.Map; +import java.util.Set; + +public class GetDataverseStorageDriverCommand extends AbstractCommand { + + private Dataverse dv; + private Boolean getEffective; + + public GetDataverseStorageDriverCommand(DataverseRequest aRequest, Dataverse dv, Boolean getEffective) { + super(aRequest, dv); + this.dv = dv; + this.getEffective = getEffective; + } + + @Override + public String execute(CommandContext ctxt) { + + if (getEffective != null && getEffective) { + return dv.getEffectiveStorageDriverId(); + } else { + return dv.getStorageDriverId(); + } + } + + @Override + public Map> getRequiredPermissions() { + return Collections.singletonMap("", + dv.isReleased() ? Collections.emptySet() + : Collections.singleton(Permission.ViewUnpublishedDataverse)); + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseMetadataLanguageCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseMetadataLanguageCommand.java index 438c332436a..d290f3747e6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseMetadataLanguageCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseMetadataLanguageCommand.java @@ -4,7 +4,6 @@ import java.util.Map; import edu.harvard.iq.dataverse.Dataverse; -import edu.harvard.iq.dataverse.DvObject; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseStorageDriverCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseStorageDriverCommand.java new file mode 100644 index 00000000000..e2bc95c0183 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseStorageDriverCommand.java @@ -0,0 +1,44 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import java.util.Map.Entry; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.dataaccess.DataAccess; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.authorization.Permission; + +@RequiredPermissions(Permission.EditDataverse) +public class SetDataverseStorageDriverCommand extends AbstractCommand { + + private Dataverse dv; + private String label; + + public SetDataverseStorageDriverCommand(DataverseRequest aRequest, Dataverse dv, String label) { + super(aRequest, dv); + this.dv = dv; + this.label = label; + } + + @Override + public String execute(CommandContext ctxt) { + + String storageDriverId = null; + for (Entry store: DataAccess.getStorageDriverLabels().entrySet()) { + if(store.getKey().equals(label)) { + storageDriverId = store.getValue(); + } + } + + if (storageDriverId != null) { + dv.setStorageDriverId(storageDriverId); + return "Storage set to: " + storageDriverId + "/" + label; + } else { + throw new IllegalArgumentException("No Storage Driver found for : " + label); + } + + } + +} From 73853c8cdc39c2409e250f4594141a972e540d65 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Wed, 25 Feb 2026 10:33:13 -0500 Subject: [PATCH 02/12] Added endpoint for allowed storage drivers --- .../harvard/iq/dataverse/api/Dataverses.java | 24 +++++++++++---- .../DeleteDataverseStorageDriverComman.java | 2 -- ...tDataverseAllowedStorageDriverCommand.java | 29 +++++++++++++++++++ .../GetDataverseStorageDriverCommand.java | 2 -- .../SetDataverseStorageDriverCommand.java | 1 - 5 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseAllowedStorageDriverCommand.java diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index a5dcad8e946..33e43e0d056 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -2,6 +2,8 @@ import com.google.common.collect.Lists; import com.google.api.client.util.ArrayMap; +import com.google.api.client.util.Data; +import com.google.api.services.storage.Storage.AnywhereCaches.Get; import edu.harvard.iq.dataverse.*; import edu.harvard.iq.dataverse.api.auth.AuthRequired; @@ -2129,15 +2131,25 @@ public Response resetStorageDriver(@Context ContainerRequestContext crc, @PathPa @GET @AuthRequired @Path("{identifier}/allowedStorageDrivers") - public Response listStorageDrivers(@Context ContainerRequestContext crc) throws WrappedResponse { + public Response listStorageDrivers(@Context ContainerRequestContext crc, @PathParam("identifier") String id) throws WrappedResponse { + Dataverse dv = findDataverseOrDie(id); + + /* - * TODO: This endpoint will return the full list but there is a request by Jim Myers - * to only return the storage drivers that the dataverse can use. + * TODO: This endpoint ad GetDataverseAllowedStorageDriverCommand needs to be completed, + * currently it mocks things that will be required to model the behavior requested by Jim Myers, + * which is to return the list of storage drivers that the dataverse can use. + * Currently it will return the full list of drivers available. */ - JsonObjectBuilder bld = jsonObjectBuilder(); - DataAccess.getStorageDriverLabels().entrySet().forEach(s -> bld.add(s.getKey(), s.getValue())); - return ok(bld); + try { + AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); + DataverseRequest request = createDataverseRequest(user); + GetDataverseAllowedStorageDriverCommand getAllowedStorageDriversCommand = new GetDataverseAllowedStorageDriverCommand(request, dv); + return ok(execCommand(getAllowedStorageDriversCommand)); + } catch (Exception e) { + return error(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage()); + } } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java index bba5ad2a542..9064b0fc731 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java @@ -1,7 +1,5 @@ package edu.harvard.iq.dataverse.engine.command.impl; -import java.util.Map.Entry; - import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.dataaccess.DataAccess; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseAllowedStorageDriverCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseAllowedStorageDriverCommand.java new file mode 100644 index 00000000000..f1f55d7e602 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseAllowedStorageDriverCommand.java @@ -0,0 +1,29 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + + +import static edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder.jsonObjectBuilder; +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import jakarta.json.JsonObjectBuilder; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.dataaccess.DataAccess; + +@RequiredPermissions(Permission.AddDataverse) +public class GetDataverseAllowedStorageDriverCommand extends AbstractCommand { + + public GetDataverseAllowedStorageDriverCommand(DataverseRequest aRequest, Dataverse dv) { + super(aRequest, dv); + } + + @Override + public JsonObjectBuilder execute(CommandContext ctxt) { + + JsonObjectBuilder bld = jsonObjectBuilder(); + DataAccess.getStorageDriverLabels().entrySet().forEach(s -> bld.add(s.getKey(), s.getValue())); + return bld; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseStorageDriverCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseStorageDriverCommand.java index 47378e0b542..85adf791800 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseStorageDriverCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataverseStorageDriverCommand.java @@ -1,8 +1,6 @@ package edu.harvard.iq.dataverse.engine.command.impl; - import java.util.Collections; - import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseStorageDriverCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseStorageDriverCommand.java index e2bc95c0183..447e3ed0e8d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseStorageDriverCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SetDataverseStorageDriverCommand.java @@ -1,7 +1,6 @@ package edu.harvard.iq.dataverse.engine.command.impl; import java.util.Map.Entry; - import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.dataaccess.DataAccess; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; From e26fdd137db2e37df05d55d39bf57c476dcec98f Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Wed, 25 Feb 2026 11:04:03 -0500 Subject: [PATCH 03/12] Update for tests --- .../edu/harvard/iq/dataverse/api/Dataverses.java | 14 -------------- .../java/edu/harvard/iq/dataverse/api/UtilIT.java | 8 ++++---- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 33e43e0d056..3d21e9df844 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -2068,20 +2068,6 @@ public Response getStorageDriver(@Context ContainerRequestContext crc, @PathPara String storageDriver = execCommand(new GetDataverseStorageDriverCommand(req, findDataverseOrDie(id), getEffective)); return ok(JsonPrinter.jsonStorageDriver(storageDriver)); }, getRequestUser(crc)); - - - - // try { - // AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); - // } catch (WrappedResponse wr) { - // return error(Response.Status.NOT_FOUND, wr.getMessage()); - // } - - // if (getEffective != null && getEffective) { - // return ok(JsonPrinter.jsonStorageDriver(dataverse.getEffectiveStorageDriverId())); - // } else { - // return ok(JsonPrinter.jsonStorageDriver(dataverse.getStorageDriverId())); - // } } @PUT diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index 24ab8b56eff..322bf9f4986 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -2920,10 +2920,10 @@ static Response deleteStorageSite(long storageSiteId) { .delete("/api/admin/storageSites/" + storageSiteId); } - static Response listStorageDrivers(String apiToken) { + static Response listStorageDrivers(String apiToken, String dataverseAlias) { return given() .header(API_TOKEN_HTTP_HEADER, apiToken) - .get("/api/admin/dataverse/storageDrivers"); + .get("/api/dataverses/" + dataverseAlias + "/storageDrivers"); } static Response getStorageDriver(String dvAlias, String apiToken) { @@ -2933,14 +2933,14 @@ static Response getStorageDriver(String dvAlias, String apiToken, Boolean getEff String params = getEffective != null ? "?getEffective=" + getEffective : ""; return given() .header(API_TOKEN_HTTP_HEADER, apiToken) - .get("/api/admin/dataverse/" + dvAlias + "/storageDriver" + params); + .get("/api/dataverses/" + dvAlias + "/storageDriver" + params); } static Response setStorageDriver(String dvAlias, String label, String apiToken) { return given() .header(API_TOKEN_HTTP_HEADER, apiToken) .body(label) - .put("/api/admin/dataverse/" + dvAlias + "/storageDriver"); + .put("/api/dataverses/" + dvAlias + "/storageDriver"); } static Response getUploadUrls(String idOrPersistentIdOfDataset, long sizeInBytes, String apiToken) { From 39f6a73f72bbc2e96616b951e68b50c695216dcd Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Wed, 25 Feb 2026 14:20:13 -0500 Subject: [PATCH 04/12] Update storage driver listing to include dataverse alias --- src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java index d9e21d9fdc7..596318519d4 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -6294,7 +6294,7 @@ public void testSetGetDatasetStorageDriver() { Response createDataset = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken); Integer datasetId = UtilIT.getDatasetIdFromResponse(createDataset); - Response storageDrivers = UtilIT.listStorageDrivers(apiToken); + Response storageDrivers = UtilIT.listStorageDrivers(apiToken, dataverseAlias); storageDrivers.prettyPrint(); JsonObject data = JsonUtil.getJsonObject(storageDrivers.getBody().asString()); String first = data.getJsonObject("data").keySet().iterator().next(); From 555adff3859fe28157938cbe8e88b7b9d5f2ad23 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Wed, 25 Feb 2026 14:27:12 -0500 Subject: [PATCH 05/12] Update S3AccessIT to specify storage driver root in listStorageDrivers calls --- .../java/edu/harvard/iq/dataverse/api/S3AccessIT.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/S3AccessIT.java b/src/test/java/edu/harvard/iq/dataverse/api/S3AccessIT.java index 60e83f9f2ba..48a64490796 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/S3AccessIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/S3AccessIT.java @@ -116,7 +116,7 @@ public void testNonDirectUpload() { String superuserApiToken = UtilIT.getApiTokenFromResponse(createSuperuser); String superusername = UtilIT.getUsernameFromResponse(createSuperuser); UtilIT.makeSuperUser(superusername).then().assertThat().statusCode(200); - Response storageDrivers = UtilIT.listStorageDrivers(superuserApiToken); + Response storageDrivers = UtilIT.listStorageDrivers(superuserApiToken, "root"); storageDrivers.prettyPrint(); // TODO where is "Local/local" coming from? String drivers = """ @@ -250,7 +250,7 @@ public void testDirectUpload() { String superuserApiToken = UtilIT.getApiTokenFromResponse(createSuperuser); String superusername = UtilIT.getUsernameFromResponse(createSuperuser); UtilIT.makeSuperUser(superusername).then().assertThat().statusCode(200); - Response storageDrivers = UtilIT.listStorageDrivers(superuserApiToken); + Response storageDrivers = UtilIT.listStorageDrivers(superuserApiToken, "root"); storageDrivers.prettyPrint(); // TODO where is "Local/local" coming from? String drivers = """ @@ -468,7 +468,7 @@ public void testDirectUploadDetectStataFile() { String superuserApiToken = UtilIT.getApiTokenFromResponse(createSuperuser); String superusername = UtilIT.getUsernameFromResponse(createSuperuser); UtilIT.makeSuperUser(superusername).then().assertThat().statusCode(200); - Response storageDrivers = UtilIT.listStorageDrivers(superuserApiToken); + Response storageDrivers = UtilIT.listStorageDrivers(superuserApiToken, "root"); storageDrivers.prettyPrint(); // TODO where is "Local/local" coming from? String drivers = """ @@ -655,7 +655,7 @@ public void testDirectUploadWithFileCountLimit() throws JsonParseException { String superuserApiToken = UtilIT.getApiTokenFromResponse(createSuperuser); String superusername = UtilIT.getUsernameFromResponse(createSuperuser); UtilIT.makeSuperUser(superusername).then().assertThat().statusCode(200); - Response storageDrivers = UtilIT.listStorageDrivers(superuserApiToken); + Response storageDrivers = UtilIT.listStorageDrivers(superuserApiToken, "root"); storageDrivers.prettyPrint(); // TODO where is "Local/local" coming from? String drivers = """ From 827f87815a5647499a1b8a16393a2910e729b474 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Thu, 26 Feb 2026 15:36:47 -0500 Subject: [PATCH 06/12] Update API endpoints in dataverses-datasets.rst to reflect correct storage driver paths --- .../source/admin/dataverses-datasets.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/sphinx-guides/source/admin/dataverses-datasets.rst b/doc/sphinx-guides/source/admin/dataverses-datasets.rst index c916b79aaa8..48481b414bf 100644 --- a/doc/sphinx-guides/source/admin/dataverses-datasets.rst +++ b/doc/sphinx-guides/source/admin/dataverses-datasets.rst @@ -52,17 +52,17 @@ Configure a Dataverse Collection to Store All New Files in a Specific File Store To direct new files (uploaded when datasets are created or edited) for all datasets in a given Dataverse collection, the store can be specified via the API as shown below, or by editing the 'General Information' for a Dataverse collection on the Dataverse collection page. Only accessible to superusers. :: - curl -H "X-Dataverse-key: $API_TOKEN" -X PUT -d $storageDriverLabel http://$SERVER/api/admin/dataverse/$dataverse-alias/storageDriver + curl -H "X-Dataverse-key: $API_TOKEN" -X PUT -d $storageDriverLabel http://$SERVER/api/dataverses/$dataverse-alias/storageDriver (Note that for ``dataverse.files.store1.label=MyLabel``, you should pass ``MyLabel``.) A store assigned directly to a collection can be seen using:: - curl -H "X-Dataverse-key: $API_TOKEN" http://$SERVER/api/admin/dataverse/$dataverse-alias/storageDriver + curl -H "X-Dataverse-key: $API_TOKEN" http://$SERVER/api/dataverses/$dataverse-alias/storageDriver This may be null. To get the effective storageDriver for a collection, which may be inherited from a parent collection or be the installation default, you can use:: - curl -H "X-Dataverse-key: $API_TOKEN" http://$SERVER/api/admin/dataverse/$dataverse-alias/storageDriver?getEffective=true + curl -H "X-Dataverse-key: $API_TOKEN" http://$SERVER/api/dataverses/$dataverse-alias/storageDriver?getEffective=true This will never be null. @@ -70,11 +70,11 @@ This will never be null. To delete a store assigned directly to a collection (so that the colllection's effective store is inherted from it's parent or is the global default), use:: - curl -H "X-Dataverse-key: $API_TOKEN" -X DELETE http://$SERVER/api/admin/dataverse/$dataverse-alias/storageDriver + curl -H "X-Dataverse-key: $API_TOKEN" -X DELETE http://$SERVER/api/dataverses/$dataverse-alias/storageDriver -The available drivers can be listed with:: +The available drivers within a collection can be listed with:: - curl -H "X-Dataverse-key: $API_TOKEN" http://$SERVER/api/admin/dataverse/storageDrivers + curl -H "X-Dataverse-key: $API_TOKEN" http://$SERVER/api/dataverses/$dataverse-alias/allowedStorageDrivers (Individual datasets can be configured to use specific file stores as well. See the "Datasets" section below.) From b40bd12c92223e87eb74600defbd7f73271b9cf3 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Thu, 26 Feb 2026 15:48:43 -0500 Subject: [PATCH 07/12] Add release notes for breaking changes in storage driver endpoints --- doc/release-notes/12141-storage-driver-endpoints.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/release-notes/12141-storage-driver-endpoints.md diff --git a/doc/release-notes/12141-storage-driver-endpoints.md b/doc/release-notes/12141-storage-driver-endpoints.md new file mode 100644 index 00000000000..dc0ac34a7bc --- /dev/null +++ b/doc/release-notes/12141-storage-driver-endpoints.md @@ -0,0 +1,6 @@ +### Breaking Changes + +All the endpoints related to Storage Drivers have been moved out of the Admin API. + +- The endpoints GET, PUT AND DELETE for `/admin/dataverse/{alias}/storageDriver`n has been moved to `/dataverses/{alias}/storageDriver`. +- The endpoint `/admin/dataverse/storageDrivers`n has been moved and renamed to `/dataverses/{alias}/allowedStorageDrivers`. Regarding the change of the name, this endpoint will in the future only display the storageDrivers that are allowed on the specified collection, as of now, it will display the entire list of available Drivers on the installation. From 1f254a033bf0ab9e289f13f9bffb194ca807e42d Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Tue, 3 Mar 2026 11:09:05 -0500 Subject: [PATCH 08/12] Refactor error handling in Dataverses API to use WrappedResponse for consistency --- .../harvard/iq/dataverse/api/Dataverses.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 3d21e9df844..dd4182241ea 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -2088,10 +2088,9 @@ public Response setStorageDriver(@Context ContainerRequestContext crc, SetDataverseStorageDriverCommand setDriverCommand = new SetDataverseStorageDriverCommand(request, dataverse, label); return ok(execCommand(setDriverCommand)); - } catch (IllegalArgumentException iae) { - return error(Response.Status.NOT_FOUND, iae.getMessage()); - } - + } catch (WrappedResponse wr) { + return handleWrappedResponse(wr); + } } @DELETE @@ -2109,9 +2108,9 @@ public Response resetStorageDriver(@Context ContainerRequestContext crc, @PathPa DataverseRequest request = createDataverseRequest(user); DeleteDataverseStorageDriverComman deleteDriverCommand = new DeleteDataverseStorageDriverComman(request, dataverse); return ok(execCommand(deleteDriverCommand)); - } catch (Exception e) { - return error(Response.Status.NOT_FOUND, e.getMessage()); - } + } catch (WrappedResponse wr) { + return handleWrappedResponse(wr); + } } @GET @@ -2133,9 +2132,9 @@ public Response listStorageDrivers(@Context ContainerRequestContext crc, @PathPa DataverseRequest request = createDataverseRequest(user); GetDataverseAllowedStorageDriverCommand getAllowedStorageDriversCommand = new GetDataverseAllowedStorageDriverCommand(request, dv); return ok(execCommand(getAllowedStorageDriversCommand)); - } catch (Exception e) { - return error(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage()); - } + } catch (WrappedResponse wr) { + return handleWrappedResponse(wr); + } } } From c4ec41ec65fdc4e2535d7c3e1db2b3defaa33731 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Tue, 3 Mar 2026 11:10:43 -0500 Subject: [PATCH 09/12] Remove unused imports in Dataverses API for cleaner code --- src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index dd4182241ea..6ae28d6c7a5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -2,15 +2,11 @@ import com.google.common.collect.Lists; import com.google.api.client.util.ArrayMap; -import com.google.api.client.util.Data; -import com.google.api.services.storage.Storage.AnywhereCaches.Get; - import edu.harvard.iq.dataverse.*; import edu.harvard.iq.dataverse.api.auth.AuthRequired; import edu.harvard.iq.dataverse.api.datadeposit.SwordServiceBean; import edu.harvard.iq.dataverse.api.dto.*; import edu.harvard.iq.dataverse.authorization.DataverseRole; - import edu.harvard.iq.dataverse.api.imports.ImportException; import edu.harvard.iq.dataverse.api.imports.ImportServiceBean; import edu.harvard.iq.dataverse.authorization.Permission; @@ -20,7 +16,6 @@ import edu.harvard.iq.dataverse.authorization.groups.impl.explicit.ExplicitGroupServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.authorization.users.User; -import edu.harvard.iq.dataverse.dataaccess.DataAccess; import edu.harvard.iq.dataverse.dataset.DatasetType; import edu.harvard.iq.dataverse.dataverse.DataverseUtil; import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItem; @@ -37,7 +32,6 @@ import edu.harvard.iq.dataverse.util.StringUtil; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.*; -import static edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder.jsonObjectBuilder; import edu.harvard.iq.dataverse.util.json.*; From 7f069ca625f7ab6db6fab8496e96145aea4ce162 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Tue, 3 Mar 2026 11:13:33 -0500 Subject: [PATCH 10/12] Remove unused imports in Info.java for cleaner code --- src/main/java/edu/harvard/iq/dataverse/api/Info.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Info.java b/src/main/java/edu/harvard/iq/dataverse/api/Info.java index be39b6681c6..1a60d3eb1ca 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Info.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Info.java @@ -1,18 +1,11 @@ package edu.harvard.iq.dataverse.api; -import static edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder.jsonObjectBuilder; - import java.util.logging.Logger; - -import edu.harvard.iq.dataverse.api.auth.AuthRequired; -import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.customization.CustomizationConstants; -import edu.harvard.iq.dataverse.dataaccess.DataAccess; import jakarta.ws.rs.*; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.container.ContainerRequestContext; import edu.harvard.iq.dataverse.export.ExportService; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; @@ -24,7 +17,6 @@ import jakarta.json.Json; import jakarta.json.JsonObjectBuilder; import jakarta.json.JsonValue; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.openapi.annotations.Operation; From 3634db6ec73248fcc169fbe7956968e09920e848 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Tue, 3 Mar 2026 11:15:52 -0500 Subject: [PATCH 11/12] Fix typo in DeleteDataverseStorageDriverCommand instantiation and add command implementation for resetting storage driver --- src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java | 2 +- ...erComman.java => DeleteDataverseStorageDriverCommand.java} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/edu/harvard/iq/dataverse/engine/command/impl/{DeleteDataverseStorageDriverComman.java => DeleteDataverseStorageDriverCommand.java} (82%) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 6ae28d6c7a5..e071d3bf8cb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -2100,7 +2100,7 @@ public Response resetStorageDriver(@Context ContainerRequestContext crc, @PathPa try { AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); DataverseRequest request = createDataverseRequest(user); - DeleteDataverseStorageDriverComman deleteDriverCommand = new DeleteDataverseStorageDriverComman(request, dataverse); + DeleteDataverseStorageDriverCommand deleteDriverCommand = new DeleteDataverseStorageDriverCommand(request, dataverse); return ok(execCommand(deleteDriverCommand)); } catch (WrappedResponse wr) { return handleWrappedResponse(wr); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverCommand.java similarity index 82% rename from src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java rename to src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverCommand.java index 9064b0fc731..39f368cb877 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverComman.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataverseStorageDriverCommand.java @@ -9,11 +9,11 @@ import edu.harvard.iq.dataverse.authorization.Permission; @RequiredPermissions(Permission.EditDataverse) -public class DeleteDataverseStorageDriverComman extends AbstractCommand { +public class DeleteDataverseStorageDriverCommand extends AbstractCommand { private Dataverse dv; - public DeleteDataverseStorageDriverComman(DataverseRequest aRequest, Dataverse dv) { + public DeleteDataverseStorageDriverCommand(DataverseRequest aRequest, Dataverse dv) { super(aRequest, dv); this.dv = dv; } From 26cc48bb5bcd7cfa27138b7b7464eb2afbfdf84e Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Tue, 3 Mar 2026 11:30:15 -0500 Subject: [PATCH 12/12] Update doc/release-notes/12141-storage-driver-endpoints.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- doc/release-notes/12141-storage-driver-endpoints.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/release-notes/12141-storage-driver-endpoints.md b/doc/release-notes/12141-storage-driver-endpoints.md index dc0ac34a7bc..614d3c2f3b1 100644 --- a/doc/release-notes/12141-storage-driver-endpoints.md +++ b/doc/release-notes/12141-storage-driver-endpoints.md @@ -2,5 +2,5 @@ All the endpoints related to Storage Drivers have been moved out of the Admin API. -- The endpoints GET, PUT AND DELETE for `/admin/dataverse/{alias}/storageDriver`n has been moved to `/dataverses/{alias}/storageDriver`. -- The endpoint `/admin/dataverse/storageDrivers`n has been moved and renamed to `/dataverses/{alias}/allowedStorageDrivers`. Regarding the change of the name, this endpoint will in the future only display the storageDrivers that are allowed on the specified collection, as of now, it will display the entire list of available Drivers on the installation. +- The endpoints GET, PUT AND DELETE for `/api/admin/dataverse/{alias}/storageDriver` has been moved to `/api/dataverses/{alias}/storageDriver`. +- The endpoint `/api/admin/dataverse/storageDrivers` has been moved and renamed to `/api/dataverses/{alias}/allowedStorageDrivers`. Regarding the change of the name, this endpoint will in the future only display the storageDrivers that are allowed on the specified collection, as of now, it will display the entire list of available Drivers on the installation.