Skip to content

Commit

Permalink
Merge pull request #8706 from IQSS/8600-duplicate-template
Browse files Browse the repository at this point in the history
8600 duplicate template
  • Loading branch information
kcondon authored May 19, 2022
2 parents adf2305 + a9861fb commit fdef1f6
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 26 deletions.
9 changes: 9 additions & 0 deletions doc/release-notes/8600-duplicate-templates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
###Duplicate Templates in Database
Prior to this release making a copy of a Dataset Template was creating two copies, one of which is visible in the dataverse, the other not being assigned
a dataverse was invisible to the user (https://github.com/IQSS/dataverse/issues/8600). This release fixes the issue.

If you would like to remove these orphan templates you may run the follwing script:

https://github.com/IQSS/dataverse/raw/develop/scripts/issues/8600/delete_orphan_templates_8600.sh

Also, admin APIs for finding and deleting templates have been added.
33 changes: 33 additions & 0 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3806,3 +3806,36 @@ Superusers can delete a license that is not in use by the license ``$ID``:
.. code-block:: bash
curl -X DELETE -H X-Dataverse-key:$API_TOKEN $SERVER_URL/api/licenses/$ID
List Dataset Templates
~~~~~~~~~~~~~~~~~~~~~~
List all templates in the system. ::
GET http://$SERVER/api/admin/templates
List templates in a given dataverse by the dataverse's alias or id. ::
GET http://$SERVER/api/admin/templates/{alias or id}
Delete Dataset Template
~~~~~~~~~~~~~~~~~~~~~~~
A curl example using an ``ID``
.. code-block:: bash
export SERVER_URL=https://demo.dataverse.org
export ID=24
curl -X DELETE $SERVER_URL/api/admin/template/$ID
The fully expanded example above (without environment variables) looks like this:
.. code-block:: bash
curl -X DELETE https://demo.dataverse.org/api/admin/template/24
70 changes: 70 additions & 0 deletions scripts/issues/8600/delete_orphan_templates_8600.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash

# begin config
# PostgresQL credentials:
# edit the following lines so that psql can talk to your database
pg_host=localhost
pg_port=5432
pg_user=dvnapp
pg_db=dvndb
#edit this line with the server for the api call to delete orphan templates
SERVER=http://localhost:8080/api
# you can leave the password blank, if Postgres is configured
# to accept connections without auth:
pg_pass=
# psql executable - add full path, if necessary:
PSQL_EXEC=psql

# end config

# check for orphan template :

PG_QUERY_0="SELECT count(t.id) FROM template t WHERE dataverse_id is null;"
PG_QUERY_1="SELECT t.id, ',' FROM template t WHERE dataverse_id is null;"

PGPASSWORD=$pg_pass; export PGPASSWORD

echo "Checking the total number of orphan templates in database..."

NUM_TEMPLATES=`${PSQL_EXEC} -h ${pg_host} -U ${pg_user} -d ${pg_db} -tA -F ' ' -c "${PG_QUERY_0}"`
if [ $? != 0 ]
then
echo "FAILED to execute psql! Check the credentials and try again?"
echo "exiting..."
echo
echo "the command line that failed:"
echo "${PSQL_EXEC} -h ${pg_host} -U ${pg_user} -d ${pg_db} -tA -F ' ' -c \"${PG_QUERY_0}\""
exit 1
fi

echo $NUM_TEMPLATES total.
echo


TEMPLATE_ID=`${PSQL_EXEC} -h ${pg_host} -U ${pg_user} -d ${pg_db} -tA -F ' ' -c "${PG_QUERY_1}"`

echo $TEMPLATE_ID to remove.


${PSQL_EXEC} -h ${pg_host} -U ${pg_user} -d ${pg_db} -t -c "${PG_QUERY_1}" \
-t \
--field-separator ' ' \
--quiet \
| while read -a Record ; do
id=${Record[0]}

if [[ "x${id}" = "x" ]]
then
echo "nothing to do here"
else
curl -X DELETE $SERVER/admin/template/${id}
echo "template ${id} deleted "
fi

done

NUM_TEMPLATES=`${PSQL_EXEC} -h ${pg_host} -U ${pg_user} -d ${pg_db} -tA -F ' ' -c "${PG_QUERY_0}"`

echo $NUM_TEMPLATES orphan templates remaining.


Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,17 @@ public String cloneTemplate(Template templateIn) {
newOne.setName(name);
newOne.setUsageCount(new Long(0));
newOne.setCreateTime(new Timestamp(new Date().getTime()));
dataverse.getTemplates().add(newOne);
templates.add(newOne);
newOne.setDataverse(dataverse);

Template created;
try {
created = engineService.submit(new CreateTemplateCommand(newOne, dvRequestService.getDataverseRequest(), dataverse));
dataverse.getTemplates().add(created);
templates.add(created);
saveDataverse("");
String msg = BundleUtil.getStringFromBundle("template.clone");//"The template has been copied";
JsfHelper.addFlashMessage(msg);
return "/template.xhtml?id=" + created.getId() + "&ownerId=" + dataverse.getId() + "&editMode=METADATA&faces-redirect=true";
return "/template.xhtml?id=" + created.getId() + "&ownerId=" + dataverse.getId() + "&editMode=CLONE&faces-redirect=true";
} catch (CommandException ex) {
JH.addMessage(FacesMessage.SEVERITY_FATAL, BundleUtil.getStringFromBundle("template.clone.error"));//"Template could not be copied. "
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/Template.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,22 @@
import javax.validation.constraints.Size;

import edu.harvard.iq.dataverse.util.DateUtil;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import org.hibernate.validator.constraints.NotBlank;

/**
*
* @author skraffmiller
*/

@NamedQueries({
@NamedQuery(name = "Template.findByOwnerId",
query = "select object(o) from Template as o where o.dataverse.id =:ownerId"),
@NamedQuery(name = "Template.findAll",
query = "select object(o) from Template as o")
})

@Entity
@Table(indexes = {@Index(columnList="dataverse_id")})
public class Template implements Serializable {
Expand Down
19 changes: 18 additions & 1 deletion src/main/java/edu/harvard/iq/dataverse/TemplatePage.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import edu.harvard.iq.dataverse.engine.command.Command;
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.engine.command.impl.CreateTemplateCommand;
import edu.harvard.iq.dataverse.engine.command.impl.DeleteTemplateCommand;
import edu.harvard.iq.dataverse.engine.command.impl.UpdateDataverseCommand;
import edu.harvard.iq.dataverse.engine.command.impl.UpdateDataverseTemplateCommand;
import edu.harvard.iq.dataverse.license.LicenseServiceBean;
Expand All @@ -12,6 +13,7 @@
import static edu.harvard.iq.dataverse.util.JsfHelper.JH;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.faces.application.FacesMessage;
Expand Down Expand Up @@ -53,7 +55,7 @@ public class TemplatePage implements java.io.Serializable {

public enum EditMode {

CREATE, METADATA, LICENSE, LICENSEADD
CREATE, METADATA, LICENSE, LICENSEADD, CLONE
};

private Template template;
Expand Down Expand Up @@ -236,5 +238,20 @@ public String save(String redirectPage) {
public void cancel() {
editMode = null;
}

public String deleteTemplate(Long templateId) {
List <Dataverse> dataverseWDefaultTemplate = null;
Template doomed = templateService.find(templateId);
dataverse.getTemplates().remove(doomed);
dataverseWDefaultTemplate = templateService.findDataversesByDefaultTemplateId(doomed.getId());
try {
commandEngine.submit(new DeleteTemplateCommand(dvRequestService.getDataverseRequest(), getDataverse(), doomed, dataverseWDefaultTemplate ));
JsfHelper.addFlashMessage(BundleUtil.getStringFromBundle("template.delete"));//("The template has been deleted");
} catch (CommandException ex) {
String failMessage = BundleUtil.getStringFromBundle("template.delete.error");//"The dataset template cannot be deleted.";
JH.addMessage(FacesMessage.SEVERITY_FATAL, failMessage);
}
return "/manage-templates.xhtml?dataverseId=" + dataverse.getId() + "&faces-redirect=true";
}

}
21 changes: 8 additions & 13 deletions src/main/java/edu/harvard/iq/dataverse/TemplateServiceBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,17 @@ public Template find(Object pk) {
}

public Template save(Template template) {
/*
if (template.getId() == null) {
em.persist(template);
return template;
} else {
return em.merge(template);
} */
return em.merge(template);
}

public Template findByDeafultTemplateOwnerId(Long ownerId) {
TypedQuery<Template> query = em.createQuery("select object(o.defaultTemplate) from Dataverse as o where o.owner.id =:ownerId order by o.name", Template.class);
query.setParameter("ownerId", ownerId);
return query.getSingleResult();

public List<Template> findByOwnerId(Long ownerId) {
return em.createNamedQuery("Template.findByOwnerId", Template.class).setParameter("ownerId", ownerId).getResultList();
}


public List<Template> findAll() {
return em.createNamedQuery("Template.findAll", Template.class).getResultList();
}

public List<Dataverse> findDataversesByDefaultTemplateId(Long defaultTemplateId) {
TypedQuery<Dataverse> query = em.createQuery("select object(o) from Dataverse as o where o.defaultTemplate.id =:defaultTemplateId order by o.name", Dataverse.class);
query.setParameter("defaultTemplateId", defaultTemplateId);
Expand Down
78 changes: 78 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/api/Admin.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
import edu.harvard.iq.dataverse.DatasetVersionServiceBean;
import edu.harvard.iq.dataverse.Dataverse;
import edu.harvard.iq.dataverse.DataverseRequestServiceBean;
import edu.harvard.iq.dataverse.DataverseServiceBean;
import edu.harvard.iq.dataverse.DataverseSession;
import edu.harvard.iq.dataverse.DvObject;
import edu.harvard.iq.dataverse.validation.EMailValidator;
import edu.harvard.iq.dataverse.EjbDataverseEngine;
import edu.harvard.iq.dataverse.GlobalId;
import edu.harvard.iq.dataverse.Template;
import edu.harvard.iq.dataverse.TemplateServiceBean;
import edu.harvard.iq.dataverse.UserServiceBean;
import edu.harvard.iq.dataverse.actionlogging.ActionLogRecord;
import edu.harvard.iq.dataverse.api.dto.RoleDTO;
Expand Down Expand Up @@ -85,6 +88,7 @@
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.engine.command.impl.DeactivateUserCommand;
import edu.harvard.iq.dataverse.engine.command.impl.DeleteRoleCommand;
import edu.harvard.iq.dataverse.engine.command.impl.DeleteTemplateCommand;
import edu.harvard.iq.dataverse.engine.command.impl.RegisterDvObjectCommand;
import edu.harvard.iq.dataverse.ingest.IngestServiceBean;
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
Expand All @@ -101,6 +105,7 @@
import static edu.harvard.iq.dataverse.util.json.JsonPrinter.json;
import static edu.harvard.iq.dataverse.util.json.JsonPrinter.rolesToJson;
import static edu.harvard.iq.dataverse.util.json.JsonPrinter.toJsonArray;
import java.math.BigDecimal;


import java.util.ArrayList;
Expand Down Expand Up @@ -140,6 +145,8 @@ public class Admin extends AbstractApiBean {
DataFileServiceBean fileService;
@EJB
DatasetServiceBean datasetService;
@EJB
DataverseServiceBean dataverseService;
@EJB
DatasetVersionServiceBean datasetversionService;
@Inject
Expand All @@ -156,6 +163,8 @@ public class Admin extends AbstractApiBean {
ExplicitGroupServiceBean explicitGroupService;
@EJB
BannerMessageServiceBean bannerMessageService;
@EJB
TemplateServiceBean templateService;

// Make the session available
@Inject
Expand Down Expand Up @@ -208,6 +217,75 @@ public Response deleteSetting(@PathParam("name") String name, @PathParam("lang")
settingsSvc.delete(name, lang);
return ok("Setting " + name + " - " + lang + " deleted.");
}

@Path("template/{id}")
@DELETE
public Response deleteTemplate(@PathParam("id") long id) {

AuthenticatedUser superuser = authSvc.getAdminUser();
if (superuser == null) {
return error(Response.Status.INTERNAL_SERVER_ERROR, "Cannot find superuser to execute DeleteTemplateCommand.");
}

Template doomed = templateService.find(id);
if (doomed == null) {
return error(Response.Status.NOT_FOUND, "Template with id " + id + " - not found.");
}

Dataverse dv = doomed.getDataverse();
List <Dataverse> dataverseWDefaultTemplate = templateService.findDataversesByDefaultTemplateId(doomed.getId());

try {
commandEngine.submit(new DeleteTemplateCommand(createDataverseRequest(superuser), dv, doomed, dataverseWDefaultTemplate));
} catch (CommandException ex) {
Logger.getLogger(Admin.class.getName()).log(Level.SEVERE, null, ex);
return error(Response.Status.BAD_REQUEST, ex.getLocalizedMessage());
}

return ok("Template " + doomed.getName() + " deleted.");
}


@Path("templates")
@GET
public Response findAllTemplates() {
return findTemplates("");
}

@Path("templates/{alias}")
@GET
public Response findTemplates(@PathParam("alias") String alias) {
List<Template> templates;

if (alias.isEmpty()) {
templates = templateService.findAll();
} else {
try{
Dataverse owner = findDataverseOrDie(alias);
templates = templateService.findByOwnerId(owner.getId());
} catch (WrappedResponse r){
return r.getResponse();
}
}

JsonArrayBuilder container = Json.createArrayBuilder();
for (Template t : templates) {
JsonObjectBuilder bld = Json.createObjectBuilder();
bld.add("templateId", t.getId());
bld.add("templateName", t.getName());
Dataverse loopowner = t.getDataverse();
if (loopowner != null) {
bld.add("owner", loopowner.getDisplayName());
} else {
bld.add("owner", "This an orphan template, it may be safely removed");
}
container.add(bld);
}

return ok(container);


}

@Path("authenticationProviderFactories")
@GET
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,17 @@ public DeleteTemplateCommand(DataverseRequest aRequest, Dataverse editedDv , Tem

@Override
public Dataverse execute(CommandContext ctxt) throws CommandException {
Dataverse merged = ctxt.em().merge(editedDv);
if (!dvWDefaultTemplate.isEmpty()){
for (Dataverse remove: dvWDefaultTemplate){
remove.setDefaultTemplate(null);
ctxt.em().merge(remove);
}
Dataverse merged = null;
if (editedDv != null) {
merged = ctxt.em().merge(editedDv);
if (!dvWDefaultTemplate.isEmpty()) {
for (Dataverse remove : dvWDefaultTemplate) {
remove.setDefaultTemplate(null);
ctxt.em().merge(remove);
}
}
}

Template doomedAndMerged = ctxt.em().merge(doomed);
ctxt.em().remove(doomedAndMerged);
return merged;
Expand Down
Loading

0 comments on commit fdef1f6

Please sign in to comment.