Index: dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/Navigation.java =================================================================== --- dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/Navigation.java (revision 4449) +++ dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/Navigation.java (working copy) @@ -92,7 +92,8 @@ private static final Message T_context_create_collection = message("xmlui.administrative.Navigation.context_create_collection"); 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_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"); private static final Message T_administrative_people = message("xmlui.administrative.Navigation.administrative_people"); @@ -237,11 +238,14 @@ Item item = (Item) dso; if (item.canEdit()) { - context.setHead(T_context_head); - context.addItem().addXref(contextPath+"/admin/item?itemID="+item.getID(), T_context_edit_item); - if (AuthorizeManager.isAdmin(this.context, dso)) - context.addItem().addXref(contextPath+"/admin/export?itemID="+item.getID(), T_context_export_item ); - } + context.setHead(T_context_head); + context.addItem().addXref(contextPath+"/admin/item?itemID="+item.getID(), T_context_edit_item); + if (AuthorizeManager.isAdmin(this.context, dso)) + { + context.addItem().addXref(contextPath+"/admin/export?itemID="+item.getID(), T_context_export_item ); + context.addItem().addXref(contextPath+ "/csv/handle/"+dso.getHandle(),T_context_export_metadata ); + } + } } else if (dso instanceof Collection) { @@ -254,7 +258,10 @@ context.addItemXref(contextPath+"/admin/collection?collectionID=" + collection.getID(), T_context_edit_collection); context.addItemXref(contextPath+"/admin/mapper?collectionID="+collection.getID(), T_context_item_mapper); if (AuthorizeManager.isAdmin(this.context, dso)) + { context.addItem().addXref(contextPath+"/admin/export?collectionID="+collection.getID(), T_context_export_collection ); + context.addItem().addXref(contextPath+ "/csv/handle/"+dso.getHandle(),T_context_export_metadata ); + } } } else if (dso instanceof Community) @@ -268,6 +275,7 @@ context.addItemXref(contextPath+"/admin/community?communityID=" + community.getID(), T_context_edit_community); if (AuthorizeManager.isAdmin(this.context, dso)) context.addItem().addXref(contextPath+"/admin/export?communityID="+community.getID(), T_context_export_community ); + context.addItem().addXref(contextPath+ "/csv/handle/"+dso.getHandle(),T_context_export_metadata ); } // can they add to this community? @@ -311,6 +319,7 @@ admin.addItemXref(contextPath+"/admin/withdrawn", T_administrative_withdrawn); admin.addItemXref(contextPath+"/admin/panel", T_administrative_control_panel); admin.addItemXref(contextPath+"/statistics", T_statistics); + admin.addItemXref(contextPath+ "/admin/metadataimport", T_administrative_import_metadata); } } Index: dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/FlowMetadataImportUtils.java =================================================================== --- dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/FlowMetadataImportUtils.java (revision 0) +++ dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/FlowMetadataImportUtils.java (revision 0) @@ -0,0 +1,229 @@ +/* + * FlowMetadataImportUtils.java + * + * Version: $Revision: $ + * + * Date: $Date: $ + * + * Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the DSpace Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ +package org.dspace.app.xmlui.aspect.administrative; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.io.File; + +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.xmlui.wing.Message; +import org.dspace.authorize.AuthorizeException; +import org.dspace.core.Context; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.LogManager; + +import org.dspace.app.bulkedit.MetadataImport; +import org.dspace.app.bulkedit.MetadataImportException; +import org.dspace.app.bulkedit.DSpaceCSV; +import org.dspace.app.bulkedit.BulkEditChange; + +/** + * Utility methods to processes MetadataImport actions. These methods are used + * exclusively from the administrative flow scripts. + * + * @author Kim Shepherd + */ + +public class FlowMetadataImportUtils +{ + + /** Language Strings */ + private static final Message T_upload_successful = new Message("default", "xmlui.administrative.metadataimport.flow.upload_successful"); + private static final Message T_upload_failed = new Message("default", "xmlui.administrative.metadataimport.flow.upload_failed"); + private static final Message T_import_successful = new Message("default", "xmlui.administrative.metadataimport.flow.import_successful"); + private static final Message T_import_failed = new Message("default", "xmlui.administrative.metadataimport.flow.import_failed"); + private static final Message T_over_limit = new Message("default", "xmlui.administrative.metadataimport.flow.over_limit"); + private static final Message T_no_changes = new Message("default", "xmlui.administrative.metadataimport.general.no_changes"); + + // Other variables + private static final int limit = ConfigurationManager.getIntProperty("bulkedit.gui-item-limit", 20); + private static Logger log = Logger.getLogger(FlowMetadataImportUtils.class); + + public static FlowResult processMetadataImport(Context context,Request request) throws SQLException, AuthorizeException, IOException, Exception + { + + FlowResult result = new FlowResult(); + result.setContinue(false); + + DSpaceCSV csv = (DSpaceCSV)request.getSession().getAttribute("csv"); + + if(csv != null) + { + try { + + // Run the import + MetadataImport mImport = new MetadataImport(context, csv.getCSVLines()); + ArrayList changes = mImport.runImport(true, false, false, false); + + // Commit the changes + context.commit(); + request.setAttribute("changes",changes); + request.getSession().removeAttribute("csv"); + + log.debug(LogManager.getHeader(context, "metadataimport", changes.size() + " items changed")); + + if(changes.size() > 0) { + result.setContinue(true); + result.setOutcome(true); + result.setMessage(T_import_successful); + } + else { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_no_changes); + } + + } + catch(MetadataImportException e) { + result.setContinue(false); + result.setOutcome(false); + result.addError(e.getLocalizedMessage()); + result.setMessage(T_import_failed); + log.debug(LogManager.getHeader(context, "metadataimport", "Error encountered while making changes - " + e.getMessage())); + } + } + else { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_import_failed); + log.debug(LogManager.getHeader(context, "metadataimport", "Changes cancelled")); + } + + return result; + } + + public static FlowResult processUploadCSV(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); + } + + try { + + log.info(LogManager.getHeader(context, "metadataimport", "loading file")); + + // Process CSV without import + DSpaceCSV csv = new DSpaceCSV(file); + file.delete(); + + MetadataImport mImport = new MetadataImport(context, csv.getCSVLines()); + ArrayList changes = mImport.runImport(false, false, false, false); + log.debug(LogManager.getHeader(context, "metadataimport", changes.size() + " items with changes identifed")); + + if(changes.size() > 0) + { + if(changes.size() > limit) + { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_over_limit); + + log.info(LogManager.getHeader(context, "metadataimport", "too many changes - " + + changes.size() + " (" + limit + " allowed)")); + } + else + { + // Success! + // Set session and request attributes + + request.setAttribute("changes", changes); + request.getSession().setAttribute("csv", csv); + result.setContinue(true); + result.setOutcome(true); + result.setMessage(T_upload_successful); + } + + } + else + { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_no_changes); + } + } + catch(MetadataImportException e) { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_upload_failed); + log.debug(LogManager.getHeader(context, "metadataimport", "Error encountered while looking for changes - " + e.getMessage())); + } + } + else + { + result.setContinue(false); + result.setOutcome(false); + result.setMessage(T_upload_failed); + } + + return result; + + } +} Index: dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportMain.java =================================================================== --- dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportMain.java (revision 0) +++ dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportMain.java (revision 0) @@ -0,0 +1,100 @@ +/* + * MetadataImportMain.java + * + * Version: $Revision: $ + * + * Date: $Date: $ + * + * Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the DSpace Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. +*/ + +package org.dspace.app.xmlui.aspect.administrative.metadataimport; + +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 Bulk Metadata Import app. + * ported from org.dspace.app.webui.servlet.MetadataImportServlet + * + * Initial select file / upload CSV form + * + * @author Kim Shepherd + */ + +public class MetadataImportMain 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.metadataimport.general.title"); + private static final Message T_head1 = message("xmlui.administrative.metadataimport.general.head1"); + private static final Message T_submit_upload = message("xmlui.administrative.metadataimport.MetadataImportMain.submit_upload"); + private static final Message T_trail = message("xmlui.administrative.metadataimport.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: metadata-import + Division div = body.addInteractiveDivision("metadata-import",contextPath + "/admin/metadataimport", 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()); + } + + + +} Index: dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportUpload.java =================================================================== --- dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportUpload.java (revision 0) +++ dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportUpload.java (revision 0) @@ -0,0 +1,241 @@ +/* + * MetadataImportUpload.java + * + * Version: $Revision: $ + * + * Date: $Date: $ + * + * Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the DSpace Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. +*/ + +package org.dspace.app.xmlui.aspect.administrative.metadataimport; + +import java.sql.SQLException; +import java.util.ArrayList; + +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 Bulk Metadata Import app. + * ported from org.dspace.app.webui.servlet.MetadataImportServlet + * + * Display form for user to review changes and confirm + * + * @author Kim Shepherd + */ + +public class MetadataImportUpload 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_no_changes = message("xmlui.administrative.metadataimport.general.no_changes"); + private static final Message T_new_item = message("xmlui.administrative.metadataimport.general.new_item"); + 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_para = message("xmlui.administrative.metadataimport.MetadataImportUpload.hint"); + private static final Message T_submit_confirm = message("xmlui.administrative.metadataimport.MetadataImportUpload.submit_confirm"); + private static final Message T_changes_pending = message("xmlui.administrative.metadataimport.MetadataImportUpload.changes_pending"); + private static final Message T_item_addition = message("xmlui.administrative.metadataimport.MetadataImportUpload.item_add"); + private static final Message T_item_deletion = message("xmlui.administrative.metadataimport.MetadataImportUpload.item_remove"); + private static final Message T_collection_addition = message("xmlui.administrative.metadataimport.MetadataImportUpload.collection_add"); + private static final Message T_collection_deletion = message("xmlui.administrative.metadataimport.MetadataImportUpload.collection_remove"); + + + + 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; + int num_changes = 0; + + if(request.getAttribute("changes") != null) + { + changes = ((ArrayList)request.getAttribute("changes")); + num_changes = changes.size(); + } + + + // DIVISION: metadata-import + Division div = body.addInteractiveDivision("metadata-import",contextPath + "/admin/metadataimport", Division.METHOD_MULTIPART,"primary administrative"); + div.setHead(T_head1); + + if(num_changes > 0) + { + + div.addPara(T_para); + + Table mdchanges = div.addTable("metadata-changes", num_changes, 2); + + // Display the changes + int changeCounter = 0; + for (BulkEditChange change : changes) + { + // Get the changes + ArrayList adds = change.getAdds(); + ArrayList removes = change.getRemoves(); + ArrayList newCollections = change.getNewOwningCollections(); + ArrayList oldCollections = change.getOldOwningCollections(); + + if ((adds.size() > 0) || (removes.size() > 0) || + (newCollections.size() > 0) || (oldCollections.size() > 0)) + { + 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_pending); + cell.addContent(" " + i.getID() + "(" + i.getHandle() + ")"); + + } + else + { + headerrow.addCellContent(T_new_item); + } + headerrow.addCell(); + changeCounter++; + } + + // Show new 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_addition); + colrow.addCellContent(cHandle + " (" + cName + ")"); + } + + // Show old 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_deletion); + 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); + } + } + Para actions = div.addPara(); + Button applychanges = actions.addButton("submit_confirm"); + applychanges.setValue(T_submit_confirm); + Button cancel = actions.addButton("submit_return"); + cancel.setValue(T_submit_return); + } + 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()); + } + +} Index: dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportConfirm.java =================================================================== --- dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportConfirm.java (revision 0) +++ dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/metadataimport/MetadataImportConfirm.java (revision 0) @@ -0,0 +1,232 @@ +/* + * MetadataImportConfirm.java + * + * Version: $Revision: $ + * + * Date: $Date: $ + * + * Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the DSpace Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. +*/ + +package org.dspace.app.xmlui.aspect.administrative.metadataimport; + +import java.sql.SQLException; +import java.util.ArrayList; + +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 Bulk Metadata Import app. + * ported from org.dspace.app.webui.servlet.MetadataImportServlet + * + * Display summary of committed changes + * + * @author Kim Shepherd + */ + +public class MetadataImportConfirm 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_addition = message("xmlui.administrative.metadataimport.MetadataImportConfirm.collection_added"); + private static final Message T_collection_deletion = message("xmlui.administrative.metadataimport.MetadataImportConfirm.collection_removed"); + + + 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")); + + // DIVISION: metadata-import + Division div = body.addInteractiveDivision("metadata-import",contextPath + "/admin/metadataimport", 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 + int changeCounter = 0; + for (BulkEditChange change : changes) + { + // Get the changes + ArrayList adds = change.getAdds(); + ArrayList removes = change.getRemoves(); + ArrayList newCollections = change.getNewOwningCollections(); + ArrayList oldCollections = change.getOldOwningCollections(); + + if ((adds.size() > 0) || (removes.size() > 0) || + (newCollections.size() > 0) || (oldCollections.size() > 0)) + { + 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(); + changeCounter++; + } + + // Show new 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_addition); + colrow.addCellContent(cHandle + " (" + cName + ")"); + } + + // Show old 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_deletion); + 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()); + } + + + +} Index: dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/cocoon/MetadataExportReader.java =================================================================== --- dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/cocoon/MetadataExportReader.java (revision 0) +++ dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/cocoon/MetadataExportReader.java (revision 0) @@ -0,0 +1,232 @@ +/* + * MetadataExportReader.java + * + * Version: $Revision: $ + * + * Date: $Date: $ + * + * Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the DSpace Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +package org.dspace.app.xmlui.cocoon; + +import java.io.IOException; +import java.util.Map; +import java.util.ArrayList; +import javax.servlet.http.HttpServletResponse; +import org.xml.sax.SAXException; + +import org.apache.avalon.excalibur.pool.Recyclable; +import org.apache.avalon.framework.parameters.Parameters; +import org.apache.cocoon.ProcessingException; +import org.apache.cocoon.environment.ObjectModelHelper; +import org.apache.cocoon.environment.Request; +import org.apache.cocoon.environment.Response; +import org.apache.cocoon.environment.SourceResolver; +import org.apache.cocoon.environment.http.HttpEnvironment; +import org.apache.cocoon.reading.AbstractReader; +import org.apache.log4j.Logger; + +import org.dspace.app.xmlui.utils.AuthenticationUtil; +import org.dspace.app.xmlui.utils.ContextUtil; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.handle.HandleManager; +import org.dspace.core.Context; +import org.dspace.core.Constants; +import org.dspace.core.LogManager; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.ItemIterator; + +import org.dspace.app.bulkedit.DSpaceCSV; +import org.dspace.app.bulkedit.MetadataExport; + +/** + * + * AbstractReader that generates a CSV of item, collection + * or community metadata using MetadataExport + * + * @author Kim Shepherd + */ + +public class MetadataExportReader extends AbstractReader implements Recyclable +{ + + /** + * Messages to be sent when the user is not authorized to view + * a particular bitstream. They will be redirected to the login + * where this message will be displayed. + */ + private final static String AUTH_REQUIRED_HEADER = "xmlui.ItemExportDownloadReader.auth_header"; + private final static String AUTH_REQUIRED_MESSAGE = "xmlui.ItemExportDownloadReader.auth_message"; + + /** + * How big of a buffer should we use when reading from the bitstream before + * writting to the HTTP response? + */ + protected static final int BUFFER_SIZE = 8192; + + /** + * When should a download expire in milliseconds. This should be set to + * some low value just to prevent someone hitting DSpace repeatily from + * killing the server. Note: 60000 milliseconds are in a second. + * + * Format: minutes * seconds * milliseconds + */ + protected static final int expires = 60 * 60 * 60000; + + /** The Cocoon response */ + protected Response response; + + /** The Cocoon request */ + protected Request request; + + private static Logger log = Logger.getLogger(MetadataExportReader.class); + + + DSpaceCSV csv = null; + MetadataExport exporter = null; + String filename = null; + /** + * Set up the export reader. + * + * See the class description for information on configuration options. + */ + public void setup(SourceResolver resolver, Map objectModel, String src, + Parameters par) throws ProcessingException, SAXException, + IOException + { + super.setup(resolver, objectModel, src, par); + + try + { + this.request = ObjectModelHelper.getRequest(objectModel); + this.response = ObjectModelHelper.getResponse(objectModel); + Context context = ContextUtil.obtainContext(objectModel); + + if(AuthorizeManager.isAdmin(context)) + { + + /* Get our parameters that identify the item, collection + * or community to be exported + * + */ + + String handle = par.getParameter("handle"); + DSpaceObject dso = HandleManager.resolveToObject(context, handle); + + ArrayList itemmd = new ArrayList(); + if(dso.getType() == Constants.ITEM) + { + itemmd.add(dso.getID()); + exporter = new MetadataExport(context, new ItemIterator(context, itemmd),true); + } + else if(dso.getType() == Constants.COLLECTION) + { + Collection collection = (Collection)dso; + ItemIterator toExport = collection.getAllItems(); + exporter = new MetadataExport(context, toExport,true); + } + else if(dso.getType() == Constants.COMMUNITY) + { + exporter = new MetadataExport(context, (Community)dso, false); + } + + log.info(LogManager.getHeader(context, "metadataexport", "exporting_handle:" + handle)); + csv = exporter.export(); + filename = handle.replaceAll("/", "-") + ".csv"; + log.info(LogManager.getHeader(context, "metadataexport", "exported_file:" + filename)); + } + else { + /* + * Auth should ge done by MetadataExport -- pass context through + * we should just be catching exceptions and displaying errors here + * + */ + + if(this.request.getSession().getAttribute("dspace.current.user.id")!=null) { + String redictURL = request.getContextPath() + "/restricted-resource"; + HttpServletResponse httpResponse = (HttpServletResponse) + objectModel.get(HttpEnvironment.HTTP_RESPONSE_OBJECT); + httpResponse.sendRedirect(redictURL); + return; + } + else { + + String redictURL = request.getContextPath() + "/login"; + AuthenticationUtil.interruptRequest(objectModel, AUTH_REQUIRED_HEADER, AUTH_REQUIRED_MESSAGE, null); + HttpServletResponse httpResponse = (HttpServletResponse) + objectModel.get(HttpEnvironment.HTTP_RESPONSE_OBJECT); + httpResponse.sendRedirect(redictURL); + return; + } + + } + + } + catch (Exception e) + { + throw new ProcessingException("Unable to read bitstream.",e); + } + } + + + /** + * Write the CSV. + * + */ + public void generate() throws IOException, SAXException, + ProcessingException + { + + response.setContentType("text/csv; charset=UTF-8"); + response.setHeader("Content-Disposition","attachment; filename=" + filename); + + out.write(csv.toString().getBytes("UTF-8")); + out.flush(); + out.close(); + + + } + + + /** + * Recycle + */ + public void recycle() { + this.response = null; + this.request = null; + + } + + +} Index: dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/sitemap.xmap =================================================================== --- dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/sitemap.xmap (revision 4449) +++ dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/sitemap.xmap (working copy) @@ -83,7 +83,11 @@ - + + + + + @@ -215,8 +219,23 @@ - + + + + + + + + + + + + + @@ -623,6 +642,23 @@ + + + + + + + + + + + + + + + + + @@ -834,6 +870,9 @@ + + + Index: dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/administrative.js =================================================================== --- dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/administrative.js (revision 4449) +++ dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/administrative.js (working copy) @@ -60,6 +60,7 @@ importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowMapperUtils); importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowAuthorizationUtils); importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowContainerUtils); +importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowMetadataImportUtils); importClass(Packages.java.lang.System); /** @@ -545,6 +546,18 @@ cocoon.exit(); } +function startMetadataImport() +{ + + assertAdministrator(); + + doMetadataImport(); + + cocoon.redirectTo(cocoon.request.getContextPath()); + getDSContext().complete(); + cocoon.exit(); +} + /** * Start creating a new collection. */ @@ -1754,7 +1767,8 @@ assertEditCollection(collectionID); var result; - do { + do + { sendPageAndWait("admin/mapper/main",{"collectionID":collectionID},result); assertEditCollection(collectionID); result = null; @@ -1779,6 +1793,61 @@ } /** + * Manage batch metadata import + * + */ + +function doMetadataImport() +{ + var result; + + assertAdministrator(); + do + { + sendPageAndWait("admin/metadataimport/main",{},result); + result = null; + + if (cocoon.request.get("submit_upload")) + { + result = doMetadataImportUpload(); + + } + + } while (true); +} + +function doMetadataImportUpload() +{ + var result = FlowMetadataImportUtils.processUploadCSV(getDSContext(),cocoon.request); + + assertAdministrator(); + do + { + sendPageAndWait("admin/metadataimport/upload",{},result); + result = null; + + if (cocoon.request.get("submit_return")) + { + return null; + } + else if (cocoon.request.get("submit_confirm")) + { + + result = doMetadataImportConfirm(); + return result; + } + } while (true); +} + +function doMetadataImportConfirm() +{ + var result = FlowMetadataImportUtils.processMetadataImport(getDSContext(),cocoon.request); + assertAdministrator(); + sendPageAndWait("admin/metadataimport/confirm",{},result); + return null; +} + +/** * Search for new items to map into the collection */ function doMapItemSearch(collectionID) @@ -1811,7 +1880,7 @@ */ function doMapItemBrowse(collectionID) { - var result + var result; do { sendPageAndWait("admin/mapper/browse",{"collectionID":collectionID}); Index: dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml =================================================================== --- dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml (revision 4449) +++ dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml (working copy) @@ -806,8 +806,9 @@ Create Sub-community Create Community Export Item - Export Collection - Export Community + Export Collection + Export Community + Export Metadata Administrative @@ -822,6 +823,7 @@ Withdrawn Items Control Panel Statistics + Import Metadata My Exports @@ -1358,7 +1360,40 @@ Internal Item ID/Item Handle Unable to resolve identifier. Find - + + + Import Metadata + Import Metadata + Import Metadata + changes + No changes were detected + New item + Upload successful + Upload failed + Import successful + Import failed + Number of changes exceeds maximum allowed. Limit changes or alter bulkedit.gui-item-limit in dspace.cfg + + + Upload CSV + + + Successfully processed + Changes applied to item + Added: + Removed: + Added to collection + Removed from collection + + + Add: + Remove: + Add to collection + Remove from collection + Changes pending for item + Apply changes + Pending changes are listed below for review + Item mapper Index: dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Classic/lib/style.css =================================================================== --- dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Classic/lib/style.css (revision 4449) +++ dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Classic/lib/style.css (working copy) @@ -532,8 +532,23 @@ } +/* metadata import rows + * additions and deletions + */ +tr.ds-table-row.metadata-addition { + background-color: #CCFFCC; +} +tr.ds-table-row.metadata-deletion { + background-color: #CCCCCC; +} + +tr.ds-table-row.metadata-addition td,tr.ds-table-row.metadata-deletion td { + border-top: 1px solid black; +} + + /******************************* *********** forms *********** *******************************/ Index: dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Kubrick/lib/css/style.css =================================================================== --- dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Kubrick/lib/css/style.css (revision 4449) +++ dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Kubrick/lib/css/style.css (working copy) @@ -216,7 +216,23 @@ } +/* metadata import rows + * additions and deletions + */ +tr.ds-table-row.metadata-addition { + background-color: #CCFFCC; +} + +tr.ds-table-row.metadata-deletion { + background-color: #CCCCCC; +} + +tr.ds-table-row.metadata-addition td,tr.ds-table-row.metadata-deletion td { + border-top: 1px solid black; +} + + .artifact-description { /* This is about as wide as we can get it without pushing the pictures (artifact-previews) down. Index: dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Reference/lib/style.css =================================================================== --- dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Reference/lib/style.css (revision 4449) +++ dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Reference/lib/style.css (working copy) @@ -525,6 +525,22 @@ background-color: rgb(216, 245, 216); } +/* metadata import rows + * additions and deletions + */ + +tr.ds-table-row.metadata-addition { + background-color: #CCFFCC; +} + +tr.ds-table-row.metadata-deletion { + background-color: #CCCCCC; +} + +tr.ds-table-row.metadata-addition td,tr.ds-table-row.metadata-deletion td { + border-top: 1px solid black; +} + /* Tables that are actually a result of glossary lists are not rendered as plain tables are... */ table.ds-gloss-list { Index: dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/sitemap.xmap =================================================================== --- dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/sitemap.xmap (revision 4449) +++ dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/sitemap.xmap (working copy) @@ -196,6 +196,7 @@ + @@ -375,6 +376,12 @@ + + + + + +