diff --git a/dspace-api/src/main/java/org/dspace/scripts/filepreview/FilePreview.java b/dspace-api/src/main/java/org/dspace/scripts/filepreview/FilePreview.java index 60da5acaba30..a35a2ac6f035 100644 --- a/dspace-api/src/main/java/org/dspace/scripts/filepreview/FilePreview.java +++ b/dspace-api/src/main/java/org/dspace/scripts/filepreview/FilePreview.java @@ -7,10 +7,12 @@ */ package org.dspace.scripts.filepreview; +import java.sql.SQLException; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.UUID; +import javax.naming.AuthenticationException; import org.apache.commons.cli.ParseException; import org.apache.commons.lang3.StringUtils; @@ -58,8 +60,8 @@ public class FilePreview extends DSpaceRunnable { */ private String specificItemUUID = null; - private String email = null; - private String password = null; + private String epersonMail = null; + private String epersonPassword = null; @Override public FilePreviewConfiguration getScriptConfiguration() { @@ -83,12 +85,11 @@ public void setup() throws ParseException { specificItemUUID); } - if (commandLine.hasOption('e')) { - email = commandLine.getOptionValue('e'); - } + epersonMail = commandLine.getOptionValue('e'); + epersonPassword = commandLine.getOptionValue('p'); - if (commandLine.hasOption('p')) { - password = commandLine.getOptionValue('p'); + if (getEpersonIdentifier() == null && (epersonMail == null || epersonPassword == null)) { + throw new ParseException("Provide both -e/--email and -p/--password when no eperson is supplied."); } } @@ -101,30 +102,8 @@ public void internalRun() throws Exception { Context context = new Context(); try { - if (StringUtils.isBlank(email)) { - handler.logError("Email is required for authentication."); - return; - } - if (StringUtils.isBlank(password)) { - handler.logError("Password is required for authentication."); - return; - } - - EPerson eperson = ePersonService.findByEmail(context, email); - if (eperson == null) { - handler.logError("No EPerson found for this email: " + email); - return; - } - - int authenticated = authenticateService.authenticate(context, email, password, null, null); - if (AuthenticationMethod.SUCCESS != authenticated) { - handler.logError("Authentication failed for email: " + email); - return; - } else { - handler.logInfo("Authentication successful for email: " + email); - } - - context.setCurrentUser(eperson); + context.setCurrentUser(getAuthenticatedEperson((context))); + handler.logInfo("Authentication by user: " + context.getCurrentUser().getEmail()); if (StringUtils.isNotBlank(specificItemUUID)) { // Generate the preview only for a specific item generateItemFilePreviews(context, UUID.fromString(specificItemUUID)); @@ -203,4 +182,37 @@ public void printHelp() { " -p, --password Password for authentication\n"); } + + /** + * Retrieves an EPerson object either by its identifier or by performing an email-based lookup. + * It then authenticates the EPerson using the provided email and password. + * If the authentication is successful, it returns the EPerson object; otherwise, + * it throws an AuthenticationException. + * + * @param context The Context object used for interacting with the DSpace database and service layer. + * @return The authenticated EPerson object corresponding to the provided email, + * if authentication is successful. + * @throws SQLException If a database error occurs while retrieving or interacting with the EPerson data. + * @throws AuthenticationException If no EPerson is found for the provided email + * or if the authentication fails. + */ + private EPerson getAuthenticatedEperson(Context context) throws SQLException, AuthenticationException { + if (getEpersonIdentifier() != null) { + return ePersonService.find(context, getEpersonIdentifier()); + } + String msg; + EPerson ePerson = ePersonService.findByEmail(context, epersonMail); + if (ePerson == null) { + msg = "No EPerson found for this email: " + epersonMail; + handler.logError(msg); + throw new AuthenticationException(msg); + } + int authenticated = authenticateService.authenticate(context, epersonMail, epersonPassword, null, null); + if (AuthenticationMethod.SUCCESS != authenticated) { + msg = "Authentication failed for email: " + epersonMail; + handler.logError(msg); + throw new AuthenticationException(msg); + } + return ePerson; + } } diff --git a/dspace-api/src/test/java/org/dspace/scripts/filepreview/FilePreviewIT.java b/dspace-api/src/test/java/org/dspace/scripts/filepreview/FilePreviewIT.java index 09bb7552aafa..7d3cad26fc0a 100644 --- a/dspace-api/src/test/java/org/dspace/scripts/filepreview/FilePreviewIT.java +++ b/dspace-api/src/test/java/org/dspace/scripts/filepreview/FilePreviewIT.java @@ -12,6 +12,7 @@ import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertEquals; import java.io.InputStream; import java.sql.SQLException; @@ -86,11 +87,9 @@ public void testUnauthorizedEmail() throws Exception { // Run the script TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler(); String[] args = new String[] { "file-preview"}; - ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl); - - List messages = testDSpaceRunnableHandler.getErrorMessages(); - assertThat(messages, hasSize(1)); - assertThat(messages, hasItem(containsString("Email is required for authentication."))); + int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), + testDSpaceRunnableHandler, kernelImpl); + assertEquals(1, run); // Since a ParseException was caught, expect return code 1 } @Test @@ -98,11 +97,9 @@ public void testUnauthorizedPassword() throws Exception { // Run the script TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler(); String[] args = new String[] { "file-preview", "-e", eperson.getEmail()}; - ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl); - - List messages = testDSpaceRunnableHandler.getErrorMessages(); - assertThat(messages, hasSize(1)); - assertThat(messages, hasItem(containsString("Password is required for authentication."))); + int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), + testDSpaceRunnableHandler, kernelImpl); + assertEquals(1, run); // Since a ParseException was caught, expect return code 1 } @Test @@ -110,8 +107,9 @@ public void testWhenNoFilesRun() throws Exception { TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler(); String[] args = new String[] { "file-preview", "-e", eperson.getEmail(), "-p", PASSWORD }; - ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl); - + int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), + testDSpaceRunnableHandler, kernelImpl); + assertEquals(0, run); checkNoError(testDSpaceRunnableHandler); } @@ -121,8 +119,9 @@ public void testForSpecificItem() throws Exception { TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler(); String[] args = new String[] { "file-preview", "-u", item.getID().toString(), "-e", eperson.getEmail(), "-p", PASSWORD}; - ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl); - + int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), + testDSpaceRunnableHandler, kernelImpl); + assertEquals(0, run); // There should be no errors or warnings checkNoError(testDSpaceRunnableHandler); @@ -132,7 +131,7 @@ public void testForSpecificItem() throws Exception { assertThat(messages, hasItem(containsString("Generate the file previews for the specified item with " + "the given UUID: " + item.getID()))); assertThat(messages, - hasItem(containsString("Authentication successful for email: " + eperson.getEmail()))); + hasItem(containsString("Authentication by user: " + eperson.getEmail()))); } @Test @@ -140,8 +139,9 @@ public void testForAllItem() throws Exception { // Run the script TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler(); String[] args = new String[] { "file-preview", "-e", eperson.getEmail(), "-p", PASSWORD}; - ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl); - + int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), + testDSpaceRunnableHandler, kernelImpl); + assertEquals(0, run); // There should be no errors or warnings checkNoError(testDSpaceRunnableHandler); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ScriptConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ScriptConverter.java index 2d84a91dc771..22b5f92c7085 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ScriptConverter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ScriptConverter.java @@ -9,6 +9,7 @@ import java.util.LinkedList; import java.util.List; +import java.util.Objects; import org.apache.commons.cli.Option; import org.apache.commons.collections4.CollectionUtils; @@ -36,6 +37,13 @@ public ScriptRest convert(ScriptConfiguration scriptConfiguration, Projection pr List parameterRestList = new LinkedList<>(); for (Option option : CollectionUtils.emptyIfNull(scriptConfiguration.getOptions().getOptions())) { + if ("file-preview".equalsIgnoreCase(scriptConfiguration.getName()) + && (Objects.equals(option.getOpt(), "e") + || Objects.equals(option.getOpt(), "p") + || Objects.equals(option.getLongOpt(), "email") + || Objects.equals(option.getLongOpt(), "password"))) { + continue; + } ParameterRest parameterRest = new ParameterRest(); parameterRest.setDescription(option.getDescription()); parameterRest.setName((option.getOpt() != null ? "-" + option.getOpt() : "--" + option.getLongOpt())); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScriptRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScriptRestRepositoryIT.java index 42c9f2c9f7b4..bb536028aa43 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScriptRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ScriptRestRepositoryIT.java @@ -579,8 +579,56 @@ public void postProcessAndVerifyOutput() throws Exception { } } + @Test + public void postFilePreviewProcess() throws Exception { + LinkedList parameters = new LinkedList<>(); + + List list = parameters.stream() + .map(dSpaceCommandLineParameter -> dSpaceRunnableParameterConverter + .convert(dSpaceCommandLineParameter, Projection.DEFAULT)) + .collect(Collectors.toList()); + + String token = getAuthToken(admin.getEmail(), password); + List acceptableProcessStatuses = new LinkedList<>(); + acceptableProcessStatuses.addAll(Arrays.asList(ProcessStatus.SCHEDULED, + ProcessStatus.RUNNING, + ProcessStatus.COMPLETED)); + + AtomicReference idRef = new AtomicReference<>(); + + try { + getClient(token) + .perform(multipart("/api/system/scripts/file-preview/processes") + .param("properties", new ObjectMapper().writeValueAsString(list))) + .andExpect(status().isAccepted()) + .andExpect(jsonPath("$", is( + ProcessMatcher.matchProcess("file-preview", + String.valueOf(admin.getID()), + parameters, + acceptableProcessStatuses)))) + .andDo(result -> idRef + .set(read(result.getResponse().getContentAsString(), "$.processId"))); + Process process = processService.find(context, idRef.get()); + Bitstream bitstream = processService.getBitstream(context, process, Process.OUTPUT_TYPE); + MvcResult mvcResult = getClient(token) + .perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content")).andReturn(); + String content = mvcResult.getResponse().getContentAsString(); + getClient(token).perform(get("/api/system/processes/" + idRef.get() + "/output")) + .andExpect(status().isOk()); + assertThat(content, CoreMatchers + .containsString("INFO file-preview - " + process.getID() + " @ The script has started")); + assertThat(content, + CoreMatchers.containsString( + "INFO file-preview - " + process.getID() + + " @ Authentication by user: " + admin.getEmail())); + assertThat(content, CoreMatchers + .containsString("INFO file-preview - " + process.getID() + " @ The script has completed")); + } finally { + ProcessBuilder.deleteProcess(idRef.get()); + } + } @Test public void postProcessAdminWithWrongContentTypeBadRequestException() throws Exception {