diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImport.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImport.java index dd774c38eb..57fa119259 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImport.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImport.java @@ -111,6 +111,8 @@ public class ItemImport private static PrintWriter mapOut = null; + private static final String ziptempdir = ConfigurationManager.getProperty("org.dspace.app.itemexport.work.dir"); + // File listing filter to look for metadata files private static FilenameFilter metadataFileFilter = new FilenameFilter() { @@ -276,7 +278,6 @@ public class ItemImport boolean zip = false; String zipfilename = ""; - String ziptempdir = ConfigurationManager.getProperty("org.dspace.app.itemexport.work.dir"); if (line.hasOption('z')) { zip = true; @@ -396,39 +397,6 @@ public class ItemImport System.exit(1); } - // does the zip file exist and can we write to the temp directory - if (zip) - { - File zipfile = new File(sourcedir); - if (!zipfile.canRead()) - { - System.out.println("Zip file '" + sourcedir + "' does not exist, or is not readable."); - System.exit(1); - } - - if (ziptempdir == null) - { - System.out.println("Unable to unzip import file as the key 'org.dspace.app.itemexport.work.dir' is not set in dspace.cfg"); - System.exit(1); - } - zipfile = new File(ziptempdir); - if (!zipfile.isDirectory()) - { - System.out.println("'" + ConfigurationManager.getProperty("org.dspace.app.itemexport.work.dir") + - "' as defined by the key 'org.dspace.app.itemexport.work.dir' in dspace.cfg " + - "is not a valid directory"); - System.exit(1); - } - File tempdir = new File(ziptempdir); - if (!tempdir.exists() && !tempdir.mkdirs()) - { - log.error("Unable to create temporary directory"); - } - sourcedir = ziptempdir + System.getProperty("file.separator") + line.getOptionValue("z"); - ziptempdir = ziptempdir + System.getProperty("file.separator") + - line.getOptionValue("z") + System.getProperty("file.separator"); - } - ItemImport myloader = new ItemImport(); // create a context @@ -515,70 +483,11 @@ public class ItemImport try { // If this is a zip archive, unzip it first - if (zip) - { - String sourceDirForZip = sourcedir; - ZipFile zf = new ZipFile(zipfilename); - ZipEntry entry; - Enumeration entries = zf.entries(); - while (entries.hasMoreElements()) - { - entry = entries.nextElement(); - if (entry.isDirectory()) - { - if (!new File(ziptempdir + entry.getName()).mkdir()) - { - log.error("Unable to create contents directory"); - } - } - else - { - System.out.println("Extracting file: " + entry.getName()); - int index = entry.getName().lastIndexOf('/'); - if (index == -1) - { - // Was it created on Windows instead? - index = entry.getName().lastIndexOf('\\'); - } - if (index > 0) - { - File dir = new File(ziptempdir + entry.getName().substring(0, index)); - if (!dir.mkdirs()) - { - log.error("Unable to create directory"); - } - - //Entries could have too many directories, and we need to adjust the sourcedir - //regex supports either windows or *nix file paths - String[] entryChunks = entry.getName().split("/|\\\\"); - if(entryChunks.length > 1) { - if(sourceDirForZip == sourcedir) { - sourceDirForZip += "/" + entryChunks[0]; - } - } - - - } - byte[] buffer = new byte[1024]; - int len; - InputStream in = zf.getInputStream(entry); - BufferedOutputStream out = new BufferedOutputStream( - new FileOutputStream(ziptempdir + entry.getName())); - while((len = in.read(buffer)) >= 0) - { - out.write(buffer, 0, len); - } - in.close(); - out.close(); - } - } - - if(sourceDirForZip != sourcedir) { - sourcedir = sourceDirForZip; - System.out.println("Set sourceDir using path inside of Zip: " + sourcedir); - } + if (zip) { + sourcedir = unzip(sourcedir, zipfilename); } + c.turnOffAuthorisationSystem(); if ("add".equals(command)) @@ -741,7 +650,7 @@ public class ItemImport } } - private void addItems(Context c, Collection[] mycollections, + public void addItems(Context c, Collection[] mycollections, String sourceDir, String mapFile, boolean template) throws Exception { Map skipItems = new HashMap(); // set of items to skip if in 'resume' @@ -2069,6 +1978,103 @@ public class ItemImport return (pathDeleted); } + public static String unzip(File zipfile) throws IOException { + log.info("ZIPFILE: " + zipfile.getAbsolutePath()); + + // 2 + // does the zip file exist and can we write to the temp directory + if (!zipfile.canRead()) + { + log.error("Zip file '" + zipfile.getAbsolutePath() + "' does not exist, or is not readable."); + } + + + File tempdir = new File(ziptempdir); + if (!tempdir.isDirectory()) + { + log.error("'" + ConfigurationManager.getProperty("org.dspace.app.itemexport.work.dir") + + "' as defined by the key 'org.dspace.app.itemexport.work.dir' in dspace.cfg " + + "is not a valid directory"); + } + + if (!tempdir.exists() && !tempdir.mkdirs()) + { + log.error("Unable to create temporary directory"); + } + String sourcedir = ziptempdir + System.getProperty("file.separator") + zipfile.getName(); + String zipDir = ziptempdir + System.getProperty("file.separator") + zipfile.getName() + System.getProperty("file.separator"); + + + // 3 + String sourceDirForZip = sourcedir; + ZipFile zf = new ZipFile(zipfile); + ZipEntry entry; + Enumeration entries = zf.entries(); + while (entries.hasMoreElements()) + { + entry = entries.nextElement(); + if (entry.isDirectory()) + { + if (!new File(zipDir + entry.getName()).mkdir()) + { + log.error("Unable to create contents directory"); + } + } + else + { + System.out.println("Extracting file: " + entry.getName()); + int index = entry.getName().lastIndexOf('/'); + if (index == -1) + { + // Was it created on Windows instead? + index = entry.getName().lastIndexOf('\\'); + } + if (index > 0) + { + File dir = new File(zipDir + entry.getName().substring(0, index)); + if (!dir.mkdirs()) + { + log.error("Unable to create directory"); + } + + //Entries could have too many directories, and we need to adjust the sourcedir + //regex supports either windows or *nix file paths + String[] entryChunks = entry.getName().split("/|\\\\"); + if(entryChunks.length > 1) { + if(sourceDirForZip == sourcedir) { + sourceDirForZip += "/" + entryChunks[0]; + } + } + + + } + byte[] buffer = new byte[1024]; + int len; + InputStream in = zf.getInputStream(entry); + BufferedOutputStream out = new BufferedOutputStream( + new FileOutputStream(zipDir + entry.getName())); + while((len = in.read(buffer)) >= 0) + { + out.write(buffer, 0, len); + } + in.close(); + out.close(); + } + } + + if(sourceDirForZip != sourcedir) { + sourcedir = sourceDirForZip; + System.out.println("Set sourceDir using path inside of Zip: " + sourcedir); + } + + return sourcedir; + } + + public static String unzip(String sourcedir, String zipfilename) throws IOException { + File zipfile = new File(sourcedir + File.separator + zipfilename); + return unzip(zipfile); + } + /** * Generate a random filename based on current time * @param hidden: add . as a prefix to make the file hidden diff --git a/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/FlowBatchImportUtils.java b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/FlowBatchImportUtils.java new file mode 100644 index 0000000000..70096d6274 --- /dev/null +++ b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/FlowBatchImportUtils.java @@ -0,0 +1,215 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.xmlui.aspect.administrative; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.SQLException; +import java.io.File; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.cocoon.environment.Request; +import org.apache.cocoon.servlet.multipart.Part; +import org.apache.cocoon.servlet.multipart.PartOnDisk; +import org.dspace.app.bulkedit.BulkEditChange; +import org.dspace.app.bulkedit.DSpaceCSV; +import org.dspace.app.bulkedit.MetadataImport; +import org.dspace.app.bulkedit.MetadataImportException; +import org.dspace.app.bulkedit.MetadataImportInvalidHeadingException; +import org.dspace.app.itemimport.ItemImport; +import org.dspace.app.itemimport.ItemImportOptions; +import org.dspace.app.xmlui.wing.Message; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Collection; +import org.dspace.core.Context; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.LogManager; +import org.dspace.eperson.EPerson; + +/** + * Utility methods to processes BatchImport actions. These methods are used + * exclusively from the administrative flow scripts. + * + * @author Peter Dietz + */ + +public class FlowBatchImportUtils { + + /** + * Language Strings + */ + private static final Message T_upload_successful = new Message("default", "xmlui.administrative.batchimport.flow.upload_successful"); + private static final Message T_upload_failed = new Message("default", "xmlui.administrative.batchimport.flow.upload_failed"); + private static final Message T_upload_badschema = new Message("default", "xmlui.administrative.batchimport.flow.upload_badschema"); + private static final Message T_upload_badelement = new Message("default", "xmlui.administrative.batchimport.flow.upload_badelement"); + private static final Message T_import_successful = new Message("default", "xmlui.administrative.batchimport.flow.import_successful"); + private static final Message T_import_failed = new Message("default", "xmlui.administrative.batchimport.flow.import_failed"); + private static final Message T_over_limit = new Message("default", "xmlui.administrative.batchimport.flow.over_limit"); + private static final Message T_no_changes = new Message("default", "xmlui.administrative.batchimport.general.no_changes"); + + // Other variables + private static final int limit = ConfigurationManager.getIntProperty("bulkedit", "gui-item-limit", 20); + private static Logger log = Logger.getLogger(FlowBatchImportUtils.class); + + public static FlowResult processBatchImport(Context context, Request request) throws SQLException, AuthorizeException, IOException, Exception { + + FlowResult result = new FlowResult(); + result.setContinue(false); + + String zipFile = (String) request.getSession().getAttribute("zip"); + log.info(zipFile); + + if (zipFile != null) { + // Commit the changes + context.commit(); + request.getSession().removeAttribute("zipFile"); + + log.debug(LogManager.getHeader(context, "batchimport", " items changed")); + + if (true) { + result.setContinue(true); + result.setOutcome(true); + result.setMessage(T_import_successful); + } else { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_no_changes); + } + } else { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_import_failed); + log.debug(LogManager.getHeader(context, "batchimport", "Changes cancelled")); + } + + return result; + } + + public static FlowResult processUploadZIP(Context context, Request request) throws SQLException, AuthorizeException, IOException, Exception { + FlowResult result = new FlowResult(); + result.setContinue(false); + + Object object = null; + + if (request.get("file") != null) { + object = request.get("file"); + } + + Part filePart = null; + File file = null; + + if (object instanceof Part) { + filePart = (Part) object; + file = ((PartOnDisk) filePart).getFile(); + } + + if (filePart != null && filePart.getSize() > 0) { + String name = filePart.getUploadName(); + + while (name.indexOf('/') > -1) { + name = name.substring(name.indexOf('/') + 1); + } + + while (name.indexOf('\\') > -1) { + name = name.substring(name.indexOf('\\') + 1); + } + + + log.info(LogManager.getHeader(context, "batchimport", "loading file")); + + // Process CSV without import + ItemImport itemImport = new ItemImport(); + + /* + ItemImportOptions itemImportOptions = new ItemImportOptions(); + + itemImportOptions.setZipFilePath(file); + + Collection destCollection = Collection.find(context, 10); + itemImportOptions.setCollection(destCollection); + + EPerson epersonSubmitter = EPerson.findByEmail(context, "peter@longsight.com"); + itemImportOptions.setEpersonSubmitter(epersonSubmitter); + + itemImportOptions.setUseTemplate(true); +*/ + File mapFile = File.createTempFile("batch", "map"); +/* PrintWriter mapOut = new PrintWriter(new FileWriter(mapFile)); + itemImportOptions.setMapFileOut(mapOut); + log.info("MapFile: " + mapFile.getAbsolutePath()); + //Process ItemImport with ZIP, and other options. +*/ + + /* + // equivalent command-line would be: + import -a -e -c -s -z -m --template + + -c,--collection destination collection(s) Handle or database ID + -e,--eperson email of eperson doing importing + -m,--mapfile mapfile items in mapfile + -n,--notify if sending submissions through the workflow, send + notification emails + -p,--template apply template + -q,--quiet don't display metadata + + -s,--source source of items (directory) + -t,--test test run - do not actually import items + -w,--workflow send submission through collection's workflow + -z,--zip name of zip file + + //Control + -a,--add add items to DSpace + -R,--resume resume a failed import (add only) + */ + + + String sourceBatchDir = ItemImport.unzip(file); + + + + Collection col10 = Collection.find(context, 10); + Collection[] collections = new Collection[1]; + collections[0] = col10; + itemImport.addItems(context, collections, sourceBatchDir, mapFile.getAbsolutePath(), true); + + + + if(true) + { + // Success! + // Set session and request attributes + + //request.setAttribute("changes", changes); + //request.getSession().setAttribute("csv", csv); + log.info("batch success"); + + result.setContinue(true); + result.setOutcome(true); + result.setMessage(T_upload_successful); + } + else + { + //fail + log.info("batch fail"); + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_no_changes); + } + } + else + { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_upload_failed); + } + + return result; + } +} diff --git a/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/Navigation.java b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/Navigation.java index 70e47526a9..8e9ed36254 100644 --- a/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/Navigation.java +++ b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/Navigation.java @@ -61,6 +61,7 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr private static final Message T_context_create_subcommunity = message("xmlui.administrative.Navigation.context_create_subcommunity"); private static final Message T_context_create_community = message("xmlui.administrative.Navigation.context_create_community"); private static final Message T_context_export_metadata = message("xmlui.administrative.Navigation.context_export_metadata"); + private static final Message T_administrative_batch_import = message("xmlui.administrative.Navigation.administrative_batch_import"); private static final Message T_administrative_import_metadata = message("xmlui.administrative.Navigation.administrative_import_metadata"); private static final Message T_administrative_head = message("xmlui.administrative.Navigation.administrative_head"); private static final Message T_administrative_access_control = message("xmlui.administrative.Navigation.administrative_access_control"); @@ -297,6 +298,7 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr admin.addItemXref(contextPath+"/admin/panel", T_administrative_control_panel); admin.addItemXref(contextPath+"/statistics", T_statistics); admin.addItemXref(contextPath+ "/admin/metadataimport", T_administrative_import_metadata); + admin.addItemXref(contextPath+"/admin/batchimport", T_administrative_batch_import); admin.addItemXref(contextPath+ "/admin/curate", T_administrative_curation); } } diff --git a/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportConfirm.java b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportConfirm.java new file mode 100644 index 0000000000..da4f45af04 --- /dev/null +++ b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportConfirm.java @@ -0,0 +1,263 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.xmlui.aspect.administrative.batchimport; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.cocoon.environment.ObjectModelHelper; +import org.apache.cocoon.environment.Request; + +import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer; +import org.dspace.app.xmlui.wing.Message; +import org.dspace.app.xmlui.wing.WingException; +import org.dspace.app.xmlui.wing.element.Body; +import org.dspace.app.xmlui.wing.element.Button; +import org.dspace.app.xmlui.wing.element.Division; +import org.dspace.app.xmlui.wing.element.PageMeta; +import org.dspace.app.xmlui.wing.element.Para; +import org.dspace.app.xmlui.wing.element.Table; +import org.dspace.app.xmlui.wing.element.Row; +import org.dspace.app.xmlui.wing.element.Cell; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.content.DCValue; +import org.xml.sax.SAXException; + +import org.dspace.app.bulkedit.BulkEditChange; + +/** + * Web interface to Batch Import app. + * Display summary of committed changes + * + * @author Peter Dietz + */ + +public class BatchImportConfirm extends AbstractDSpaceTransformer { + + /** Language strings */ + private static final Message T_dspace_home = message("xmlui.general.dspace_home"); + private static final Message T_submit_return = message("xmlui.general.return"); + private static final Message T_trail = message("xmlui.administrative.metadataimport.general.trail"); + private static final Message T_changes = message("xmlui.administrative.metadataimport.general.changes"); + private static final Message T_new_item = message("xmlui.administrative.metadataimport.general.new_item"); + private static final Message T_no_changes = message("xmlui.administrative.metadataimport.general.no_changes"); + private static final Message T_title = message("xmlui.administrative.metadataimport.general.title"); + private static final Message T_head1 = message("xmlui.administrative.metadataimport.general.head1"); + + private static final Message T_success = message("xmlui.administrative.metadataimport.MetadataImportConfirm.success"); + private static final Message T_changes_committed = message("xmlui.administrative.metadataimport.MetadataImportConfirm.changes_committed"); + private static final Message T_item_addition = message("xmlui.administrative.metadataimport.MetadataImportConfirm.item_added"); + private static final Message T_item_deletion = message("xmlui.administrative.metadataimport.MetadataImportConfirm.item_removed"); + private static final Message T_collection_newowner = message("xmlui.administrative.metadataimport.MetadataImportConfirm.collection_newowner"); + private static final Message T_collection_oldowner = message("xmlui.administrative.metadataimport.MetadataImportConfirm.collection_oldowner"); + private static final Message T_collection_mapped = message("xmlui.administrative.metadataimport.MetadataImportConfirm.collection_mapped"); + private static final Message T_collection_unmapped = message("xmlui.administrative.metadataimport.MetadataImportConfirm.collection_unmapped"); + private static final Message T_item_deleted = message("xmlui.administrative.metadataimport.MetadataImportConfirm.item_deleted"); + private static final Message T_item_withdrawn = message("xmlui.administrative.metadataimport.MetadataImportConfirm.item_withdrawn"); + private static final Message T_item_reinstated = message("xmlui.administrative.metadataimport.MetadataImportConfirm.item_reinstated"); + + public void addPageMeta(PageMeta pageMeta) throws WingException + { + pageMeta.addMetadata("title").addContent(T_title); + + pageMeta.addTrailLink(contextPath + "/", T_dspace_home); + pageMeta.addTrail().addContent(T_trail); + } + + + public void addBody(Body body) throws SAXException, WingException, SQLException + { + // Get list of changes + + Request request = ObjectModelHelper.getRequest(objectModel); + ArrayList changes = null; + + if(request.getAttribute("changes") != null) + { + changes = ((ArrayList)request.getAttribute("changes")); + } + + if (changes == null) + { + changes = new ArrayList(); + } + + // DIVISION: metadata-import + Division div = body.addInteractiveDivision("batch-import",contextPath + "/admin/batchimport", Division.METHOD_MULTIPART,"primary administrative"); + div.setHead(T_head1); + Para para = div.addPara(); + para.addContent(T_success); + para.addContent(" " + changes.size() + " "); + para.addContent(T_changes); + + if(changes.size() > 0) { + Table mdchanges = div.addTable("metadata-changes", changes.size(), 2); + + // Display the changes + for (BulkEditChange change : changes) + { + // Get the changes + List adds = change.getAdds(); + List removes = change.getRemoves(); + List newCollections = change.getNewMappedCollections(); + List oldCollections = change.getOldMappedCollections(); + + if ((adds.size() > 0) || (removes.size() > 0) || + (newCollections.size() > 0) || (oldCollections.size() > 0) || + (change.getNewOwningCollection() != null) || (change.getOldOwningCollection() != null) || + (change.isDeleted()) || (change.isWithdrawn()) || (change.isReinstated())) + { + Row headerrow = mdchanges.addRow(Row.ROLE_HEADER); + // Show the item + if (!change.isNewItem()) + { + Item i = change.getItem(); + Cell cell = headerrow.addCell(); + cell.addContent(T_changes_committed); + cell.addContent(" " + i.getID() + " (" + i.getHandle() + ")"); + } + else + { + headerrow.addCellContent(T_new_item); + } + headerrow.addCell(); + } + + // Show actions + if (change.isDeleted()) + { + Row mdrow = mdchanges.addRow("addition",Row.ROLE_DATA,"item-delete"); + + Cell cell = mdrow.addCell(); + cell.addContent(T_item_deleted); + mdrow.addCellContent(""); + } + if (change.isWithdrawn()) + { + Row mdrow = mdchanges.addRow("addition",Row.ROLE_DATA,"item-withdraw"); + + Cell cell = mdrow.addCell(); + cell.addContent(T_item_withdrawn); + mdrow.addCellContent(""); + } + if (change.isReinstated()) + { + Row mdrow = mdchanges.addRow("addition",Row.ROLE_DATA,"item-reinstate"); + + Cell cell = mdrow.addCell(); + cell.addContent(T_item_reinstated); + mdrow.addCellContent(""); + } + + // Show new owning collection + if (change.getNewOwningCollection() != null) + { + Collection c = change.getNewOwningCollection(); + if (c != null) + { + String cHandle = c.getHandle(); + String cName = c.getName(); + Row colrow = mdchanges.addRow("addition",Row.ROLE_DATA,"metadata-addition"); + colrow.addCellContent(T_collection_newowner); + colrow.addCellContent(cHandle + " (" + cName + ")"); + } + } + + // Show old owning collection + if (change.getOldOwningCollection() != null) + { + Collection c = change.getOldOwningCollection(); + if (c != null) + { + String cHandle = c.getHandle(); + String cName = c.getName(); + Row colrow = mdchanges.addRow("deletion",Row.ROLE_DATA,"metadata-deletion"); + colrow.addCellContent(T_collection_oldowner); + colrow.addCellContent(cHandle + " (" + cName + ")"); + } + } + + // Show new mapped collections + for (Collection c : newCollections) + { + String cHandle = c.getHandle(); + String cName = c.getName(); + Row colrow = mdchanges.addRow("addition",Row.ROLE_DATA,"metadata-addition"); + colrow.addCellContent(T_collection_mapped); + colrow.addCellContent(cHandle + " (" + cName + ")"); + } + + // Show old mapped collections + for (Collection c : oldCollections) + { + String cHandle = c.getHandle(); + String cName = c.getName(); + Row colrow = mdchanges.addRow("deletion",Row.ROLE_DATA,"metadata-deletion"); + colrow.addCellContent(T_collection_unmapped); + colrow.addCellContent(cHandle + " (" + cName + ")"); + } + + // Show additions + for (DCValue dcv : adds) + { + Row mdrow = mdchanges.addRow("addition",Row.ROLE_DATA,"metadata-addition"); + String md = dcv.schema + "." + dcv.element; + if (dcv.qualifier != null) + { + md += "." + dcv.qualifier; + } + if (dcv.language != null) + { + md += "[" + dcv.language + "]"; + } + + Cell cell = mdrow.addCell(); + cell.addContent(T_item_addition); + cell.addContent(" (" + md + ")"); + mdrow.addCellContent(dcv.value); + } + + // Show removals + for (DCValue dcv : removes) + { + Row mdrow = mdchanges.addRow("deletion",Row.ROLE_DATA,"metadata-deletion"); + String md = dcv.schema + "." + dcv.element; + if (dcv.qualifier != null) + { + md += "." + dcv.qualifier; + } + if (dcv.language != null) + { + md += "[" + dcv.language + "]"; + } + + Cell cell = mdrow.addCell(); + cell.addContent(T_item_deletion); + cell.addContent(" (" + md + ")"); + mdrow.addCellContent(dcv.value); + } + } + } + else + { + Para nochanges = div.addPara(); + nochanges.addContent(T_no_changes); + } + Para actions = div.addPara(); + Button cancel = actions.addButton("submit_return"); + cancel.setValue(T_submit_return); + + + div.addHidden("administrative-continue").setValue(knot.getId()); + } + + + +} diff --git a/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportMain.java b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportMain.java new file mode 100644 index 0000000000..90e55f8c36 --- /dev/null +++ b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportMain.java @@ -0,0 +1,66 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.xmlui.aspect.administrative.batchimport; + +import java.sql.SQLException; + +import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer; +import org.dspace.app.xmlui.wing.Message; +import org.dspace.app.xmlui.wing.WingException; +import org.dspace.app.xmlui.wing.element.Body; +import org.dspace.app.xmlui.wing.element.Button; +import org.dspace.app.xmlui.wing.element.Division; +import org.dspace.app.xmlui.wing.element.PageMeta; +import org.dspace.app.xmlui.wing.element.Para; +import org.xml.sax.SAXException; + +/** + * Web interface to BatchImport app. + * + * @author Peter Dietz + */ + +public class BatchImportMain extends AbstractDSpaceTransformer { + + /** Language strings */ + private static final Message T_dspace_home = message("xmlui.general.dspace_home"); + + private static final Message T_title = message("xmlui.administrative.batchimport.general.title"); + private static final Message T_head1 = message("xmlui.administrative.batchimport.general.head1"); + private static final Message T_submit_upload = message("xmlui.administrative.batchimport.MetadataImportMain.submit_upload"); + private static final Message T_trail = message("xmlui.administrative.batchimport.general.trail"); + + public void addPageMeta(PageMeta pageMeta) throws WingException + { + pageMeta.addMetadata("title").addContent(T_title); + + pageMeta.addTrailLink(contextPath + "/", T_dspace_home); + pageMeta.addTrail().addContent(T_trail); + } + + + public void addBody(Body body) throws SAXException, WingException, SQLException + { + + // DIVISION: batch-import + Division div = body.addInteractiveDivision("batch-import",contextPath + "/admin/batchimport", Division.METHOD_MULTIPART,"primary administrative"); + div.setHead(T_head1); + + Para file = div.addPara(); + file.addFile("file"); + + Para actions = div.addPara(); + Button button = actions.addButton("submit_upload"); + button.setValue(T_submit_upload); + + div.addHidden("administrative-continue").setValue(knot.getId()); + } + + + +} diff --git a/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportUpload.java b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportUpload.java new file mode 100644 index 0000000000..e308b21392 --- /dev/null +++ b/dspace-xmlui/src/main/java/org/dspace/app/xmlui/aspect/administrative/batchimport/BatchImportUpload.java @@ -0,0 +1,89 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.xmlui.aspect.administrative.batchimport; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.cocoon.environment.ObjectModelHelper; +import org.apache.cocoon.environment.Request; + +import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer; +import org.dspace.app.xmlui.wing.Message; +import org.dspace.app.xmlui.wing.WingException; +import org.dspace.app.xmlui.wing.element.Body; +import org.dspace.app.xmlui.wing.element.Button; +import org.dspace.app.xmlui.wing.element.Division; +import org.dspace.app.xmlui.wing.element.PageMeta; +import org.dspace.app.xmlui.wing.element.Para; +import org.dspace.app.xmlui.wing.element.Table; +import org.dspace.app.xmlui.wing.element.Row; +import org.dspace.app.xmlui.wing.element.Cell; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.content.DCValue; +import org.xml.sax.SAXException; + +import org.dspace.app.bulkedit.BulkEditChange; + +/** + * Web interface to Batch Import app. + * + * Display form for user to review changes and confirm + * + * @author Peter Dietz + */ + +public class BatchImportUpload extends AbstractDSpaceTransformer { + + /** Language strings */ + private static final Message T_dspace_home = message("xmlui.general.dspace_home"); + private static final Message T_submit_return = message("xmlui.general.return"); + private static final Message T_trail = message("xmlui.administrative.batchimport.general.trail"); + private static final Message T_no_changes = message("xmlui.administrative.batchimport.general.no_changes"); + private static final Message T_new_item = message("xmlui.administrative.batchimport.general.new_item"); + private static final Message T_title = message("xmlui.administrative.batchimport.general.title"); + private static final Message T_head1 = message("xmlui.administrative.batchimport.general.head1"); + + private static final Message T_para = message("xmlui.administrative.batchimport.BatchImportUpload.hint"); + private static final Message T_submit_confirm = message("xmlui.administrative.batchimport.BatchImportUpload.submit_confirm"); + private static final Message T_changes_pending = message("xmlui.administrative.batchimport.BatchImportUpload.changes_pending"); + private static final Message T_item_addition = message("xmlui.administrative.batchimport.BatchImportUpload.item_add"); + private static final Message T_item_deletion = message("xmlui.administrative.batchimport.BatchImportUpload.item_remove"); + private static final Message T_collection_newowner = message("xmlui.administrative.batchimport.BatchImportUpload.collection_newowner"); + private static final Message T_collection_oldowner = message("xmlui.administrative.batchimport.BatchImportUpload.collection_oldowner"); + private static final Message T_collection_mapped = message("xmlui.administrative.batchimport.BatchImportUpload.collection_mapped"); + private static final Message T_collection_unmapped = message("xmlui.administrative.batchimport.BatchImportUpload.collection_unmapped"); + private static final Message T_item_delete = message("xmlui.administrative.batchimport.BatchImportUpload.item_delete"); + private static final Message T_item_withdraw = message("xmlui.administrative.batchimport.BatchImportUpload.item_withdraw"); + private static final Message T_item_reinstate = message("xmlui.administrative.batchimport.BatchImportUpload.item_reinstate"); + + public void addPageMeta(PageMeta pageMeta) throws WingException + { + pageMeta.addMetadata("title").addContent(T_title); + + pageMeta.addTrailLink(contextPath + "/", T_dspace_home); + pageMeta.addTrail().addContent(T_trail); + } + + + public void addBody(Body body) throws SAXException, WingException, SQLException + { + // Get list of changes + Request request = ObjectModelHelper.getRequest(objectModel); + + // DIVISION: batch-import + Division div = body.addInteractiveDivision("batch-import",contextPath + "/admin/batchimport", Division.METHOD_MULTIPART,"primary administrative"); + div.setHead(T_head1); + + + div.addHidden("administrative-continue").setValue(knot.getId()); + } + +} diff --git a/dspace-xmlui/src/main/resources/aspects/Administrative/administrative.js b/dspace-xmlui/src/main/resources/aspects/Administrative/administrative.js index 2481210582..f4a8c9a826 100644 --- a/dspace-xmlui/src/main/resources/aspects/Administrative/administrative.js +++ b/dspace-xmlui/src/main/resources/aspects/Administrative/administrative.js @@ -33,6 +33,7 @@ importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowAuthorizatio importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowContainerUtils); importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowCurationUtils); importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowMetadataImportUtils); +importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowBatchImportUtils); importClass(Packages.java.lang.System); importClass(Packages.org.dspace.core.ConfigurationManager); @@ -541,6 +542,18 @@ function startMetadataImport() cocoon.exit(); } +function startBatchImport() +{ + + assertAdministrator(); + + doBatchImport(); + + cocoon.redirectTo(cocoon.request.getContextPath()); + getDSContext().complete(); + cocoon.exit(); +} + /** * Start creating a new collection. */ @@ -1932,6 +1945,61 @@ function doMetadataImportConfirm() return null; } +/** + * Manage batch metadata import + * + */ + +function doBatchImport() +{ + var result; + + assertAdministrator(); + do + { + sendPageAndWait("admin/batchimport/main",{},result); + result = null; + + if (cocoon.request.get("submit_upload")) + { + result = doBatchImportUpload(); + + } + + } while (true); +} + +function doBatchImportUpload() +{ + var result = FlowBatchImportUtils.processUploadZIP(getDSContext(),cocoon.request); + + assertAdministrator(); + do + { + sendPageAndWait("admin/batchimport/upload",{},result); + result = null; + + if (cocoon.request.get("submit_return")) + { + return null; + } + else if (cocoon.request.get("submit_confirm")) + { + + result = doBatchImportConfirm(); + return result; + } + } while (true); +} + +function doBatchImportConfirm() +{ + var result = FlowBatchImportUtils.processBatchImport(getDSContext(),cocoon.request); + assertAdministrator(); + sendPageAndWait("admin/batchimport/confirm",{},result); + return null; +} + /** * Search for new items to map into the collection */ diff --git a/dspace-xmlui/src/main/resources/aspects/Administrative/sitemap.xmap b/dspace-xmlui/src/main/resources/aspects/Administrative/sitemap.xmap index 376f9cc036..0606d11a16 100644 --- a/dspace-xmlui/src/main/resources/aspects/Administrative/sitemap.xmap +++ b/dspace-xmlui/src/main/resources/aspects/Administrative/sitemap.xmap @@ -59,6 +59,10 @@ to administer DSpace. + + + + @@ -209,6 +213,19 @@ to administer DSpace. + + + + + + + + + + + + + + + + + + + + + + + + + @@ -925,9 +959,12 @@ to administer DSpace. - + + + + diff --git a/dspace-xmlui/src/main/webapp/i18n/messages.xml b/dspace-xmlui/src/main/webapp/i18n/messages.xml index d9a9f1821c..ce40d792fa 100644 --- a/dspace-xmlui/src/main/webapp/i18n/messages.xml +++ b/dspace-xmlui/src/main/webapp/i18n/messages.xml @@ -1019,6 +1019,7 @@ Private Items Control Panel Statistics + Batch Import (ZIP) Import Metadata Curation Tasks @@ -1438,6 +1439,35 @@ Action Group + + + + Import Batch Load (ZIP) + Import Batch Load (ZIP) + Import Batch Load (ZIP) + changes + No changes were detected + New item + Upload successful + Upload failed + Unknown metadata schema in heading + Unknown metadata element in heading + Import successful + Import failed + + + Upload SimpleArchiveFormat ZIP + + + Successfully processed + Changes applied to item + Added: + Removed: + + + Add: + Remove: + Items Edit Template Item for Collection: {0}