Skip to content

Commit 59387eb

Browse files
kosarkomilanmajchrak
authored andcommitted
[Port to dtq-dev] Issue 1364: tgz file preview fix (#1338)
(cherry picked from commit 15b296a on dtq-dev) v9 adaptations / conflict resolution: - FilePreviewIT.java: single conflict resolved toward the v9-base deletion of testPreviewWithSyncStorage + SyncBitstreamStorageServiceImpl import/SYNC_STORE_NUMBER (that class does not exist on v9-base); the commit's modernization hunk for that test dropped, everything else applied (testUnauthorizedPassword removed, -p args dropped, checkHandlerMessages helper + testPreviewWithForce added). Resulting file contains exactly 6 tests. - Intentional semantics change carried from the fork commit: the file-preview CLI no longer requires -p/--password; EPerson resolved from context or -e email, consistent with other DSpace CLI scripts. Admin-only operations stay guarded server-side. Fulfils CLARIN_V9_POST_SNAPSHOT_SYNC_ACCEPTANCE.md §5 / 15b296a (BE-1, Vlna 1).
1 parent 7415b4c commit 59387eb

5 files changed

Lines changed: 112 additions & 64 deletions

File tree

dspace-api/src/main/java/org/dspace/content/PreviewContentServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ private void processGzipFile(List<String> filePaths, File file, Bitstream bitstr
369369
if (fileName == null) {
370370
logBitstreamNameIsNull();
371371
} else {
372-
if (fileName.toLowerCase().endsWith("tar.gz")) {
372+
if (fileName.toLowerCase().endsWith(".tar.gz") || fileName.toLowerCase().endsWith(".tgz")) {
373373
processTarGzipFile(filePaths, file, bitstream);
374374
} else {
375375
try (InputStream is = new GzipCompressorInputStream(new FileInputStream(file))) {

dspace-api/src/main/java/org/dspace/scripts/filepreview/FilePreview.java

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@
1616

1717
import org.apache.commons.cli.ParseException;
1818
import org.apache.commons.lang3.StringUtils;
19-
import org.dspace.authenticate.AuthenticationMethod;
20-
import org.dspace.authenticate.factory.AuthenticateServiceFactory;
21-
import org.dspace.authenticate.service.AuthenticationService;
2219
import org.dspace.content.Bitstream;
2320
import org.dspace.content.Bundle;
2421
import org.dspace.content.Item;
22+
import org.dspace.content.PreviewContent;
2523
import org.dspace.content.factory.ContentServiceFactory;
2624
import org.dspace.content.service.ItemService;
2725
import org.dspace.content.service.PreviewContentService;
@@ -46,21 +44,19 @@ public class FilePreview extends DSpaceRunnable<FilePreviewConfiguration> {
4644
ContentServiceFactory.getInstance().getPreviewContentService();
4745
private EPersonService ePersonService = EPersonServiceFactory.getInstance()
4846
.getEPersonService();
49-
private AuthenticationService authenticateService = AuthenticateServiceFactory.getInstance()
50-
.getAuthenticationService();
5147

5248
/**
5349
* `-i`: Info, show help information.
5450
*/
5551
private boolean info = false;
52+
private boolean force = false;
5653

5754
/**
5855
* `-u`: UUID of the Item for which to create a preview of its bitstreams.
5956
*/
6057
private String specificItemUUID = null;
6158

6259
private String epersonMail = null;
63-
private String epersonPassword = null;
6460

6561
@Override
6662
public FilePreviewConfiguration getScriptConfiguration() {
@@ -84,11 +80,14 @@ public void setup() throws ParseException {
8480
specificItemUUID);
8581
}
8682

83+
if (commandLine.hasOption('f')) {
84+
force = true;
85+
}
86+
8787
epersonMail = commandLine.getOptionValue('e');
88-
epersonPassword = commandLine.getOptionValue('p');
8988

90-
if (getEpersonIdentifier() == null && (epersonMail == null || epersonPassword == null)) {
91-
throw new ParseException("Provide both -e/--email and -p/--password when no eperson is supplied.");
89+
if (getEpersonIdentifier() == null && epersonMail == null) {
90+
throw new ParseException("Provide -e/--email when no eperson is supplied.");
9291
}
9392
}
9493

@@ -101,7 +100,7 @@ public void internalRun() throws Exception {
101100

102101
Context context = new Context();
103102
try {
104-
context.setCurrentUser(getAuthenticatedEperson((context)));
103+
context.setCurrentUser(getEperson(context));
105104
handler.logInfo("Authentication by user: " + context.getCurrentUser().getEmail());
106105
if (StringUtils.isNotBlank(specificItemUUID)) {
107106
// Generate the preview only for a specific item
@@ -152,7 +151,17 @@ private void generateItemFilePreviews(Context context, UUID itemUUID) throws Exc
152151
}
153152
// Generate new content if we didn't find any
154153
if (previewContentService.hasPreview(context, bitstream)) {
155-
continue;
154+
if (force) {
155+
List<PreviewContent> previewContents = previewContentService
156+
.findByBitstream(context, bitstream.getID());
157+
for (PreviewContent content : previewContents) {
158+
handler.logInfo("Deleting existing preview content: '" + content.getName() +
159+
"', for bitstream: '" + bitstream.getName() + "'");
160+
previewContentService.delete(context, content);
161+
}
162+
} else {
163+
continue;
164+
}
156165
}
157166

158167
List<FileInfo> fileInfos = previewContentService.getFilePreviewContent(context, bitstream);
@@ -162,6 +171,7 @@ private void generateItemFilePreviews(Context context, UUID itemUUID) throws Exc
162171
continue;
163172
}
164173

174+
handler.logInfo("Generating file preview for bitstream: " + bitstream.getName());
165175
for (FileInfo fi : fileInfos) {
166176
previewContentService.createPreviewContent(context, bitstream, fi);
167177
}
@@ -176,38 +186,30 @@ public void printHelp() {
176186
"You can choose from these available options:\n" +
177187
" -i, --info Show help information\n" +
178188
" -u, --uuid The UUID of the ITEM for which to create a preview of its bitstreams\n" +
179-
" -e, --email Email for authentication\n" +
180-
" -p, --password Password for authentication\n");
189+
" -f, --force Force to create preview, even when the preview exists\n" +
190+
" -e, --email Email of the eperson to run the script as\n");
181191

182192
}
183193

184194
/**
185-
* Retrieves an EPerson object either by its identifier or by performing an email-based lookup.
186-
* It then authenticates the EPerson using the provided email and password.
187-
* If the authentication is successful, it returns the EPerson object; otherwise,
188-
* it throws an AuthenticationException.
195+
* Resolves the EPerson the script runs as: the eperson supplied by the launching context
196+
* (e.g. the logged-in user when started from the admin UI) if present, otherwise the eperson
197+
* looked up by the {@code -e}/--email option. Like other CLI scripts, command-line invocation
198+
* is trusted (shell access implies full server access), so no password is verified here;
199+
* admin-only operations remain guarded by authorization checks in the service layer.
189200
*
190201
* @param context The Context object used for interacting with the DSpace database and service layer.
191-
* @return The authenticated EPerson object corresponding to the provided email,
192-
* if authentication is successful.
193-
* @throws SQLException If a database error occurs while retrieving or interacting with the EPerson data.
194-
* @throws AuthenticationException If no EPerson is found for the provided email
195-
* or if the authentication fails.
202+
* @return The EPerson the script should run as.
203+
* @throws SQLException If a database error occurs while retrieving the EPerson data.
204+
* @throws AuthenticationException If no EPerson is found for the provided email.
196205
*/
197-
private EPerson getAuthenticatedEperson(Context context) throws SQLException, AuthenticationException {
206+
private EPerson getEperson(Context context) throws SQLException, AuthenticationException {
198207
if (getEpersonIdentifier() != null) {
199208
return ePersonService.find(context, getEpersonIdentifier());
200209
}
201-
String msg;
202210
EPerson ePerson = ePersonService.findByEmail(context, epersonMail);
203211
if (ePerson == null) {
204-
msg = "No EPerson found for this email: " + epersonMail;
205-
handler.logError(msg);
206-
throw new AuthenticationException(msg);
207-
}
208-
int authenticated = authenticateService.authenticate(context, epersonMail, epersonPassword, null, null);
209-
if (AuthenticationMethod.SUCCESS != authenticated) {
210-
msg = "Authentication failed for email: " + epersonMail;
212+
String msg = "No EPerson found for this email: " + epersonMail;
211213
handler.logError(msg);
212214
throw new AuthenticationException(msg);
213215
}

dspace-api/src/main/java/org/dspace/scripts/filepreview/FilePreviewConfiguration.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,11 @@ public Options getOptions() {
3939
options.getOption("u").setType(String.class);
4040
options.getOption("u").setRequired(false);
4141

42+
options.addOption("f", "force", false, "Force to create preview, even when the preview exists.");
43+
4244
options.addOption("e", "email", true,
43-
"Email for authentication.");
45+
"Email of the eperson to run the script as.");
4446
options.getOption("e").setType(String.class);
45-
options.getOption("e").setRequired(true);
46-
47-
options.addOption("p", "password", true,
48-
"Password for authentication.");
49-
options.getOption("p").setType(String.class);
50-
options.getOption("p").setRequired(true);
5147

5248
super.options = options;
5349
}

dspace-api/src/test/java/org/dspace/scripts/filepreview/FilePreviewIT.java

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -102,21 +102,11 @@ public void testUnauthorizedEmail() throws Exception {
102102
assertEquals(1, run); // Since a ParseException was caught, expect return code 1
103103
}
104104

105-
@Test
106-
public void testUnauthorizedPassword() throws Exception {
107-
// Run the script
108-
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
109-
String[] args = new String[] { "file-preview", "-e", ePerson.getEmail()};
110-
int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl),
111-
testDSpaceRunnableHandler, kernelImpl);
112-
assertEquals(1, run); // Since a ParseException was caught, expect return code 1
113-
}
114-
115105
@Test
116106
public void testWhenNoFilesRun() throws Exception {
117107
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
118108

119-
String[] args = new String[] { "file-preview", "-e", ePerson.getEmail(), "-p", PASSWORD };
109+
String[] args = new String[] { "file-preview", "-e", ePerson.getEmail() };
120110
int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl),
121111
testDSpaceRunnableHandler, kernelImpl);
122112
assertEquals(0, run);
@@ -127,7 +117,8 @@ public void testWhenNoFilesRun() throws Exception {
127117
public void testForSpecificItem() throws Exception {
128118
Item item2 = createOtherWorkspaceItemWithBitstream(ePerson, 0);
129119
// Run the script
130-
runScriptForItemWithBitstreams(item2, ePerson, PASSWORD);
120+
TestDSpaceRunnableHandler testHandler = runScriptForItemWithBitstreams(item2, ePerson);
121+
checkHandlerMessages(testHandler, ePerson, item2, "logos.tgz", true);
131122

132123
Bitstream b = bitstreamService.findAll(context).stream()
133124
.filter(bitstream -> bitstream.getName().equals("logos.tgz"))
@@ -145,7 +136,8 @@ public void testForSpecificItem() throws Exception {
145136
public void testWhenScriptCannotCreateFilePreview() throws Exception {
146137
Item item2 = createOtherWorkspaceItemWithBitstream(eperson, 0);
147138
// Run the script as another user, without admin rights
148-
runScriptForItemWithBitstreams(item2, ePerson, PASSWORD);
139+
TestDSpaceRunnableHandler testHandler = runScriptForItemWithBitstreams(item2, ePerson);
140+
checkHandlerMessages(testHandler, ePerson, item2, null, false);
149141

150142
Bitstream b = bitstreamService.findAll(context).stream()
151143
.filter(bitstream -> bitstream.getName().equals("logos.tgz"))
@@ -159,7 +151,8 @@ public void testWhenScriptCannotCreateFilePreview() throws Exception {
159151
assertFalse("Expects preview content not created.", previewContentService.hasPreview(context, b));
160152

161153
// Run the script as admin user
162-
runScriptForItemWithBitstreams(item2, admin, password);
154+
testHandler = runScriptForItemWithBitstreams(item2, admin);
155+
checkHandlerMessages(testHandler, admin, item2, "logos.tgz", true);
163156

164157
// now the preview content was created since the script was run by admin user
165158
assertTrue("Expects preview content created.", previewContentService.hasPreview(context, b));
@@ -170,37 +163,76 @@ public void testWhenScriptCannotCreateFilePreview() throws Exception {
170163
public void testForAllItem() throws Exception {
171164
// Run the script
172165
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
173-
String[] args = new String[] { "file-preview", "-e", ePerson.getEmail(), "-p", PASSWORD};
166+
String[] args = new String[] { "file-preview", "-e", ePerson.getEmail()};
174167
int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl),
175168
testDSpaceRunnableHandler, kernelImpl);
176169
assertEquals(0, run);
177170
// There should be no errors or warnings
178171
checkNoError(testDSpaceRunnableHandler);
179172
}
180173

174+
@Test
175+
public void testPreviewWithForce() throws Exception {
176+
Item item2 = createOtherWorkspaceItemWithBitstream(ePerson, 0);
177+
// Run the script
178+
TestDSpaceRunnableHandler testHandler1 = runScriptForItemWithBitstreams(item2, ePerson);
179+
checkHandlerMessages(testHandler1, ePerson, item2, "logos.tgz", true);
180+
181+
// run again with force option, the existing preview content should be deleted and new one created
182+
TestDSpaceRunnableHandler testHandler2 = new TestDSpaceRunnableHandler();
183+
String[] args = new String[] { "file-preview", "-u", item2.getID().toString(),
184+
"-e", admin.getEmail(), "-f"};
185+
int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testHandler2, kernelImpl);
186+
assertEquals(0, run);
187+
checkNoError(testHandler2);
188+
189+
List<String> messages = testHandler2.getInfoMessages();
190+
assertThat(messages, hasSize(7));
191+
192+
assertThat(messages, hasItem(containsString("Deleting existing preview content:")));
193+
194+
Bitstream b = bitstreamService.findAll(context).stream()
195+
.filter(bitstream -> bitstream.getName().equals("logos.tgz"))
196+
.findFirst().orElse(null);
197+
198+
assertTrue("Expects preview content created.", previewContentService.hasPreview(context, b));
199+
assertEquals(2, previewContentService.getPreview(context, b).size());
200+
}
201+
181202
private void checkNoError(TestDSpaceRunnableHandler testDSpaceRunnableHandler) {
182203
assertThat(testDSpaceRunnableHandler.getErrorMessages(), empty());
183204
assertThat(testDSpaceRunnableHandler.getWarningMessages(), empty());
184205
}
185206

186-
private void runScriptForItemWithBitstreams(Item item, EPerson user, String password) throws Exception {
207+
private TestDSpaceRunnableHandler runScriptForItemWithBitstreams(Item item, EPerson user)
208+
throws Exception {
187209
// Run the script
188210
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
189211
String[] args = new String[] { "file-preview", "-u", item.getID().toString(),
190-
"-e", user.getEmail(), "-p", password};
212+
"-e", user.getEmail()};
191213
int run = ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl),
192214
testDSpaceRunnableHandler, kernelImpl);
193215
assertEquals(0, run);
194216
// There should be no errors or warnings
195217
checkNoError(testDSpaceRunnableHandler);
196218

197-
// There should be an info message about generating the file previews for the specified item
219+
return testDSpaceRunnableHandler;
220+
}
221+
222+
private void checkHandlerMessages(TestDSpaceRunnableHandler testDSpaceRunnableHandler,
223+
EPerson user,
224+
Item item,
225+
String fileName,
226+
boolean previewGenerationExpected) {
198227
List<String> messages = testDSpaceRunnableHandler.getInfoMessages();
199-
assertThat(messages, hasSize(2));
228+
assertThat(messages, hasSize(previewGenerationExpected ? 3 : 2));
200229
assertThat(messages, hasItem(containsString("Generate the file previews for the specified item with " +
201230
"the given UUID: " + item.getID())));
202-
assertThat(messages,
203-
hasItem(containsString("Authentication by user: " + user.getEmail())));
231+
assertThat(messages, hasItem(containsString("Authentication by user: " + user.getEmail())));
232+
if (previewGenerationExpected) {
233+
// There should be an info message about generating the file previews for the specified bitstream
234+
assertThat(messages, hasItem(containsString("Generating file preview for bitstream: " + fileName)));
235+
}
204236
}
205237

206238
private Item createOtherWorkspaceItemWithBitstream(EPerson user, int storageNumber) throws Exception {

dspace-server-webapp/src/test/java/org/dspace/app/rest/PreviewContentServiceImplIT.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public class PreviewContentServiceImplIT extends AbstractControllerIntegrationTe
6666
Bitstream gzFile;
6767
Bitstream tarXzFile;
6868
Bitstream xzFile;
69+
Bitstream tgzFileWithGzipMimeType;
6970
Bitstream tarGzFileWithWrongExtension;
7071
Bitstream tarXzFileWithIncorrectMimeType;
7172

@@ -133,6 +134,15 @@ public void setup() throws SQLException, AuthorizeException, IOException {
133134
.build();
134135
}
135136

137+
try (InputStream is = getClass().getResourceAsStream("assetstore/logos.tgz")) {
138+
tgzFileWithGzipMimeType = BitstreamBuilder.
139+
createBitstream(context, bundle1, is)
140+
.withName("logos.tgz")
141+
.withDescription("tar.gz compressed file with tgz extension")
142+
.withMimeType("application/x-gzip")
143+
.build();
144+
}
145+
136146
try (InputStream is = getClass().getResourceAsStream("assetstore/logos.tgz")) {
137147
tgzFile = BitstreamBuilder.
138148
createBitstream(context, bundle1, is)
@@ -235,18 +245,21 @@ public void destroy() throws Exception {
235245
BitstreamBuilder.deleteBitstream(tarGzFile.getID());
236246

237247
BitstreamFormat customMimeTypeFormat = tarXGzipFile.getFormat(context);
238-
BitstreamBuilder.deleteBitstream(tarXGzipFile.getID());
239-
if (customMimeTypeFormat != null) {
240-
bitstreamFormatService.delete(context, customMimeTypeFormat);
241-
}
242248

249+
BitstreamBuilder.deleteBitstream(tarXGzipFile.getID());
243250
BitstreamBuilder.deleteBitstream(tgzFile.getID());
244251
BitstreamBuilder.deleteBitstream(gzFile.getID());
245252
BitstreamBuilder.deleteBitstream(tarXzFile.getID());
246253
BitstreamBuilder.deleteBitstream(xzFile.getID());
254+
BitstreamBuilder.deleteBitstream(tgzFileWithGzipMimeType.getID());
247255
BitstreamBuilder.deleteBitstream(tarGzFileWithWrongExtension.getID());
248256
BitstreamBuilder.deleteBitstream(tarXzFileWithIncorrectMimeType.getID());
249257

258+
// removing custom mime type format created for tarXGzipFile and tgzFileWithGzipMimeType files
259+
if (customMimeTypeFormat != null) {
260+
bitstreamFormatService.delete(context, customMimeTypeFormat);
261+
}
262+
250263
super.destroy();
251264
}
252265

@@ -338,6 +351,11 @@ public void testXzContent() throws Exception {
338351
assertFileInfo(xzFile, "logos", 24);
339352
}
340353

354+
@Test
355+
public void testTgzContentWithGzipMimetype() throws Exception {
356+
assertFileInfos(tgzFileWithGzipMimeType);
357+
}
358+
341359
@Test
342360
public void testGzContentForFileWithWrongExtension() throws Exception {
343361
assertFileInfo(tarGzFileWithWrongExtension, "TAR GZ File", 24);

0 commit comments

Comments
 (0)