/** * Commit the contained item to the main archive. The item is associated with the relevant * collection, added to the search index, and any other tasks such as assigning dates are * performed. * * @return the fully archived item. */ @Override public Item archive(Context context, BasicWorkflowItem workflowItem) throws SQLException, IOException, AuthorizeException { // FIXME: Check auth Item item = workflowItem.getItem(); Collection collection = workflowItem.getCollection(); log.info( LogManager.getHeader( context, "archive_item", "workflow_item_id=" + workflowItem.getID() + "item_id=" + item.getID() + "collection_id=" + collection.getID())); installItemService.installItem(context, workflowItem); // Log the event log.info( LogManager.getHeader( context, "install_item", "workflow_id=" + workflowItem.getID() + ", item_id=" + item.getID() + "handle=FIXME")); return item; }
/** * Return the workflow item to the workspace of the submitter. The workflow item is removed, and a * workspace item created. * * @param c Context * @param wfi WorkflowItem to be 'dismantled' * @return the workspace item */ protected WorkspaceItem returnToWorkspace(Context c, BasicWorkflowItem wfi) throws SQLException, IOException, AuthorizeException { // FIXME: How should this interact with the workflow system? // FIXME: Remove license // FIXME: Provenance statement? // Create the new workspace item row WorkspaceItem workspaceItem = workspaceItemService.create(c, wfi); workspaceItem.setMultipleFiles(wfi.hasMultipleFiles()); workspaceItem.setMultipleTitles(wfi.hasMultipleTitles()); workspaceItem.setPublishedBefore(wfi.isPublishedBefore()); workspaceItemService.update(c, workspaceItem); // myitem.update(); log.info( LogManager.getHeader( c, "return_to_workspace", "workflow_item_id=" + wfi.getID() + "workspace_item_id=" + workspaceItem.getID())); // Now remove the workflow object manually from the database workflowItemService.deleteWrapper(c, wfi); return workspaceItem; }
@Override public WorkspaceItem abort(Context context, BasicWorkflowItem workflowItem, EPerson e) throws SQLException, AuthorizeException, IOException { // authorize a DSpaceActions.ABORT if (!authorizeService.isAdmin(context)) { throw new AuthorizeException("You must be an admin to abort a workflow"); } // stop workflow regardless of its state taskListItemService.deleteByWorkflowItem(context, workflowItem); log.info( LogManager.getHeader( context, "abort_workflow", "workflow_item_id=" + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() + "collection_id=" + workflowItem.getCollection().getID() + "eperson_id=" + e.getID())); // convert into personal workspace return returnToWorkspace(context, workflowItem); }
protected void notifyOfReject( Context context, BasicWorkflowItem workflowItem, EPerson e, String reason) { try { // Get the item title String title = getItemTitle(workflowItem); // Get the collection Collection coll = workflowItem.getCollection(); // Get rejector's name String rejector = getEPersonName(e); Locale supportedLocale = I18nUtil.getEPersonLocale(e); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "submit_reject")); email.addRecipient(workflowItem.getSubmitter().getEmail()); email.addArgument(title); email.addArgument(coll.getName()); email.addArgument(rejector); email.addArgument(reason); email.addArgument(getMyDSpaceLink()); email.send(); } catch (RuntimeException re) { // log this email error log.warn( LogManager.getHeader( context, "notify_of_reject", "cannot email user eperson_id=" + e.getID() + " eperson_email=" + e.getEmail() + " workflow_item_id=" + workflowItem.getID() + ": " + re.getMessage())); throw re; } catch (Exception ex) { // log this email error log.warn( LogManager.getHeader( context, "notify_of_reject", "cannot email user eperson_id=" + e.getID() + " eperson_email=" + e.getEmail() + " workflow_item_id=" + workflowItem.getID() + ": " + ex.getMessage())); } }
// Record approval provenance statement protected void recordApproval(Context context, BasicWorkflowItem workflowItem, EPerson e) throws SQLException, IOException, AuthorizeException { Item item = workflowItem.getItem(); // Get user's name + email address String usersName = getEPersonName(e); // Get current date String now = DCDate.getCurrent().toString(); // Here's what happened String provDescription = "Approved for entry into archive by " + usersName + " on " + now + " (GMT) "; // add bitstream descriptions (name, size, checksums) provDescription += installItemService.getBitstreamProvenanceMessage(context, item); // Add to item as a DC field itemService.addMetadata( context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); itemService.update(context, item); }
@Override public void unclaim(Context context, BasicWorkflowItem workflowItem, EPerson e) throws SQLException, IOException, AuthorizeException { int taskstate = workflowItem.getState(); switch (taskstate) { case WFSTATE_STEP1: // authorize DSpaceActions.STEP1 doState(context, workflowItem, WFSTATE_STEP1POOL, e); break; case WFSTATE_STEP2: // authorize DSpaceActions.APPROVE doState(context, workflowItem, WFSTATE_STEP2POOL, e); break; case WFSTATE_STEP3: // authorize DSpaceActions.STEP3 doState(context, workflowItem, WFSTATE_STEP3POOL, e); break; // error handling? shouldn't get here // FIXME - what to do with error - log it? } log.info( LogManager.getHeader( context, "unclaim_workflow", "workflow_item_id=" + workflowItem.getID() + ",item_id=" + workflowItem.getItem().getID() + ",collection_id=" + workflowItem.getCollection().getID() + ",old_state=" + taskstate + ",new_state=" + workflowItem.getState())); }
@Override public String getItemTitle(BasicWorkflowItem wi) throws SQLException { Item myitem = wi.getItem(); String title = myitem.getName(); // only return the first element, or "Untitled" if (StringUtils.isNotBlank(title)) { return title; } else { return I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled "); } }
// send notices of curation activity @Override public void notifyOfCuration( Context c, BasicWorkflowItem wi, List<EPerson> ePeople, String taskName, String action, String message) throws SQLException, IOException { try { // Get the item title String title = getItemTitle(wi); // Get the submitter's name String submitter = getSubmitterName(wi); // Get the collection Collection coll = wi.getCollection(); for (EPerson epa : ePeople) { Locale supportedLocale = I18nUtil.getEPersonLocale(epa); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "flowtask_notify")); email.addArgument(title); email.addArgument(coll.getName()); email.addArgument(submitter); email.addArgument(taskName); email.addArgument(message); email.addArgument(action); email.addRecipient(epa.getEmail()); email.send(); } } catch (MessagingException e) { log.warn( LogManager.getHeader( c, "notifyOfCuration", "cannot email users of workflow_item_id " + wi.getID() + ": " + e.getMessage())); } }
@Override public BasicWorkflowItem start(Context context, WorkspaceItem wsi) throws SQLException, AuthorizeException, IOException { // FIXME Check auth Item myitem = wsi.getItem(); Collection collection = wsi.getCollection(); log.info( LogManager.getHeader( context, "start_workflow", "workspace_item_id=" + wsi.getID() + "item_id=" + myitem.getID() + "collection_id=" + collection.getID())); // record the start of the workflow w/provenance message recordStart(context, myitem); // create the WorkflowItem BasicWorkflowItem wfi = workflowItemService.create(context, myitem, collection); wfi.setMultipleFiles(wsi.hasMultipleFiles()); wfi.setMultipleTitles(wsi.hasMultipleTitles()); wfi.setPublishedBefore(wsi.isPublishedBefore()); // remove the WorkspaceItem workspaceItemService.deleteWrapper(context, wsi); // now get the workflow started wfi.setState(WFSTATE_SUBMIT); advance(context, wfi, null); // Return the workflow item return wfi; }
@Override public void claim(Context context, BasicWorkflowItem workflowItem, EPerson e) throws SQLException, IOException, AuthorizeException { int taskstate = workflowItem.getState(); switch (taskstate) { case WFSTATE_STEP1POOL: // authorize DSpaceActions.SUBMIT_REVIEW doState(context, workflowItem, WFSTATE_STEP1, e); break; case WFSTATE_STEP2POOL: // authorize DSpaceActions.SUBMIT_STEP2 doState(context, workflowItem, WFSTATE_STEP2, e); break; case WFSTATE_STEP3POOL: // authorize DSpaceActions.SUBMIT_STEP3 doState(context, workflowItem, WFSTATE_STEP3, e); break; // if we got here, we weren't pooled... error? // FIXME - log the error? } log.info( LogManager.getHeader( context, "claim_task", "workflow_item_id=" + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() + "collection_id=" + workflowItem.getCollection().getID() + "newowner_id=" + workflowItem.getOwner().getID() + "old_state=" + taskstate + "new_state=" + workflowItem.getState())); }
protected void notifyGroupOfTask( Context c, BasicWorkflowItem wi, Group mygroup, List<EPerson> epa) throws SQLException, IOException { // check to see if notification is turned off // and only do it once - delete key after notification has // been suppressed for the first time UUID myID = wi.getItem().getID(); if (noEMail.containsKey(myID)) { // suppress email, and delete key noEMail.remove(myID); } else { try { // Get the item title String title = getItemTitle(wi); // Get the submitter's name String submitter = getSubmitterName(wi); // Get the collection Collection coll = wi.getCollection(); String message = ""; for (EPerson anEpa : epa) { Locale supportedLocale = I18nUtil.getEPersonLocale(anEpa); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "submit_task")); email.addArgument(title); email.addArgument(coll.getName()); email.addArgument(submitter); ResourceBundle messages = ResourceBundle.getBundle("Messages", supportedLocale); switch (wi.getState()) { case WFSTATE_STEP1POOL: message = messages.getString("org.dspace.workflow.WorkflowManager.step1"); break; case WFSTATE_STEP2POOL: message = messages.getString("org.dspace.workflow.WorkflowManager.step2"); break; case WFSTATE_STEP3POOL: message = messages.getString("org.dspace.workflow.WorkflowManager.step3"); break; } email.addArgument(message); email.addArgument(getMyDSpaceLink()); email.addRecipient(anEpa.getEmail()); email.send(); } } catch (MessagingException e) { String gid = (mygroup != null) ? String.valueOf(mygroup.getID()) : "none"; log.warn( LogManager.getHeader( c, "notifyGroupofTask", "cannot email user group_id=" + gid + " workflow_item_id=" + wi.getID() + ": " + e.getMessage())); } } }
@Override public WorkspaceItem sendWorkflowItemBackSubmission( Context context, BasicWorkflowItem workflowItem, EPerson ePerson, String provenancePrefix, String rejection_message) throws SQLException, AuthorizeException, IOException { int oldState = workflowItem.getState(); // authorize a DSpaceActions.REJECT // stop workflow taskListItemService.deleteByWorkflowItem(context, workflowItem); // rejection provenance Item myitem = workflowItem.getItem(); // Get current date String now = DCDate.getCurrent().toString(); // Get user's name + email address String usersName = getEPersonName(ePerson); // Here's what happened String provDescription = "Rejected by " + usersName + ", reason: " + rejection_message + " on " + now + " (GMT) "; // Add to item as a DC field itemService.addMetadata( context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); itemService.update(context, myitem); // convert into personal workspace WorkspaceItem wsi = returnToWorkspace(context, workflowItem); // notify that it's been rejected notifyOfReject(context, workflowItem, ePerson, rejection_message); log.info( LogManager.getHeader( context, "reject_workflow", "workflow_item_id=" + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() + "collection_id=" + workflowItem.getCollection().getID() + "eperson_id=" + ePerson.getID())); logWorkflowEvent( context, wsi.getItem(), workflowItem, ePerson, WFSTATE_SUBMIT, null, wsi.getCollection(), oldState, null); return wsi; }
// returns true if archived protected boolean doState( Context context, BasicWorkflowItem workflowItem, int newstate, EPerson newowner) throws SQLException, IOException, AuthorizeException { Collection mycollection = workflowItem.getCollection(); Group mygroup = null; boolean archived = false; // Gather our old data for launching the workflow event int oldState = workflowItem.getState(); workflowItem.setState(newstate); switch (newstate) { case WFSTATE_STEP1POOL: // any reviewers? // if so, add them to the tasklist workflowItem.setOwner(null); // get reviewers (group 1 ) mygroup = collectionService.getWorkflowGroup(mycollection, 1); if ((mygroup != null) && !(groupService.isEmpty(mygroup))) { // get a list of all epeople in group (or any subgroups) List<EPerson> epa = groupService.allMembers(context, mygroup); // there were reviewers, change the state // and add them to the list createTasks(context, workflowItem, epa); workflowItemService.update(context, workflowItem); // email notification notifyGroupOfTask(context, workflowItem, mygroup, epa); } else { // no reviewers, skip ahead workflowItem.setState(WFSTATE_STEP1); archived = advance(context, workflowItem, null, true, false); } break; case WFSTATE_STEP1: // remove reviewers from tasklist // assign owner taskListItemService.deleteByWorkflowItem(context, workflowItem); workflowItem.setOwner(newowner); break; case WFSTATE_STEP2POOL: // clear owner // any approvers? // if so, add them to tasklist // if not, skip to next state workflowItem.setOwner(null); // get approvers (group 2) mygroup = collectionService.getWorkflowGroup(mycollection, 2); if ((mygroup != null) && !(groupService.isEmpty(mygroup))) { // get a list of all epeople in group (or any subgroups) List<EPerson> epa = groupService.allMembers(context, mygroup); // there were approvers, change the state // timestamp, and add them to the list createTasks(context, workflowItem, epa); // email notification notifyGroupOfTask(context, workflowItem, mygroup, epa); } else { // no reviewers, skip ahead workflowItem.setState(WFSTATE_STEP2); archived = advance(context, workflowItem, null, true, false); } break; case WFSTATE_STEP2: // remove admins from tasklist // assign owner taskListItemService.deleteByWorkflowItem(context, workflowItem); workflowItem.setOwner(newowner); break; case WFSTATE_STEP3POOL: // any editors? // if so, add them to tasklist workflowItem.setOwner(null); mygroup = collectionService.getWorkflowGroup(mycollection, 3); if ((mygroup != null) && !(groupService.isEmpty(mygroup))) { // get a list of all epeople in group (or any subgroups) List<EPerson> epa = groupService.allMembers(context, mygroup); // there were editors, change the state // timestamp, and add them to the list createTasks(context, workflowItem, epa); // email notification notifyGroupOfTask(context, workflowItem, mygroup, epa); } else { // no editors, skip ahead workflowItem.setState(WFSTATE_STEP3); archived = advance(context, workflowItem, null, true, false); } break; case WFSTATE_STEP3: // remove editors from tasklist // assign owner taskListItemService.deleteByWorkflowItem(context, workflowItem); workflowItem.setOwner(newowner); break; case WFSTATE_ARCHIVE: // put in archive in one transaction // remove workflow tasks taskListItemService.deleteByWorkflowItem(context, workflowItem); mycollection = workflowItem.getCollection(); Item myitem = archive(context, workflowItem); // now email notification notifyOfArchive(context, myitem, mycollection); archived = true; break; } logWorkflowEvent( context, workflowItem.getItem(), workflowItem, context.getCurrentUser(), newstate, newowner, mycollection, oldState, mygroup); if (!archived) { workflowItemService.update(context, workflowItem); } return archived; }
@Override public boolean advance( Context context, BasicWorkflowItem workflowItem, EPerson e, boolean curate, boolean record) throws SQLException, IOException, AuthorizeException { int taskstate = workflowItem.getState(); boolean archived = false; // perform curation tasks if needed if (curate && workflowCuratorService.needsCuration(workflowItem)) { if (!workflowCuratorService.doCuration(context, workflowItem)) { // don't proceed - either curation tasks queued, or item rejected log.info( LogManager.getHeader( context, "advance_workflow", "workflow_item_id=" + workflowItem.getID() + ",item_id=" + workflowItem.getItem().getID() + ",collection_id=" + workflowItem.getCollection().getID() + ",old_state=" + taskstate + ",doCuration=false")); return false; } } switch (taskstate) { case WFSTATE_SUBMIT: archived = doState(context, workflowItem, WFSTATE_STEP1POOL, e); break; case WFSTATE_STEP1: // authorize DSpaceActions.SUBMIT_REVIEW // Record provenance if (record) { recordApproval(context, workflowItem, e); } archived = doState(context, workflowItem, WFSTATE_STEP2POOL, e); break; case WFSTATE_STEP2: // authorize DSpaceActions.SUBMIT_STEP2 // Record provenance if (record) { recordApproval(context, workflowItem, e); } archived = doState(context, workflowItem, WFSTATE_STEP3POOL, e); break; case WFSTATE_STEP3: // authorize DSpaceActions.SUBMIT_STEP3 // We don't record approval for editors, since they can't reject, // and thus didn't actually make a decision archived = doState(context, workflowItem, WFSTATE_ARCHIVE, e); break; // error handling? shouldn't get here } log.info( LogManager.getHeader( context, "advance_workflow", "workflow_item_id=" + workflowItem.getID() + ",item_id=" + workflowItem.getItem().getID() + ",collection_id=" + workflowItem.getCollection().getID() + ",old_state=" + taskstate + ",new_state=" + workflowItem.getState())); return archived; }
@Override public String getSubmitterName(BasicWorkflowItem wi) throws SQLException { EPerson e = wi.getSubmitter(); return getEPersonName(e); }