From 08060d381d97e727e1bf3f2a6176621af2bc9d60 Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Thu, 12 Oct 2023 16:16:33 -0400 Subject: [PATCH 01/11] BXC-4061 updating facet constants and adding handling for events --- .../solr/filter/SetContentStatusFilter.java | 4 +- .../filter/SetContentStatusFilterTest.java | 4 +- .../lib/boxc/search/api/FacetConstants.java | 4 +- static/js/admin/src/ResultObjectActionMenu.js | 19 ++++++++ .../src/action/AssignAsThumbnailAction.js | 43 +++++++++++++++++++ .../action/ClearAssignedThumbnailAction.js | 43 +++++++++++++++++++ 6 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 static/js/admin/src/action/AssignAsThumbnailAction.js create mode 100644 static/js/admin/src/action/ClearAssignedThumbnailAction.js diff --git a/indexing-solr/src/main/java/edu/unc/lib/boxc/indexing/solr/filter/SetContentStatusFilter.java b/indexing-solr/src/main/java/edu/unc/lib/boxc/indexing/solr/filter/SetContentStatusFilter.java index e1b2f79974..b89dfc169d 100644 --- a/indexing-solr/src/main/java/edu/unc/lib/boxc/indexing/solr/filter/SetContentStatusFilter.java +++ b/indexing-solr/src/main/java/edu/unc/lib/boxc/indexing/solr/filter/SetContentStatusFilter.java @@ -54,7 +54,7 @@ private List determineContentStatus(DocumentIndexingPackage dip) status.add(FacetConstants.IS_PRIMARY_OBJECT); } if (parentResc.hasProperty(Cdr.useAsThumbnail, resc)) { - status.add(FacetConstants.IS_ASSIGNED_THUMBNAIL); + status.add(FacetConstants.ASSIGNED_AS_THUMBNAIL); } } @@ -75,7 +75,7 @@ private void addWorkObjectStatuses(List status, Resource resource) { } if (resource.hasProperty(Cdr.useAsThumbnail)) { - status.add(FacetConstants.THUMBNAIL_ASSIGNED); + status.add(FacetConstants.HAS_THUMBNAIL_ASSIGNED); } else { status.add(FacetConstants.NO_THUMBNAIL_ASSIGNED); } diff --git a/indexing-solr/src/test/java/edu/unc/lib/boxc/indexing/solr/filter/SetContentStatusFilterTest.java b/indexing-solr/src/test/java/edu/unc/lib/boxc/indexing/solr/filter/SetContentStatusFilterTest.java index 8796c2ad07..5cc21ddd74 100644 --- a/indexing-solr/src/test/java/edu/unc/lib/boxc/indexing/solr/filter/SetContentStatusFilterTest.java +++ b/indexing-solr/src/test/java/edu/unc/lib/boxc/indexing/solr/filter/SetContentStatusFilterTest.java @@ -190,7 +190,7 @@ public void testWorkWithAssignedThumbnail() throws Exception { filter.filter(dip); verify(idb).setContentStatus(listCaptor.capture()); - assertTrue(listCaptor.getValue().contains(FacetConstants.THUMBNAIL_ASSIGNED)); + assertTrue(listCaptor.getValue().contains(FacetConstants.HAS_THUMBNAIL_ASSIGNED)); assertFalse(listCaptor.getValue().contains(FacetConstants.NO_THUMBNAIL_ASSIGNED)); } @@ -216,6 +216,6 @@ public void testIsAssignedThumbnail() throws Exception { filter.filter(dip); verify(idb).setContentStatus(listCaptor.capture()); - assertTrue(listCaptor.getValue().contains(FacetConstants.IS_ASSIGNED_THUMBNAIL)); + assertTrue(listCaptor.getValue().contains(FacetConstants.ASSIGNED_AS_THUMBNAIL)); } } diff --git a/search-api/src/main/java/edu/unc/lib/boxc/search/api/FacetConstants.java b/search-api/src/main/java/edu/unc/lib/boxc/search/api/FacetConstants.java index a6ffe9d126..c5ccf7a509 100644 --- a/search-api/src/main/java/edu/unc/lib/boxc/search/api/FacetConstants.java +++ b/search-api/src/main/java/edu/unc/lib/boxc/search/api/FacetConstants.java @@ -23,8 +23,8 @@ public abstract class FacetConstants { public static final String STAFF_ONLY_ACCESS = "Staff-Only Access"; public static final String MEMBERS_ARE_ORDERED = "Members Are Ordered"; public static final String MEMBERS_ARE_UNORDERED = "Members Are Unordered"; - public static final String THUMBNAIL_ASSIGNED = "Has Assigned Thumbnail"; + public static final String HAS_THUMBNAIL_ASSIGNED = "Has Assigned Thumbnail"; public static final String NO_THUMBNAIL_ASSIGNED = "No Assigned Thumbnail"; - public static final String IS_ASSIGNED_THUMBNAIL = "Is Assigned Thumbnail"; + public static final String ASSIGNED_AS_THUMBNAIL = "Assigned As Thumbnail"; } diff --git a/static/js/admin/src/ResultObjectActionMenu.js b/static/js/admin/src/ResultObjectActionMenu.js index afca876247..c5ad4021bf 100644 --- a/static/js/admin/src/ResultObjectActionMenu.js +++ b/static/js/admin/src/ResultObjectActionMenu.js @@ -151,6 +151,11 @@ define('ResultObjectActionMenu', [ 'jquery', 'jquery-ui', 'StringUtilities', 'A } else { items['setAsPrimaryObject'] = { name : 'Set as Primary Object' }; } + if ($.inArray('Assigned As Thumbnail', metadata.contentStatus) != -1) { + items['clearAssignedThumbnail'] = { name : 'Clear Assigned Thumbnail' }; + } else { + items['assignAsThumbnail'] = { name : 'Assign as Thumbnail' }; + } } else if (metadata.type == 'Work') { if ($.inArray('Has Primary Object', metadata.contentStatus) != -1) { items['clearPrimaryObject'] = { name : 'Clear Primary Object' }; @@ -363,6 +368,20 @@ define('ResultObjectActionMenu', [ 'jquery', 'jquery-ui', 'StringUtilities', 'A confirm : false }); break; + case "clearAssignedThumbnail" : + self.actionHandler.addEvent({ + action : 'ClearAssignedThumbnail', + target : resultObject, + confirm : false + }); + break; + case "assignAsThumbnail" : + self.actionHandler.addEvent({ + action : 'AssignAsThumbnail', + target : resultObject, + confirm : false + }); + break; case "destroy" : self.actionHandler.addEvent({ action : 'DestroyResult', diff --git a/static/js/admin/src/action/AssignAsThumbnailAction.js b/static/js/admin/src/action/AssignAsThumbnailAction.js new file mode 100644 index 0000000000..8ab757e626 --- /dev/null +++ b/static/js/admin/src/action/AssignAsThumbnailAction.js @@ -0,0 +1,43 @@ +define('AssignAsThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], function($, AjaxCallbackAction) { + + function AssignAsThumbnailAction(context) { + this._create(context); + }; + + AssignAsThumbnailAction.prototype.constructor = AssignAsThumbnailAction; + AssignAsThumbnailAction.prototype = Object.create( AjaxCallbackAction.prototype ); + + AssignAsThumbnailAction.prototype._create = function(context) { + this.context = context; + + var options = { + workMethod: "PUT", + workPath: "/services/api/edit/assignThumbnail/{idPath}", + workLabel: "Setting as assigned thumbnail...", + followupLabel: "Setting as assigned thumbnail...", + followupPath: "/services/api/status/item/{idPath}/solrRecord/version" + } + + if ('confirm' in this.context && !this.context.confirm) { + options.confirm = false; + } else { + options.confirm = { + promptText : "Use this as the assigned thumbnail for its parent?", + confirmAnchor : this.context.confirmAnchor + }; + } + + AjaxCallbackAction.prototype._create.call(this, options); + }; + + AssignAsThumbnailAction.prototype.completeState = function() { + this.context.actionHandler.addEvent({ + action : 'RefreshResult', + target : this.context.target + }); + this.alertHandler.alertHandler("success", "Assignment of object \"" + this.context.target.metadata.title + "\" as the assigned thumbnail has completed."); + this.context.target.enable(); + }; + + return AssignAsThumbnailAction; +}); \ No newline at end of file diff --git a/static/js/admin/src/action/ClearAssignedThumbnailAction.js b/static/js/admin/src/action/ClearAssignedThumbnailAction.js new file mode 100644 index 0000000000..3148585846 --- /dev/null +++ b/static/js/admin/src/action/ClearAssignedThumbnailAction.js @@ -0,0 +1,43 @@ +define('ClearAssignedThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], function($, AjaxCallbackAction) { + + function ClearAssignedThumbnailAction(context) { + this._create(context); + }; + + ClearAssignedThumbnailAction.prototype.constructor = ClearAssignedThumbnailAction; + ClearAssignedThumbnailAction.prototype = Object.create( AjaxCallbackAction.prototype ); + + ClearAssignedThumbnailAction.prototype._create = function(context) { + this.context = context; + + var options = { + workMethod: "PUT", + workPath: "/services/api/edit/deleteThumbnail/{idPath}", + workLabel: "Clearing assigned thumbnail...", + followupLabel: "Clearing assigned thumbnail...", + followupPath: "/services/api/status/item/{idPath}/solrRecord/version" + } + + if ('confirm' in this.context && !this.context.confirm) { + options.confirm = false; + } else { + options.confirm = { + promptText : "Clear the assigned thumbnail?", + confirmAnchor : this.context.confirmAnchor + }; + } + + AjaxCallbackAction.prototype._create.call(this, options); + }; + + ClearAssignedThumbnailAction.prototype.completeState = function() { + this.context.actionHandler.addEvent({ + action : 'RefreshResult', + target : this.context.target + }); + this.alertHandler.alertHandler("success", "Cleared the assigned thumbnail."); + this.context.target.enable(); + }; + + return ClearAssignedThumbnailAction; +}); \ No newline at end of file From 919167a54ebb6acd288cd8a76cfd73a879000232 Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Thu, 12 Oct 2023 16:36:27 -0400 Subject: [PATCH 02/11] BXC-4061 adding help text --- static/js/admin/src/ResultObject.js | 5 ++++- static/js/admin/src/action/AssignAsThumbnailAction.js | 2 +- static/js/admin/src/action/ClearAssignedThumbnailAction.js | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/static/js/admin/src/ResultObject.js b/static/js/admin/src/ResultObject.js index fb9414a937..fbb1d97b64 100644 --- a/static/js/admin/src/ResultObject.js +++ b/static/js/admin/src/ResultObject.js @@ -85,7 +85,7 @@ define('ResultObject', [ 'jquery', 'jquery-ui', 'underscore', 'ModalLoadingOverl case 'patron-settings': helpText = 'Patron access settings for this object have been added'; break; - case 'primary-object': + case 'is-primary-object': helpText = 'This file is the representative object for the work which contains it'; break; case 'staff-only': @@ -94,6 +94,9 @@ define('ResultObject', [ 'jquery', 'jquery-ui', 'underscore', 'ModalLoadingOverl case 'inherited-settings': helpText = 'Object is inheriting patron access settings which have been modified (typically they are more restrictive)'; break; + case 'assigned-as-thumbnail': + helpText = 'This file is the assigned thumbnail for the work which contains it'; + break; default: helpText = ''; } diff --git a/static/js/admin/src/action/AssignAsThumbnailAction.js b/static/js/admin/src/action/AssignAsThumbnailAction.js index 8ab757e626..c06775cbba 100644 --- a/static/js/admin/src/action/AssignAsThumbnailAction.js +++ b/static/js/admin/src/action/AssignAsThumbnailAction.js @@ -40,4 +40,4 @@ define('AssignAsThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], function($, }; return AssignAsThumbnailAction; -}); \ No newline at end of file +}); diff --git a/static/js/admin/src/action/ClearAssignedThumbnailAction.js b/static/js/admin/src/action/ClearAssignedThumbnailAction.js index 3148585846..fa8f650252 100644 --- a/static/js/admin/src/action/ClearAssignedThumbnailAction.js +++ b/static/js/admin/src/action/ClearAssignedThumbnailAction.js @@ -27,6 +27,7 @@ define('ClearAssignedThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], functi }; } + AjaxCallbackAction.prototype._create.call(this, options); }; From 7f96faa98d00feca382676609730b9d4e12294fb Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Mon, 16 Oct 2023 13:57:47 -0400 Subject: [PATCH 03/11] BXC-4061 fix backend of assigning thumbnail dropdown selection and clear thumbnail selection --- .../camel/thumbnails/ThumbnailRequestProcessor.java | 11 ++++++++++- .../admin/src/action/ClearAssignedThumbnailAction.js | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/services-camel-app/src/main/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailRequestProcessor.java b/services-camel-app/src/main/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailRequestProcessor.java index 100df0db0f..157915984e 100644 --- a/services-camel-app/src/main/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailRequestProcessor.java +++ b/services-camel-app/src/main/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailRequestProcessor.java @@ -3,6 +3,7 @@ import edu.unc.lib.boxc.auth.api.Permission; import edu.unc.lib.boxc.auth.api.services.AccessControlService; import edu.unc.lib.boxc.model.api.objects.RepositoryObjectLoader; +import edu.unc.lib.boxc.model.api.objects.WorkObject; import edu.unc.lib.boxc.model.api.rdf.Cdr; import edu.unc.lib.boxc.model.api.services.RepositoryObjectFactory; import edu.unc.lib.boxc.model.fcrepo.ids.PIDs; @@ -39,10 +40,16 @@ public void process(Exchange exchange) throws IOException { pid, agent.getPrincipals(), Permission.editDescription); var file = repositoryObjectLoader.getFileObject(pid); - var work = file.getParent(); + var work = (WorkObject) file.getParent(); if (Objects.equals(action, ThumbnailRequest.ASSIGN)) { repositoryObjectFactory.createExclusiveRelationship(work, Cdr.useAsThumbnail, file.getResource()); + // reindex old thumbnail object + var oldThumbnailFile = work.getThumbnailObject(); + if (oldThumbnailFile != null) { + indexingMessageSender.sendIndexingOperation( + agent.getUsername(), oldThumbnailFile.getPid(), IndexingActionType.UPDATE_DATASTREAMS); + } } else if ( Objects.equals(action, ThumbnailRequest.DELETE)) { repositoryObjectFactory.deleteProperty(work, Cdr.useAsThumbnail); } @@ -50,6 +57,8 @@ public void process(Exchange exchange) throws IOException { // send message to update solr indexingMessageSender.sendIndexingOperation( agent.getUsername(), work.getPid(), IndexingActionType.UPDATE_DATASTREAMS); + indexingMessageSender.sendIndexingOperation( + agent.getUsername(), file.getPid(), IndexingActionType.UPDATE_DATASTREAMS); } public void setRepositoryObjectLoader(RepositoryObjectLoader repositoryObjectLoader) { diff --git a/static/js/admin/src/action/ClearAssignedThumbnailAction.js b/static/js/admin/src/action/ClearAssignedThumbnailAction.js index fa8f650252..d01d45761e 100644 --- a/static/js/admin/src/action/ClearAssignedThumbnailAction.js +++ b/static/js/admin/src/action/ClearAssignedThumbnailAction.js @@ -11,7 +11,7 @@ define('ClearAssignedThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], functi this.context = context; var options = { - workMethod: "PUT", + workMethod: "DELETE", workPath: "/services/api/edit/deleteThumbnail/{idPath}", workLabel: "Clearing assigned thumbnail...", followupLabel: "Clearing assigned thumbnail...", From 0aa0f240e1196090673aeb2e8ff27b03de50210e Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Wed, 18 Oct 2023 12:23:00 -0400 Subject: [PATCH 04/11] BXC-4061 get js working --- .../src/action/AssignAsThumbnailAction.js | 11 +++++++++++ .../rest/modify/ThumbnailController.java | 19 +++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/static/js/admin/src/action/AssignAsThumbnailAction.js b/static/js/admin/src/action/AssignAsThumbnailAction.js index c06775cbba..82c328d2de 100644 --- a/static/js/admin/src/action/AssignAsThumbnailAction.js +++ b/static/js/admin/src/action/AssignAsThumbnailAction.js @@ -35,9 +35,20 @@ define('AssignAsThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], function($, action : 'RefreshResult', target : this.context.target }); + this.context.actionHandler.addEvent({ + action : 'RefreshResult', + target : this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId) + }); this.alertHandler.alertHandler("success", "Assignment of object \"" + this.context.target.metadata.title + "\" as the assigned thumbnail has completed."); this.context.target.enable(); }; + AssignAsThumbnailAction.prototype.workDone = function(data) { + this.completeTimestamp = data.timestamp; + this.oldThumbnailId = data.oldThumbnailId; + this.newThumbnailId = data.newThumbnailId; + return true; + }; + return AssignAsThumbnailAction; }); diff --git a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java index 94441bb031..aabf56082a 100644 --- a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java +++ b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java @@ -11,6 +11,7 @@ import edu.unc.lib.boxc.model.api.ids.PID; import edu.unc.lib.boxc.model.api.objects.FileObject; import edu.unc.lib.boxc.model.api.objects.RepositoryObjectLoader; +import edu.unc.lib.boxc.model.api.objects.WorkObject; import edu.unc.lib.boxc.model.fcrepo.ids.PIDs; import edu.unc.lib.boxc.operations.jms.thumbnails.ThumbnailRequest; import edu.unc.lib.boxc.operations.jms.thumbnails.ThumbnailRequestSender; @@ -100,6 +101,8 @@ ResponseEntity importThumbnail(@PathVariable("pid") String pid, @ResponseBody public ResponseEntity assignThumbnail(@PathVariable("pidString") String pidString) { PID pid = PIDs.get(pidString); + Map result = new HashMap<>(); + result.put("action", "assignThumbnail"); AccessGroupSet principals = getAgentPrincipals().getPrincipals(); aclService.assertHasAccess("Insufficient permissions to assign thumbnail for " + pidString, @@ -111,6 +114,12 @@ public ResponseEntity assignThumbnail(@PathVariable("pidString") String return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } + var workObject = (WorkObject) object.getParent(); + var oldThumbnail = workObject.getThumbnailObject(); + if (oldThumbnail != null) { + result.put("oldThumbnailId", oldThumbnail.getPid().getId()); + } + var agent = AgentPrincipalsImpl.createFromThread(); var request = new ThumbnailRequest(); request.setAgent(agent); @@ -123,13 +132,17 @@ public ResponseEntity assignThumbnail(@PathVariable("pidString") String log.error("Error assigning file {} as thumbnail", request.getFilePidString(), e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - return new ResponseEntity<>(HttpStatus.OK); + result.put("timestamp", System.currentTimeMillis()); + result.put("newThumbnailId", object.getPid().getId()); + return new ResponseEntity<>(result, HttpStatus.OK); } @DeleteMapping(value = "/edit/deleteThumbnail/{pidString}") @ResponseBody public ResponseEntity deleteThumbnail(@PathVariable("pidString") String pidString) { PID pid = PIDs.get(pidString); + Map result = new HashMap<>(); + result.put("action", "deleteThumbnail"); AccessGroupSet principals = getAgentPrincipals().getPrincipals(); aclService.assertHasAccess("Insufficient permissions to assign thumbnail for " + pidString, @@ -153,6 +166,8 @@ public ResponseEntity deleteThumbnail(@PathVariable("pidString") String return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - return new ResponseEntity<>(HttpStatus.OK); + result.put("timestamp", System.currentTimeMillis()); + result.put("oldThumbnailId", object.getPid().getId()); + return new ResponseEntity<>(result, HttpStatus.OK); } } From 55727c88e917a87a1b82f7c32cdaa8942a6850e3 Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Wed, 18 Oct 2023 16:52:54 -0400 Subject: [PATCH 05/11] BXC-4061 making sure ajax waits to update row until item is updated in solr --- static/js/admin/src/action/AssignAsThumbnailAction.js | 8 ++++++++ .../js/admin/src/action/ClearAssignedThumbnailAction.js | 7 +++++++ .../js/admin/src/action/ClearPrimaryObjectResultAction.js | 7 +++++++ .../js/admin/src/action/SetAsPrimaryObjectResultAction.js | 7 +++++++ 4 files changed, 29 insertions(+) diff --git a/static/js/admin/src/action/AssignAsThumbnailAction.js b/static/js/admin/src/action/AssignAsThumbnailAction.js index 82c328d2de..4cfa07ff06 100644 --- a/static/js/admin/src/action/AssignAsThumbnailAction.js +++ b/static/js/admin/src/action/AssignAsThumbnailAction.js @@ -50,5 +50,13 @@ define('AssignAsThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], function($, return true; }; + AssignAsThumbnailAction.prototype.followup = function(data) { + if (data) { + return this.context.target.updateVersion(data) && + this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).updateVersion(data); + } + return false; + }; + return AssignAsThumbnailAction; }); diff --git a/static/js/admin/src/action/ClearAssignedThumbnailAction.js b/static/js/admin/src/action/ClearAssignedThumbnailAction.js index d01d45761e..2fe727077f 100644 --- a/static/js/admin/src/action/ClearAssignedThumbnailAction.js +++ b/static/js/admin/src/action/ClearAssignedThumbnailAction.js @@ -40,5 +40,12 @@ define('ClearAssignedThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], functi this.context.target.enable(); }; + ClearAssignedThumbnailAction.prototype.followup = function(data) { + if (data) { + return this.context.target.updateVersion(data); + } + return false; + }; + return ClearAssignedThumbnailAction; }); \ No newline at end of file diff --git a/static/js/admin/src/action/ClearPrimaryObjectResultAction.js b/static/js/admin/src/action/ClearPrimaryObjectResultAction.js index 8fe6e21c1d..8284eaceb9 100644 --- a/static/js/admin/src/action/ClearPrimaryObjectResultAction.js +++ b/static/js/admin/src/action/ClearPrimaryObjectResultAction.js @@ -38,6 +38,13 @@ define('ClearPrimaryObjectResultAction', [ 'jquery', 'AjaxCallbackAction'], func this.alertHandler.alertHandler("success", "Cleared the primary object assignment."); this.context.target.enable(); }; + + ClearPrimaryObjectResultAction.prototype.followup = function(data) { + if (data) { + return this.context.target.updateVersion(data); + } + return false; + }; return ClearPrimaryObjectResultAction; }); \ No newline at end of file diff --git a/static/js/admin/src/action/SetAsPrimaryObjectResultAction.js b/static/js/admin/src/action/SetAsPrimaryObjectResultAction.js index 37ab7064d5..513a3745f6 100644 --- a/static/js/admin/src/action/SetAsPrimaryObjectResultAction.js +++ b/static/js/admin/src/action/SetAsPrimaryObjectResultAction.js @@ -38,6 +38,13 @@ define('SetAsPrimaryObjectResultAction', [ 'jquery', 'AjaxCallbackAction'], func this.alertHandler.alertHandler("success", "Assignment of object \"" + this.context.target.metadata.title + "\" as primary object has completed."); this.context.target.enable(); }; + + SetAsPrimaryObjectResultAction.prototype.followup = function(data) { + if (data) { + return this.context.target.updateVersion(data); + } + return false; + }; return SetAsPrimaryObjectResultAction; }); \ No newline at end of file From d360af5ce6dc75dbf66ba827fccf0a73af0cf234 Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Thu, 19 Oct 2023 16:57:22 -0400 Subject: [PATCH 06/11] BXC-4061 this isn't quite working right yet but close --- static/js/admin/src/ResultObjectActionMenu.js | 3 + .../action/ClearAssignedThumbnailAction.js | 59 ++++++++++++++++++- .../rest/modify/ThumbnailController.java | 15 +++-- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/static/js/admin/src/ResultObjectActionMenu.js b/static/js/admin/src/ResultObjectActionMenu.js index c5ad4021bf..3befc524d6 100644 --- a/static/js/admin/src/ResultObjectActionMenu.js +++ b/static/js/admin/src/ResultObjectActionMenu.js @@ -160,6 +160,9 @@ define('ResultObjectActionMenu', [ 'jquery', 'jquery-ui', 'StringUtilities', 'A if ($.inArray('Has Primary Object', metadata.contentStatus) != -1) { items['clearPrimaryObject'] = { name : 'Clear Primary Object' }; } + if ($.inArray('Has Assigned Thumbnail', metadata.contentStatus) != -1) { + items['clearAssignedThumbnail'] = { name : 'Clear Assigned Thumbnail' }; + } } } diff --git a/static/js/admin/src/action/ClearAssignedThumbnailAction.js b/static/js/admin/src/action/ClearAssignedThumbnailAction.js index 2fe727077f..9eb62188ec 100644 --- a/static/js/admin/src/action/ClearAssignedThumbnailAction.js +++ b/static/js/admin/src/action/ClearAssignedThumbnailAction.js @@ -31,18 +31,73 @@ define('ClearAssignedThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], functi AjaxCallbackAction.prototype._create.call(this, options); }; + ClearAssignedThumbnailAction.prototype.performWork = function(workMethod, workData) { + this.workState(); + var op = this; + + $.ajax({ + type: workMethod, + url: this.workURL, + dataType: "json", + data: workData + }).done(function(data) { + this.oldThumbnailId = data.oldThumbnailId; + if (op.options.followup) { + try { + var workSuccessful = op.workDone(data); + + if (!workSuccessful) + throw "Operation was unsuccessful"; + } catch (e) { + op.alertHandler.alertHandler('error', e.message); + if (typeof console == "object") + console.error(e.message, e.error); + if (op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId)) + op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).setState("failed"); + return; + } + if (op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId)) + op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).setState("followup"); + op.followupMonitor.performPing(); + } else { + if (op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId)) + op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).setState("idle"); + op.complete(data); + } + + // Trigger unchecking all checked objects when action completes + $(".select_all").trigger('click', function(){ + var resultObjects = op.resultObjectList.resultObjects; + for (var index in resultObjects) { + resultObjects[index]["unselect"](); + } + op.selectionUpdated(); + }).children("input").prop("checked", false); + + }).fail(function(data, error) { + op.alertHandler.alertHandler('error', data.responseText + ", " + error); + console.error(data.responseText, error); + }); + }; + ClearAssignedThumbnailAction.prototype.completeState = function() { this.context.actionHandler.addEvent({ action : 'RefreshResult', - target : this.context.target + target : this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId) }); this.alertHandler.alertHandler("success", "Cleared the assigned thumbnail."); this.context.target.enable(); }; + ClearAssignedThumbnailAction.prototype.workDone = function(data) { + this.completeTimestamp = data.timestamp; + this.oldThumbnailId = data.oldThumbnailId; + return true; + }; + ClearAssignedThumbnailAction.prototype.followup = function(data) { if (data) { - return this.context.target.updateVersion(data); + return this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).updateVersion(data); } return false; }; diff --git a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java index aabf56082a..6acdb54883 100644 --- a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java +++ b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java @@ -149,16 +149,24 @@ public ResponseEntity deleteThumbnail(@PathVariable("pidString") String pid, principals, Permission.editDescription); var object = repositoryObjectLoader.getRepositoryObject(pid); - if (!(object instanceof FileObject)) { - log.error("Error object is not a file: {}", pidString); + if (!(object instanceof FileObject) && !(object instanceof WorkObject)) { + log.error("Error object is not a file or work: {}", pidString); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } var agent = AgentPrincipalsImpl.createFromThread(); var request = new ThumbnailRequest(); request.setAgent(agent); - request.setFilePidString(pidString); request.setAction(ThumbnailRequest.DELETE); + if (object instanceof WorkObject) { + var fileId = ((WorkObject) object).getThumbnailObject().getPid().getId(); + request.setFilePidString(fileId); + result.put("oldThumbnailId", fileId); + } else { + request.setFilePidString(pidString); + result.put("oldThumbnailId", object.getPid().getId()); + } + try { thumbnailRequestSender.sendToQueue(request); } catch (IOException e) { @@ -167,7 +175,6 @@ public ResponseEntity deleteThumbnail(@PathVariable("pidString") String } result.put("timestamp", System.currentTimeMillis()); - result.put("oldThumbnailId", object.getPid().getId()); return new ResponseEntity<>(result, HttpStatus.OK); } } From cbbb2dfee911ddd57313e96ae8358696429e9d53 Mon Sep 17 00:00:00 2001 From: Ben Pennell Date: Fri, 20 Oct 2023 16:26:50 -0400 Subject: [PATCH 07/11] Retrieve old thumbnail id before clearing the property, otherwise we generally won't get an id back. Adjust when refreshes happen --- .../thumbnails/ThumbnailRequestProcessor.java | 3 +- .../src/action/AssignAsThumbnailAction.js | 14 ++-- .../action/ClearAssignedThumbnailAction.js | 64 ++++--------------- 3 files changed, 22 insertions(+), 59 deletions(-) diff --git a/services-camel-app/src/main/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailRequestProcessor.java b/services-camel-app/src/main/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailRequestProcessor.java index 157915984e..98d28c3006 100644 --- a/services-camel-app/src/main/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailRequestProcessor.java +++ b/services-camel-app/src/main/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailRequestProcessor.java @@ -43,9 +43,10 @@ public void process(Exchange exchange) throws IOException { var work = (WorkObject) file.getParent(); if (Objects.equals(action, ThumbnailRequest.ASSIGN)) { + // Capture the old thumbnail id before it gets cleared + var oldThumbnailFile = work.getThumbnailObject(); repositoryObjectFactory.createExclusiveRelationship(work, Cdr.useAsThumbnail, file.getResource()); // reindex old thumbnail object - var oldThumbnailFile = work.getThumbnailObject(); if (oldThumbnailFile != null) { indexingMessageSender.sendIndexingOperation( agent.getUsername(), oldThumbnailFile.getPid(), IndexingActionType.UPDATE_DATASTREAMS); diff --git a/static/js/admin/src/action/AssignAsThumbnailAction.js b/static/js/admin/src/action/AssignAsThumbnailAction.js index 4cfa07ff06..f19b47d493 100644 --- a/static/js/admin/src/action/AssignAsThumbnailAction.js +++ b/static/js/admin/src/action/AssignAsThumbnailAction.js @@ -35,10 +35,6 @@ define('AssignAsThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], function($, action : 'RefreshResult', target : this.context.target }); - this.context.actionHandler.addEvent({ - action : 'RefreshResult', - target : this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId) - }); this.alertHandler.alertHandler("success", "Assignment of object \"" + this.context.target.metadata.title + "\" as the assigned thumbnail has completed."); this.context.target.enable(); }; @@ -47,13 +43,19 @@ define('AssignAsThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], function($, this.completeTimestamp = data.timestamp; this.oldThumbnailId = data.oldThumbnailId; this.newThumbnailId = data.newThumbnailId; + if (this.oldThumbnailId) { + this.context.actionHandler.addEvent({ + action : 'RefreshResult', + target : this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId), + waitForUpdate : true + }); + } return true; }; AssignAsThumbnailAction.prototype.followup = function(data) { if (data) { - return this.context.target.updateVersion(data) && - this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).updateVersion(data); + return this.context.target.updateVersion(data); } return false; }; diff --git a/static/js/admin/src/action/ClearAssignedThumbnailAction.js b/static/js/admin/src/action/ClearAssignedThumbnailAction.js index 9eb62188ec..6330487248 100644 --- a/static/js/admin/src/action/ClearAssignedThumbnailAction.js +++ b/static/js/admin/src/action/ClearAssignedThumbnailAction.js @@ -27,63 +27,13 @@ define('ClearAssignedThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], functi }; } - AjaxCallbackAction.prototype._create.call(this, options); }; - ClearAssignedThumbnailAction.prototype.performWork = function(workMethod, workData) { - this.workState(); - var op = this; - - $.ajax({ - type: workMethod, - url: this.workURL, - dataType: "json", - data: workData - }).done(function(data) { - this.oldThumbnailId = data.oldThumbnailId; - if (op.options.followup) { - try { - var workSuccessful = op.workDone(data); - - if (!workSuccessful) - throw "Operation was unsuccessful"; - } catch (e) { - op.alertHandler.alertHandler('error', e.message); - if (typeof console == "object") - console.error(e.message, e.error); - if (op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId)) - op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).setState("failed"); - return; - } - if (op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId)) - op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).setState("followup"); - op.followupMonitor.performPing(); - } else { - if (op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId)) - op.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).setState("idle"); - op.complete(data); - } - - // Trigger unchecking all checked objects when action completes - $(".select_all").trigger('click', function(){ - var resultObjects = op.resultObjectList.resultObjects; - for (var index in resultObjects) { - resultObjects[index]["unselect"](); - } - op.selectionUpdated(); - }).children("input").prop("checked", false); - - }).fail(function(data, error) { - op.alertHandler.alertHandler('error', data.responseText + ", " + error); - console.error(data.responseText, error); - }); - }; - ClearAssignedThumbnailAction.prototype.completeState = function() { this.context.actionHandler.addEvent({ action : 'RefreshResult', - target : this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId) + target : this.context.target }); this.alertHandler.alertHandler("success", "Cleared the assigned thumbnail."); this.context.target.enable(); @@ -92,12 +42,22 @@ define('ClearAssignedThumbnailAction', [ 'jquery', 'AjaxCallbackAction'], functi ClearAssignedThumbnailAction.prototype.workDone = function(data) { this.completeTimestamp = data.timestamp; this.oldThumbnailId = data.oldThumbnailId; + if (this.context.target.metadata.type == "Work") { + var oldThumbnail = this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId); + if (oldThumbnail != null) { + this.context.actionHandler.addEvent({ + action : 'RefreshResult', + target : oldThumbnail, + waitForUpdate : true + }); + } + } return true; }; ClearAssignedThumbnailAction.prototype.followup = function(data) { if (data) { - return this.context.resultTable.resultObjectList.getResultObject(this.oldThumbnailId).updateVersion(data); + return this.context.target.updateVersion(data); } return false; }; From 1938c72fcb0797d59232e73f3a4be3b489e6657f Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Tue, 24 Oct 2023 12:15:00 -0400 Subject: [PATCH 08/11] BXC-4061 make sure no assigned thumbnail tag is hidden in frontend --- static/js/admin/src/ResultObject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/admin/src/ResultObject.js b/static/js/admin/src/ResultObject.js index fbb1d97b64..f7bc8b70f3 100644 --- a/static/js/admin/src/ResultObject.js +++ b/static/js/admin/src/ResultObject.js @@ -31,7 +31,7 @@ define('ResultObject', [ 'jquery', 'jquery-ui', 'underscore', 'ModalLoadingOverl if (tags.length > 0) { this.metadata.tags = tags.filter(function(d) { - return !/^(has|not|no.primary|public.access|members.are.unordered)/i.test(d); + return !/^(has|not|no.primary|public.access|members.are.unordered|no.assigned.thumbnail)/i.test(d); }).map(function(d) { var tagValue; From c183564860e248158960e00f1c93ad8d956cbc74 Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Tue, 24 Oct 2023 13:37:54 -0400 Subject: [PATCH 09/11] BXC-4061 fix codeclimate and update tests --- .../rest/modify/ThumbnailController.java | 14 ++++++----- .../web/services/rest/modify/ThumbnailIT.java | 25 ++++++++++++++++++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java index 6acdb54883..15c5df0fb5 100644 --- a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java +++ b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java @@ -47,6 +47,8 @@ @Controller public class ThumbnailController { private static final Logger log = LoggerFactory.getLogger(ThumbnailController.class); + private static final String OLD_THUMBNAIL_ID = "oldThumbnailId"; + private static final String ACTION = "action"; @Autowired private ImportThumbnailService service; @@ -72,7 +74,7 @@ ResponseEntity importThumbnail(@PathVariable("pid") String pid, String mimeType = thumbnailFile.getContentType(); Map result = new HashMap<>(); - result.put("action", "editThumbnail"); + result.put(ACTION, "editThumbnail"); result.put("username", agent.getUsername()); try (InputStream importStream = thumbnailFile.getInputStream()) { @@ -102,7 +104,7 @@ ResponseEntity importThumbnail(@PathVariable("pid") String pid, public ResponseEntity assignThumbnail(@PathVariable("pidString") String pidString) { PID pid = PIDs.get(pidString); Map result = new HashMap<>(); - result.put("action", "assignThumbnail"); + result.put(ACTION, "assignThumbnail"); AccessGroupSet principals = getAgentPrincipals().getPrincipals(); aclService.assertHasAccess("Insufficient permissions to assign thumbnail for " + pidString, @@ -117,7 +119,7 @@ public ResponseEntity assignThumbnail(@PathVariable("pidString") String var workObject = (WorkObject) object.getParent(); var oldThumbnail = workObject.getThumbnailObject(); if (oldThumbnail != null) { - result.put("oldThumbnailId", oldThumbnail.getPid().getId()); + result.put(OLD_THUMBNAIL_ID, oldThumbnail.getPid().getId()); } var agent = AgentPrincipalsImpl.createFromThread(); @@ -142,7 +144,7 @@ public ResponseEntity assignThumbnail(@PathVariable("pidString") String public ResponseEntity deleteThumbnail(@PathVariable("pidString") String pidString) { PID pid = PIDs.get(pidString); Map result = new HashMap<>(); - result.put("action", "deleteThumbnail"); + result.put(ACTION, "deleteThumbnail"); AccessGroupSet principals = getAgentPrincipals().getPrincipals(); aclService.assertHasAccess("Insufficient permissions to assign thumbnail for " + pidString, @@ -161,10 +163,10 @@ public ResponseEntity deleteThumbnail(@PathVariable("pidString") String if (object instanceof WorkObject) { var fileId = ((WorkObject) object).getThumbnailObject().getPid().getId(); request.setFilePidString(fileId); - result.put("oldThumbnailId", fileId); + result.put(OLD_THUMBNAIL_ID, fileId); } else { request.setFilePidString(pidString); - result.put("oldThumbnailId", object.getPid().getId()); + result.put(OLD_THUMBNAIL_ID, object.getPid().getId()); } try { diff --git a/web-services-app/src/test/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailIT.java b/web-services-app/src/test/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailIT.java index c265575a7f..0674f7481d 100644 --- a/web-services-app/src/test/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailIT.java +++ b/web-services-app/src/test/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailIT.java @@ -23,6 +23,7 @@ import java.nio.file.Path; import edu.unc.lib.boxc.model.api.objects.RepositoryObjectLoader; +import edu.unc.lib.boxc.model.api.rdf.Cdr; import edu.unc.lib.boxc.operations.jms.thumbnails.ThumbnailRequest; import edu.unc.lib.boxc.operations.jms.thumbnails.ThumbnailRequestSender; import org.apache.commons.io.IOUtils; @@ -163,7 +164,9 @@ public void assignThumbnailSuccess() throws Exception { var pid = makePid(); var filePidString = pid.getId(); var file = repositoryObjectFactory.createFileObject(pid, null); + var work = repositoryObjectFactory.createWorkObject(makePid(), null); when(repositoryObjectLoader.getRepositoryObject(pid)).thenReturn(file); + work.addMember(file); mvc.perform(put("/edit/assignThumbnail/" + filePidString)) .andExpect(status().is2xxSuccessful()) @@ -240,13 +243,33 @@ public void deleteThumbnailNoAccess() throws Exception { } @Test - public void deleteThumbnailPidIsNotAFile() throws Exception { + public void deleteThumbnailPidIsAWork() throws Exception { var pid = makePid(); var workPidString = pid.getId(); var work = repositoryObjectFactory.createWorkObject(pid, null); + var filePid = makePid(); + var file = repositoryObjectFactory.createFileObject(filePid, null); + work.addMember(file); + repositoryObjectFactory.createExclusiveRelationship(work, Cdr.useAsThumbnail, file.getResource()); when(repositoryObjectLoader.getRepositoryObject(pid)).thenReturn(work); mvc.perform(delete("/edit/deleteThumbnail/" + workPidString)) + .andExpect(status().is2xxSuccessful()) + .andReturn(); + verify(thumbnailRequestSender).sendToQueue(requestCaptor.capture()); + ThumbnailRequest request = requestCaptor.getValue(); + assertEquals(filePid.getId(), request.getFilePidString()); + assertEquals(ThumbnailRequest.DELETE, request.getAction()); + } + + @Test + public void deleteThumbnailPidIsNotAFileOrWork() throws Exception { + var pid = makePid(); + var folderPidString = pid.getId(); + var folder = repositoryObjectFactory.createFolderObject(pid, null); + when(repositoryObjectLoader.getRepositoryObject(pid)).thenReturn(folder); + + mvc.perform(delete("/edit/deleteThumbnail/" + folderPidString)) .andExpect(status().isBadRequest()) .andReturn(); verify(thumbnailRequestSender, never()).sendMessage(any(Document.class)); From eba9806b6d3fedc9f0b0fa8423569e138ac05be3 Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Wed, 25 Oct 2023 14:03:48 -0400 Subject: [PATCH 10/11] BXC-4061 updating tests and adding handling for delete case without assigned thumbnail --- .../thumbnails/ThumbnailProcessorTest.java | 33 ++++++++-- .../rest/modify/ThumbnailController.java | 11 +++- .../web/services/rest/modify/ThumbnailIT.java | 63 +++++++++++++++++-- 3 files changed, 95 insertions(+), 12 deletions(-) diff --git a/services-camel-app/src/test/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailProcessorTest.java b/services-camel-app/src/test/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailProcessorTest.java index 5f074584ab..62931e6f8a 100644 --- a/services-camel-app/src/test/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailProcessorTest.java +++ b/services-camel-app/src/test/java/edu/unc/lib/boxc/services/camel/thumbnails/ThumbnailProcessorTest.java @@ -87,14 +87,37 @@ void closeService() throws Exception { } @Test - public void testUpdateThumbnail() throws Exception { + public void testAssignThumbnail() throws Exception { var exchange = createRequestExchange(ThumbnailRequest.ASSIGN); processor.process(exchange); verify(repositoryObjectFactory).createExclusiveRelationship(eq(parentWork), eq(Cdr.useAsThumbnail), fileResourceCaptor.capture()); // check to see the right file was related to the work assertEquals(resource, fileResourceCaptor.getValue()); - assertIndexingMessageSent(); + assertIndexingMessageSent(workPid); + assertIndexingMessageSent(filePid); + } + + // test for when the work already has an assigned thumbnail and a new one is chosen + @Test + public void testAssignNewThumbnail() throws Exception { + // set up pre-existing assigned thumbnail + var oldThumbnailPid = ProcessorTestHelper.makePid(); + var oldThumbnailFile = mock(FileObject.class); + var oldResource = mock(Resource.class); + when(oldThumbnailFile.getResource()).thenReturn(oldResource); + when(oldThumbnailFile.getPid()).thenReturn(oldThumbnailPid); + when(parentWork.getThumbnailObject()).thenReturn(oldThumbnailFile); + + var exchange = createRequestExchange(ThumbnailRequest.ASSIGN); + + processor.process(exchange); + verify(repositoryObjectFactory).createExclusiveRelationship(eq(parentWork), eq(Cdr.useAsThumbnail), fileResourceCaptor.capture()); + // check to see the right file was related to the work + assertEquals(resource, fileResourceCaptor.getValue()); + assertIndexingMessageSent(workPid); + assertIndexingMessageSent(filePid); + assertIndexingMessageSent(oldThumbnailPid); } @Test @@ -114,11 +137,11 @@ public void testDeleteAssignedThumbnail() throws IOException { processor.process(exchange); verify(repositoryObjectFactory).deleteProperty(eq(parentWork), eq(Cdr.useAsThumbnail)); - assertIndexingMessageSent(); + assertIndexingMessageSent(workPid); } - private void assertIndexingMessageSent() { - verify(indexingMessageSender).sendIndexingOperation(agent.getUsername(), workPid, + private void assertIndexingMessageSent(PID pid) { + verify(indexingMessageSender).sendIndexingOperation(agent.getUsername(), pid, IndexingActionType.UPDATE_DATASTREAMS); } diff --git a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java index 15c5df0fb5..c9258340aa 100644 --- a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java +++ b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java @@ -47,8 +47,8 @@ @Controller public class ThumbnailController { private static final Logger log = LoggerFactory.getLogger(ThumbnailController.class); - private static final String OLD_THUMBNAIL_ID = "oldThumbnailId"; - private static final String ACTION = "action"; + public static final String OLD_THUMBNAIL_ID = "oldThumbnailId"; + public static final String ACTION = "action"; @Autowired private ImportThumbnailService service; @@ -156,6 +156,13 @@ public ResponseEntity deleteThumbnail(@PathVariable("pidString") String return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } + if (object instanceof WorkObject) { + if (((WorkObject) object).getThumbnailObject() == null) { + log.error("Error work object does not have assigned thumbnail to delete: {}", pidString); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } + var agent = AgentPrincipalsImpl.createFromThread(); var request = new ThumbnailRequest(); request.setAgent(agent); diff --git a/web-services-app/src/test/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailIT.java b/web-services-app/src/test/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailIT.java index 0674f7481d..4a5e68eda5 100644 --- a/web-services-app/src/test/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailIT.java +++ b/web-services-app/src/test/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailIT.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.FileInputStream; import java.nio.file.Path; +import java.util.Map; import edu.unc.lib.boxc.model.api.objects.RepositoryObjectLoader; import edu.unc.lib.boxc.model.api.rdf.Cdr; @@ -40,6 +41,7 @@ import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextHierarchy; +import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import edu.unc.lib.boxc.auth.api.exceptions.AccessRestrictionException; @@ -168,13 +170,17 @@ public void assignThumbnailSuccess() throws Exception { when(repositoryObjectLoader.getRepositoryObject(pid)).thenReturn(file); work.addMember(file); - mvc.perform(put("/edit/assignThumbnail/" + filePidString)) + MvcResult result = mvc.perform(put("/edit/assignThumbnail/" + filePidString)) .andExpect(status().is2xxSuccessful()) .andReturn(); verify(thumbnailRequestSender).sendToQueue(requestCaptor.capture()); ThumbnailRequest request = requestCaptor.getValue(); assertEquals(filePidString, request.getFilePidString()); + + Map respMap = getMapFromResponse(result); + assertEquals("assignThumbnail", respMap.get(ThumbnailController.ACTION)); + assertEquals(filePidString, respMap.get("newThumbnailId")); } @Test @@ -200,13 +206,40 @@ public void assignThumbnailInvalidPidString() throws Exception { } @Test - public void assignThumbnailPidIsNotAFile() throws Exception { + public void assignThumbnailPidIsAWorkWithPreviousAssignedThumbnail() throws Exception { var pid = makePid(); var filePidString = pid.getId(); - var work = repositoryObjectFactory.createWorkObject(pid, null); + var file = repositoryObjectFactory.createFileObject(pid, null); + var oldThumbnailPid = makePid(); + var oldThumbnail = repositoryObjectFactory.createFileObject(oldThumbnailPid, null); + var workPid = makePid(); + var work = repositoryObjectFactory.createWorkObject(workPid, null); + work.addMember(file); + work.addMember(oldThumbnail); when(repositoryObjectLoader.getRepositoryObject(pid)).thenReturn(work); + repositoryObjectFactory.createExclusiveRelationship(work, Cdr.useAsThumbnail, oldThumbnail.getResource()); - mvc.perform(put("/edit/assignThumbnail/" + filePidString)) + MvcResult result = mvc.perform(put("/edit/assignThumbnail/" + filePidString)) + .andExpect(status().is2xxSuccessful()) + .andReturn(); + verify(thumbnailRequestSender).sendToQueue(requestCaptor.capture()); + ThumbnailRequest request = requestCaptor.getValue(); + assertEquals(filePidString, request.getFilePidString()); + + Map respMap = getMapFromResponse(result); + assertEquals("assignThumbnail", respMap.get(ThumbnailController.ACTION)); + assertEquals(filePidString, respMap.get("newThumbnailId")); + assertEquals(oldThumbnailPid.getId(), respMap.get(ThumbnailController.OLD_THUMBNAIL_ID)); + } + + @Test + public void assignThumbnailPidIsNotAFileOrWork() throws Exception { + var pid = makePid(); + var folderPidString = pid.getId(); + var folder = repositoryObjectFactory.createFolderObject(pid, null); + when(repositoryObjectLoader.getRepositoryObject(pid)).thenReturn(folder); + + mvc.perform(put("/edit/assignThumbnail/" + folderPidString)) .andExpect(status().isBadRequest()) .andReturn(); verify(thumbnailRequestSender, never()).sendMessage(any(Document.class)); @@ -218,7 +251,7 @@ public void deleteThumbnailSuccess() throws Exception { var filePidString = pid.getId(); var file = repositoryObjectFactory.createFileObject(pid, null); when(repositoryObjectLoader.getRepositoryObject(pid)).thenReturn(file); - mvc.perform(delete("/edit/deleteThumbnail/" + filePidString)) + MvcResult result = mvc.perform(delete("/edit/deleteThumbnail/" + filePidString)) .andExpect(status().is2xxSuccessful()) .andReturn(); @@ -226,6 +259,10 @@ public void deleteThumbnailSuccess() throws Exception { ThumbnailRequest request = requestCaptor.getValue(); assertEquals(filePidString, request.getFilePidString()); assertEquals(ThumbnailRequest.DELETE, request.getAction()); + + Map respMap = getMapFromResponse(result); + assertEquals("deleteThumbnail", respMap.get(ThumbnailController.ACTION)); + assertEquals(filePidString, respMap.get(ThumbnailController.OLD_THUMBNAIL_ID)); } @Test @@ -262,6 +299,22 @@ public void deleteThumbnailPidIsAWork() throws Exception { assertEquals(ThumbnailRequest.DELETE, request.getAction()); } + @Test + public void deleteThumbnailPidIsAWorkButNoAssignedThumbnail() throws Exception { + var pid = makePid(); + var workPidString = pid.getId(); + var work = repositoryObjectFactory.createWorkObject(pid, null); + var filePid = makePid(); + var file = repositoryObjectFactory.createFileObject(filePid, null); + work.addMember(file); + when(repositoryObjectLoader.getRepositoryObject(pid)).thenReturn(work); + + mvc.perform(delete("/edit/deleteThumbnail/" + workPidString)) + .andExpect(status().isBadRequest()) + .andReturn(); + verify(thumbnailRequestSender, never()).sendMessage(any(Document.class)); + } + @Test public void deleteThumbnailPidIsNotAFileOrWork() throws Exception { var pid = makePid(); From 623cb93a00d5c3f7f7d000724a2f1cc2a8f861ce Mon Sep 17 00:00:00 2001 From: Sharon Luong Date: Wed, 25 Oct 2023 14:15:55 -0400 Subject: [PATCH 11/11] BXC-4061 collapse nested if statement to make codeclimate happy --- .../web/services/rest/modify/ThumbnailController.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java index c9258340aa..c29024188c 100644 --- a/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java +++ b/web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/modify/ThumbnailController.java @@ -156,11 +156,9 @@ public ResponseEntity deleteThumbnail(@PathVariable("pidString") String return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - if (object instanceof WorkObject) { - if (((WorkObject) object).getThumbnailObject() == null) { - log.error("Error work object does not have assigned thumbnail to delete: {}", pidString); - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - } + if (object instanceof WorkObject && ((WorkObject) object).getThumbnailObject() == null) { + log.error("Error work object does not have assigned thumbnail to delete: {}", pidString); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } var agent = AgentPrincipalsImpl.createFromThread();