From 78da3e7776026cd9b29b3e972c8f961458d435a1 Mon Sep 17 00:00:00 2001 From: Mike McKay <mfmckay@wustl.edu> Date: Tue, 27 Sep 2016 12:07:37 -0500 Subject: [PATCH] XNAT-4469 Fixed Bulk Delete checkboxes for subjects. --- .../screens/BulkDeleteActionScreen.java | 374 +++++++++--------- 1 file changed, 191 insertions(+), 183 deletions(-) diff --git a/src/main/java/org/nrg/xnat/turbine/modules/screens/BulkDeleteActionScreen.java b/src/main/java/org/nrg/xnat/turbine/modules/screens/BulkDeleteActionScreen.java index 61be9b42..d4d796af 100644 --- a/src/main/java/org/nrg/xnat/turbine/modules/screens/BulkDeleteActionScreen.java +++ b/src/main/java/org/nrg/xnat/turbine/modules/screens/BulkDeleteActionScreen.java @@ -26,121 +26,129 @@ public class BulkDeleteActionScreen extends SecureScreen { // Enumeration to determine what type of item is stored in an ItemContainer object. private enum ITEM_TYPE { SUBJECT, SUBJ_ASSESSOR, IMG_ASSESSOR }; - + @Override protected void doBuildTemplate(RunData data, Context context) throws Exception { - - //retrieve passed search object - DisplaySearch search = TurbineUtils.getSearch(data); - search.setPagingOn(false); - - //Load search results into a table - XFTTable table = (org.nrg.xft.XFTTable)search.execute(null,TurbineUtils.getUser(data).getLogin()); - - XFTTable experiments = null; - UserI user = TurbineUtils.getUser(data); - - // Build the query to retrieve information about the items we want to delete. - StringBuilder query = new StringBuilder(); - query.append("SELECT subj.id AS subj_id, subj.label AS subj_label, subj.project AS subj_project, session_expt.id AS session_id, session_expt.label AS session_label, session_expt.project AS session_project, session_expt.date AS session_date, session_meta.element_name AS session_xsi, expt.id AS assess_id, expt.label AS assess_label, expt.project AS assess_project, expt.date AS assess_date, meta.element_name AS assess_xsi FROM xnat_imageassessordata iad FULL JOIN xnat_experimentData expt ON iad.id=expt.id FULL JOIN xdat_meta_element meta ON expt.extension=meta.xdat_meta_element_id FULL JOIN xnat_subjectAssessorData session_sad ON iad.imagesession_id=session_sad.id FULL JOIN xnat_experimentData session_expt ON session_sad.id=session_expt.id FULL JOIN xdat_meta_element session_meta ON session_expt.extension=session_meta.xdat_meta_element_id FULL JOIN xnat_subjectData subj ON session_sad.subject_id=subj.id "); - - // Build the WHERE Clause based on what type of query we are performing. (Subject, Subject Assessor, or Image Assessor) - // Also, set the searchType, we need this in the velocity to determine if a user is allowed to delete an item. (see ItemContainer.canDelete() below) - if (search.getRootElement().getFullXMLName().equals("xnat:subjectData")){ - context.put("searchType", "subject"); - query.append("WHERE subj.id IN ('") - .append(buildWhereClause(table.convertColumnToArrayList("subjectid"))) - .append("');"); - // XNAT-2829: If the search was for imaging sessions - }else if(search.getRootElement().getGenericXFTElement().instanceOf("xnat:imageSessionData")){ - context.put("searchType", "subject_assessor"); // Set the searchType - query.append("WHERE session_expt.id IN ('") - .append(buildWhereClause(table.convertColumnToArrayList("session_id"))) - .append("');"); - // XNAT-2829: If the search was for subject assessors (non imaging) - }else if(search.getRootElement().getGenericXFTElement().instanceOf("xnat:subjectAssessorData")){ - context.put("searchType", "subject_assessor"); // Set the searchType - query.append("WHERE session_expt.id IN ('") - .append(buildWhereClause(table.convertColumnToArrayList("expt_id"))) - .append("');"); - }else if(search.getRootElement().getGenericXFTElement().instanceOf("xnat:imageAssessorData")){ - context.put("searchType", "image_assessor"); // Set the searchType - query.append("WHERE expt.id IN ('") - .append(buildWhereClause(table.convertColumnToArrayList("expt_id"))) - .append("');"); - } - - // Execute the query to get a list of experiments - experiments = XFTTable.Execute(query.toString(), user.getDBName(), user.getUsername()); - - // Insert the items into the context. - Hashtable<String, ItemContainer> items = getItems(experiments); - if(null != items && items.size() != 0){ - context.put("items", items); - }else{ - context.put("errMsg", "There is nothing to delete."); - } + + //retrieve passed search object + DisplaySearch search = TurbineUtils.getSearch(data); + search.setPagingOn(false); + + //Load search results into a table + XFTTable table = (org.nrg.xft.XFTTable)search.execute(null,TurbineUtils.getUser(data).getLogin()); + + XFTTable experiments = null; + UserI user = TurbineUtils.getUser(data); + + // Build the query to retrieve information about the items we want to delete. + StringBuilder query = new StringBuilder(); + query.append("SELECT subj.id AS subj_id, subj.label AS subj_label, subj.project AS subj_project, session_expt.id AS session_id, session_expt.label AS session_label, session_expt.project AS session_project, session_expt.date AS session_date, session_meta.element_name AS session_xsi, expt.id AS assess_id, expt.label AS assess_label, expt.project AS assess_project, expt.date AS assess_date, meta.element_name AS assess_xsi FROM xnat_imageassessordata iad FULL JOIN xnat_experimentData expt ON iad.id=expt.id FULL JOIN xdat_meta_element meta ON expt.extension=meta.xdat_meta_element_id FULL JOIN xnat_subjectAssessorData session_sad ON iad.imagesession_id=session_sad.id FULL JOIN xnat_experimentData session_expt ON session_sad.id=session_expt.id FULL JOIN xdat_meta_element session_meta ON session_expt.extension=session_meta.xdat_meta_element_id FULL JOIN xnat_subjectData subj ON session_sad.subject_id=subj.id "); + + // Build the WHERE Clause based on what type of query we are performing. (Subject, Subject Assessor, or Image Assessor) + // Also, set the searchType, we need this in the velocity to determine if a user is allowed to delete an item. (see ItemContainer.canDelete() below) + if (search.getRootElement().getFullXMLName().equals("xnat:subjectData")){ + context.put("searchType", "subject"); + query.append("WHERE subj.id IN ('") + .append(buildWhereClause(table.convertColumnToArrayList("subjectid"))) + .append("');"); + // XNAT-2829: If the search was for imaging sessions + }else if(search.getRootElement().getGenericXFTElement().instanceOf("xnat:imageSessionData")){ + context.put("searchType", "subject_assessor"); // Set the searchType + query.append("WHERE session_expt.id IN ('") + .append(buildWhereClause(table.convertColumnToArrayList("session_id"))) + .append("');"); + // XNAT-2829: If the search was for subject assessors (non imaging) + }else if(search.getRootElement().getGenericXFTElement().instanceOf("xnat:subjectAssessorData")){ + context.put("searchType", "subject_assessor"); // Set the searchType + query.append("WHERE session_expt.id IN ('") + .append(buildWhereClause(table.convertColumnToArrayList("expt_id"))) + .append("');"); + }else if(search.getRootElement().getGenericXFTElement().instanceOf("xnat:imageAssessorData")){ + context.put("searchType", "image_assessor"); // Set the searchType + query.append("WHERE expt.id IN ('") + .append(buildWhereClause(table.convertColumnToArrayList("expt_id"))) + .append("');"); + } + + // Execute the query to get a list of experiments + experiments = XFTTable.Execute(query.toString(), user.getDBName(), user.getUsername()); + + // Insert the items into the context. + Hashtable<String, ItemContainer> items = getItems(experiments, search); + if(null != items && items.size() != 0){ + context.put("items", items); + }else{ + context.put("errMsg", "There is nothing to delete."); + } context.put("turbineUtils", TurbineUtils.GetInstance()); } /** * Function takes a XFTtable and converts it into a Hashtable of ItemContainers. * @param t - XFTTable + * @param search - DisplaySearch * @return Hashtable<String, ItemContainer> * @throws Exception - if the Hashtable is null or empty after function executes. */ - private Hashtable<String, ItemContainer> getItems(XFTTable t) throws Exception{ + private Hashtable<String, ItemContainer> getItems(XFTTable t, DisplaySearch search) throws Exception{ Hashtable<String,ItemContainer> subjects = new Hashtable<String,ItemContainer>(); - + // For each experiment in the hashtable. for(Hashtable exp : t.rowHashs()){ - - String subj_id = (String)exp.get("subj_id"); - if(null != subj_id){ - // Get the container for the subject if it exists. - ItemContainer subj = subjects.get(subj_id); - if(null == subj){ - // If it doesn't exist create it. - subj = new ItemContainer(ITEM_TYPE.SUBJECT, subj_id,(String)exp.get("subj_project"),(String)exp.get("subj_label")); - } - - String session_id = (String)exp.get("session_id"); - if(null != session_id){ - - // Get a list of subject assessors - Hashtable<String,ItemContainer> subjAssessors = subj.getAssessors(); - ItemContainer experiment = subjAssessors.get(session_id); - - if(null == experiment){ - // If the experiment doesn't exist create it. - experiment = new ItemContainer(ITEM_TYPE.SUBJ_ASSESSOR, session_id, (String)exp.get("session_label"), (String)exp.get("session_project"), (Date)exp.get("session_date"), (String)exp.get("session_xsi")); - } - - // Get a list of image assessors for the experiment - Hashtable<String,ItemContainer> imgAssessors = experiment.getAssessors(); - String assess_id = (String)exp.get("assess_id"); - - if(assess_id != null && !imgAssessors.contains(assess_id)){ - //If the assessor doesn't exist, create it, add it to the list of assessors and attach it to the experiment. - imgAssessors.put(assess_id, new ItemContainer(ITEM_TYPE.IMG_ASSESSOR, assess_id, (String)exp.get("assess_label"), (String)exp.get("assess_project"), (Date)exp.get("assess_date"), (String)exp.get("assess_xsi"))); - experiment.addAssessors(imgAssessors); - } - - // Update the list of subject Assessors and attach it to the subject - subjAssessors.put(experiment.getId(), experiment); - subj.addAssessors(subjAssessors); - } - // Add the new ItemContainer to the Hashtable - subjects.put(subj.getId(), subj); - } + + String subj_id = (String)exp.get("subj_id"); + if(null != subj_id){ + // Get the container for the subject if it exists. + ItemContainer subj = subjects.get(subj_id); + if(null == subj){ + // If it doesn't exist create it. + + String xsiType = null; //The xsiType should be null in cases where the bulk delete is not at the + // subject level. This way the subjects will only have checkboxes next to them if the bulk delete is + // being done at the subject level, which is how this has always worked. + if(search.getRootElement().getFullXMLName().equals("xnat:subjectData")){ + xsiType="xnat:subjectData"; + } + subj = new ItemContainer(ITEM_TYPE.SUBJECT, subj_id,(String)exp.get("subj_project"),(String)exp.get("subj_label"),xsiType); + } + + String session_id = (String)exp.get("session_id"); + if(null != session_id){ + + // Get a list of subject assessors + Hashtable<String,ItemContainer> subjAssessors = subj.getAssessors(); + ItemContainer experiment = subjAssessors.get(session_id); + + if(null == experiment){ + // If the experiment doesn't exist create it. + experiment = new ItemContainer(ITEM_TYPE.SUBJ_ASSESSOR, session_id, (String)exp.get("session_label"), (String)exp.get("session_project"), (Date)exp.get("session_date"), (String)exp.get("session_xsi")); + } + + // Get a list of image assessors for the experiment + Hashtable<String,ItemContainer> imgAssessors = experiment.getAssessors(); + String assess_id = (String)exp.get("assess_id"); + + if(assess_id != null && !imgAssessors.contains(assess_id)){ + //If the assessor doesn't exist, create it, add it to the list of assessors and attach it to the experiment. + imgAssessors.put(assess_id, new ItemContainer(ITEM_TYPE.IMG_ASSESSOR, assess_id, (String)exp.get("assess_label"), (String)exp.get("assess_project"), (Date)exp.get("assess_date"), (String)exp.get("assess_xsi"))); + experiment.addAssessors(imgAssessors); + } + + // Update the list of subject Assessors and attach it to the subject + subjAssessors.put(experiment.getId(), experiment); + subj.addAssessors(subjAssessors); + } + // Add the new ItemContainer to the Hashtable + subjects.put(subj.getId(), subj); + } } - + return subjects; } - + /** * Function builds a comma delimited string of id's to be - * inserted in the where clause of a sql query. + * inserted in the where clause of a sql query. * @param ids - a list of ids * @return a comma delimited string of id's */ @@ -148,103 +156,103 @@ public class BulkDeleteActionScreen extends SecureScreen { StringBuilder whereClause = new StringBuilder(); for(Object id : ids){ if(id.equals(ids.get(ids.size()-1))){ - whereClause.append(id.toString()); + whereClause.append(id.toString()); }else{ - whereClause.append(id.toString()).append("','"); + whereClause.append(id.toString()).append("','"); } - } + } return whereClause.toString(); } - + /** * Class holds information on an item (subject, experiment, image assessors) * It has helper methods to make it easier to access the information from the velocity. */ public class ItemContainer{ - private final String id,label, project, xsi; - private final ITEM_TYPE itemType; - private final Date date; - private Hashtable<String,ItemContainer> assessors = new Hashtable<String,ItemContainer>(); - - /** - * Constructor for subject_assessor and image_assessor item types. - * @param itemType - * @param id - * @param label - * @param project - * @param date - * @param xsiType - */ - public ItemContainer(ITEM_TYPE itemType, String id, String label, String project, Date date, String xsiType){ - this.id = id; - this.label = label; - this.project = project; - this.date = date; - this.xsi = xsiType; - this.itemType = itemType; - } - - /** - * Constructor for subject item types. Date and XSI type are null. - * @param itemType - * @param id - * @param project - * @param label - */ - public ItemContainer(ITEM_TYPE itemType, String id, String project, String label){ - this.id = id; - this.project = project; - this.label = label; - this.itemType = itemType; - this.date = null; - this.xsi = null; + private final String id,label, project, xsi; + private final ITEM_TYPE itemType; + private final Date date; + private Hashtable<String,ItemContainer> assessors = new Hashtable<String,ItemContainer>(); + + /** + * Constructor for subject_assessor and image_assessor item types. + * @param itemType + * @param id + * @param label + * @param project + * @param date + * @param xsiType + */ + public ItemContainer(ITEM_TYPE itemType, String id, String label, String project, Date date, String xsiType){ + this.id = id; + this.label = label; + this.project = project; + this.date = date; + this.xsi = xsiType; + this.itemType = itemType; + } + + /** + * Constructor for subject item types. XSI type is xnat:subjectData in cases where we want a checkbox to show up for subjects and null otherwise. Date is null. + * @param itemType + * @param id + * @param project + * @param label + */ + public ItemContainer(ITEM_TYPE itemType, String id, String project, String label, String xsiType){ + this.id = id; + this.project = project; + this.label = label; + this.itemType = itemType; + this.date = null; + this.xsi = xsiType; } - - public Hashtable<String,ItemContainer> getAssessors(){ return this.assessors; } - - public void addAssessors(Hashtable<String,ItemContainer> assessors){ this.assessors = assessors; } - - public String getId(){ return this.id; } - - public String getLabel(){ return this.label; } - - public String getProject() { return this.project; } - - public String getDate() { return (this.date == null) ? "" : this.date.toString(); } - - public String getXsiType() { return this.xsi; } - - /** - * Function will determine if the given user is allowed to delete this item. - * Also, some items should not be delete based on the search type. - * (e.g.) If user searches for Image Assessors, they should not be allowed to delete the entire subject. - * @param u - the UserI - * @param searchType - subject, subject_assessor, image_assessor (this is set on lines 49, 54, and 59 above) - * @return - */ - public String canDelete(UserI u, String searchType){ - try{ - // Is the user allowed to delete this item - boolean canDelete = Permissions.canAny(u,this.xsi, this.project, "delete"); - - // The search type determines which items a user is allowed to delete. - if(searchType.equals("subject")){ - // If the user searched for subjects, they should be allowed to delete subjects, subject assessors, and image assessors. - return String.valueOf(canDelete); - }else if(searchType.equals("subject_assessor")){ - // If the user searched for subject assessors, we should allow them to delete subject assessors and image assessors. - return String.valueOf((this.itemType == ITEM_TYPE.SUBJ_ASSESSOR || this.itemType == ITEM_TYPE.IMG_ASSESSOR) && canDelete); - }else if(searchType.equals("image_assessor")){ - // If the user searched for image assessors, we should allow them to delete image assessors only. - return String.valueOf((this.itemType == ITEM_TYPE.IMG_ASSESSOR) && canDelete); - }else { - // If the search type is anything else, something went wrong so we return false. + + public Hashtable<String,ItemContainer> getAssessors(){ return this.assessors; } + + public void addAssessors(Hashtable<String,ItemContainer> assessors){ this.assessors = assessors; } + + public String getId(){ return this.id; } + + public String getLabel(){ return this.label; } + + public String getProject() { return this.project; } + + public String getDate() { return (this.date == null) ? "" : this.date.toString(); } + + public String getXsiType() { return this.xsi; } + + /** + * Function will determine if the given user is allowed to delete this item. + * Also, some items should not be delete based on the search type. + * (e.g.) If user searches for Image Assessors, they should not be allowed to delete the entire subject. + * @param u - the UserI + * @param searchType - subject, subject_assessor, image_assessor (this is set on lines 49, 54, and 59 above) + * @return + */ + public String canDelete(UserI u, String searchType){ + try{ + // Is the user allowed to delete this item + boolean canDelete = Permissions.canAny(u,this.xsi, this.project, "delete"); + + // The search type determines which items a user is allowed to delete. + if(searchType.equals("subject")){ + // If the user searched for subjects, they should be allowed to delete subjects, subject assessors, and image assessors. + return String.valueOf(canDelete); + }else if(searchType.equals("subject_assessor")){ + // If the user searched for subject assessors, we should allow them to delete subject assessors and image assessors. + return String.valueOf((this.itemType == ITEM_TYPE.SUBJ_ASSESSOR || this.itemType == ITEM_TYPE.IMG_ASSESSOR) && canDelete); + }else if(searchType.equals("image_assessor")){ + // If the user searched for image assessors, we should allow them to delete image assessors only. + return String.valueOf((this.itemType == ITEM_TYPE.IMG_ASSESSOR) && canDelete); + }else { + // If the search type is anything else, something went wrong so we return false. + return "false"; + } + }catch(Exception e){ + // Something went wrong so return false. return "false"; - } - }catch(Exception e){ - // Something went wrong so return false. - return "false"; - } - } + } + } } } -- GitLab