Skip to content

Commit

Permalink
Bxc 4061 assigned thumbnail UI (#1616)
Browse files Browse the repository at this point in the history
* BXC-4061 updating facet constants and adding handling for events

* BXC-4061 adding help text

* BXC-4061 fix backend of assigning thumbnail dropdown selection and clear thumbnail selection

* BXC-4061 get js working

* BXC-4061 making sure ajax waits to update row until item is updated in solr

* BXC-4061 this isn't quite working right yet but close

* Retrieve old thumbnail id before clearing the property, otherwise we generally won't get an id back. Adjust when refreshes happen

* BXC-4061 make sure no assigned thumbnail tag is hidden in frontend

* BXC-4061 fix codeclimate and update tests

* BXC-4061 updating tests and adding handling for delete case without assigned thumbnail

* BXC-4061 collapse nested if statement to make codeclimate happy

---------

Co-authored-by: Sharon Luong <[email protected]>
Co-authored-by: Ben Pennell <[email protected]>
  • Loading branch information
3 people authored Oct 25, 2023
1 parent 896fceb commit 13949d4
Show file tree
Hide file tree
Showing 13 changed files with 333 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ private List<String> 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);
}
}

Expand All @@ -75,7 +75,7 @@ private void addWorkObjectStatuses(List<String> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand All @@ -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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -39,17 +40,26 @@ 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)) {
// Capture the old thumbnail id before it gets cleared
var oldThumbnailFile = work.getThumbnailObject();
repositoryObjectFactory.createExclusiveRelationship(work, Cdr.useAsThumbnail, file.getResource());
// reindex old thumbnail object
if (oldThumbnailFile != null) {
indexingMessageSender.sendIndexingOperation(
agent.getUsername(), oldThumbnailFile.getPid(), IndexingActionType.UPDATE_DATASTREAMS);
}
} else if ( Objects.equals(action, ThumbnailRequest.DELETE)) {
repositoryObjectFactory.deleteProperty(work, Cdr.useAsThumbnail);
}

// 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

Expand Down
7 changes: 5 additions & 2 deletions static/js/admin/src/ResultObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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':
Expand All @@ -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 = '';
}
Expand Down
22 changes: 22 additions & 0 deletions static/js/admin/src/ResultObjectActionMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,18 @@ 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' };
}
if ($.inArray('Has Assigned Thumbnail', metadata.contentStatus) != -1) {
items['clearAssignedThumbnail'] = { name : 'Clear Assigned Thumbnail' };
}
}
}

Expand Down Expand Up @@ -363,6 +371,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',
Expand Down
64 changes: 64 additions & 0 deletions static/js/admin/src/action/AssignAsThumbnailAction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
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();
};

AssignAsThumbnailAction.prototype.workDone = function(data) {
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);
}
return false;
};

return AssignAsThumbnailAction;
});
66 changes: 66 additions & 0 deletions static/js/admin/src/action/ClearAssignedThumbnailAction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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: "DELETE",
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();
};

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.target.updateVersion(data);
}
return false;
};

return ClearAssignedThumbnailAction;
});
7 changes: 7 additions & 0 deletions static/js/admin/src/action/ClearPrimaryObjectResultAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
7 changes: 7 additions & 0 deletions static/js/admin/src/action/SetAsPrimaryObjectResultAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Loading

0 comments on commit 13949d4

Please sign in to comment.