Index: samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/QuestionPoolMessages.properties =================================================================== --- samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/QuestionPoolMessages.properties (revision 308089) +++ samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/QuestionPoolMessages.properties (working copy) @@ -112,7 +112,7 @@ # add/update add_title=Add Pool add_summary=add main form -creator=Creator +creator=Owner dept=Department/Group desc=Description obj=Objectives @@ -214,3 +214,22 @@ alt_sortRole = Order by role alt_sortRoleAscending = Order by role in Ascending alt_sortRoleDescending = Order by role in Descending + +# SAM-2049 +t_transferPool=Transfer Pool +transfer_pool=transfer pool +tranfer_pool_continue=Continue +transfer_pool_back=Back +transfer_pool_cancel=Cancel +transfer_pool_ownership=Transfer Ownership +a_transfer=t +a_transfer_back=b +a_cancel=c +transfer_pool_user=transfer pool add user +transfer_pool_confirmation=transfer pool confirmation +transfer_pool_input_user=Enter the user ID for the new owner of the selected pools and click 'Continue'. +transfer_pool_confirm_owner=Ownership of the following pools will be transferred to {0}: +transfer_pool_ids_null_error=You must select at least one question pool to proceed with the transfer. +transfer_pool_userId_null_error=Please input user ID. +transfer_pool_user_invalid=Please enter a valid username. +transfer_pool_select_all=Select All Pools Index: samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/questionpool/QuestionPoolBean.java =================================================================== --- samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/questionpool/QuestionPoolBean.java (revision 308089) +++ samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/questionpool/QuestionPoolBean.java (working copy) @@ -47,6 +47,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.upload.FormFile; +import org.osid.shared.SharedException; import org.sakaiproject.tool.assessment.business.questionpool.QuestionPoolTreeImpl; import org.sakaiproject.tool.assessment.data.dao.assessment.ItemMetaData; import org.sakaiproject.tool.assessment.data.dao.questionpool.QuestionPoolData; @@ -58,12 +59,16 @@ import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade; import org.sakaiproject.tool.assessment.facade.QuestionPoolIteratorFacade; import org.sakaiproject.tool.assessment.facade.SectionFacade; +import org.sakaiproject.tool.assessment.osid.shared.impl.IdImpl; import org.sakaiproject.tool.assessment.services.ItemService; import org.sakaiproject.tool.assessment.services.QuestionPoolService; import org.sakaiproject.tool.assessment.services.SectionService; import org.sakaiproject.tool.assessment.ui.bean.author.ItemAuthorBean; import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil; import org.sakaiproject.tool.assessment.util.BeanSort; +import org.sakaiproject.user.api.User; +import org.sakaiproject.user.api.UserNotDefinedException; +import org.sakaiproject.user.cover.UserDirectoryService; import org.sakaiproject.util.ResourceLoader; import org.sakaiproject.event.cover.EventTrackingService; @@ -149,6 +154,16 @@ private QuestionPoolDataModel qpDataModel; private QuestionPoolDataModel qpDataModelCopy; private QuestionPoolDataModel subQpDataModel; + + // SAM-2049 + private String sortTransferPoolProperty = "title"; + private boolean sortTransferPoolAscending = true; + private QuestionPoolDataModel qpDataModelTransfer; + private QuestionPoolDataModel qpDataModelTransferSelected; + private List transferPools; + private String ownerId; + private String confirmMessage; + private boolean checkAll = false; private String addOrEdit; private String outcome; @@ -2215,4 +2230,273 @@ String owner = AgentFacade.getDisplayName(getAgentId()); return owner; } + + // ********************************************** + // ****************** SAM-2049 ****************** + // ********************************************** + + public boolean getSortTransferPoolAscending() { + return sortTransferPoolAscending; + } + + public void setSortTransferPoolAscending(boolean sspa) { + sortTransferPoolAscending = sspa; + } + + public String getSortTransferPoolProperty() { + return sortTransferPoolProperty; + } + + public void setSortTransferPoolProperty(String newProperty) { + sortTransferPoolProperty= newProperty; + } + + public String transferPoolConfirmBack() { + return "transferPoolInputUser"; + } + + public List getTransferPools() { + return transferPools; + } + + public void setTransferPools(List transferPools) { + this.transferPools = transferPools; + } + + public String getOwnerId() { + return ownerId; + } + + public void setOwnerId(String ownerId) { + this.ownerId = ownerId; + } + + public boolean isCheckAll() { + return checkAll; + } + + public void setCheckAll(boolean checkAll) { + this.checkAll = checkAll; + } + + public QuestionPoolDataModel getTransferQpools() { + buildTreeCopy(); + setQpDataModelByLevelTransferPool(); + log.debug("getSelectedQpools"); + return qpDataModelTransfer; + } + + public QuestionPoolDataModel getTransferSelectedQpools() { + buildTreeTransferPool(); + setQpDataModelByLevelTransferSelectedPools(); + log.debug("qpDataModelTransferSelected"); + return qpDataModelTransferSelected; + } + + public void buildTreeTransferPool() { + try { + QuestionPoolService delegate = new QuestionPoolService(); + List qpList = new ArrayList(); + + if (transferPools != null ) { + for (Long poolId : transferPools) { + QuestionPoolFacade qpFacade = delegate.getPool(poolId, AgentFacade.getAgentString() ); + + IdImpl parentId = (IdImpl) qpFacade.getParentId(); + Long parentIdLong = new Long("0"); + + try { + parentIdLong = Long.valueOf(parentId.getIdString()); + } catch (SharedException e) { + log.warn("error setting pool id to Long." + e.getMessage()); + } + + // If just the child pool will transfer but not the parent pool, set this child pool has no parent. + if (!transferPools.contains(parentIdLong)) { + IdImpl updateParentId = new IdImpl("0"); + qpFacade.setParentId(updateParentId); + } + + qpList.add(qpFacade); + } + QuestionPoolIteratorFacade qpif = new QuestionPoolIteratorFacade(qpList); + tree = new QuestionPoolTreeImpl(qpif); + } else { + tree = new QuestionPoolTreeImpl(new QuestionPoolIteratorFacade(new ArrayList())); + } + } catch (Exception e) { + log.warn("error building transfer pool tree." + e.getMessage()); + throw new RuntimeException(e); + } + } + + public String sortTransferPoolByColumnHeader() { + String sortString = ContextUtil.lookupParam("transferPoolOrderBy"); + String ascending = ContextUtil.lookupParam("transferPoolAscending"); + this.setSortTransferPoolProperty(sortString); + this.setSortTransferPoolAscending((Boolean.valueOf(ascending)).booleanValue()); + setQpDataModelByLevelTransferPool(); + return "transferPool"; + } + + public void setQpDataModelByLevelTransferPool() { + Collection objects = tree.getSortedObjects(); + + // Construct the sortedList, pools need to be sorted one level at a time + // so the hierachical structure can be maintained. Here, we start from root = 0, + if (objects != null) { + ArrayList sortedList = sortPoolByLevel(new Long("0"), objects, + getSortTransferPoolProperty(), getSortTransferPoolAscending()); + ListDataModel model = new ListDataModel((List) sortedList); + QuestionPoolDataModel qpDataModel = new QuestionPoolDataModel(tree, + model); + this.qpDataModelTransfer = qpDataModel; + } + } + + public void setQpDataModelByLevelTransferSelectedPools() { + Collection objects = tree.getSortedObjects(); + + // Construct the sortedList, pools need to be sorted one level at a time + // so the hierachical structure can be maintained. Here, we start from root = 0, + if (objects != null) { + ArrayList sortedList = sortPoolByLevel(new Long("0"), objects, + "title", true); + ListDataModel model = new ListDataModel((List) sortedList); + QuestionPoolDataModel qpDataModel = new QuestionPoolDataModel(tree, + model); + this.qpDataModelTransferSelected = qpDataModel; + } + } + + // Click transfer ownership link in main page + public String transferPool() { + // Reset transferPools, checkAll checkbox, ownerId + this.transferPools = null; + this.checkAll = false; + this.ownerId = null; + + buildTree(); + setQpDataModelByLevelTransferPool(); + return "transferPool"; + } + + // Transfer pool tree page click continue button + public String transferPoolContinue() { + // Setup selected pools for transfer; if no pools selected, post error message + String transferPoolIds = ContextUtil.paramValueLike("transferPoolIds"); + if (transferPoolIds == null || transferPoolIds.isEmpty()) { + FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(rb.getString("transfer_pool_ids_null_error"))); + return "transferPool"; + } + + String[] poolIds = transferPoolIds.split(","); + List transferPoolIdLong = new ArrayList(); + for (int i = 0; i < poolIds.length; i++) { + if (poolIds[i] != null && !poolIds[i].isEmpty()) { + transferPoolIdLong.add(new Long(poolIds[i])); + } + } + this.transferPools = transferPoolIdLong; + + String checkAllChecked = ContextUtil.paramValueLike("checkAllCheckbox"); + if (checkAllChecked == null || "false".equals(checkAllChecked)) { + this.checkAll = false; + } else { + this.checkAll = true; + } + + return "transferPoolInputUser"; + } + + // Transfer pool tree page click cancel button + public String cancelTransferPool() { + buildTree(); + setQpDataModelByLevel(); + return "poolList"; + } + + // Transfer pool input user id page, click continue button + public String transferPoolInputUserContinue() { + String ownerUserId = ContextUtil.paramValueLike("owneruserId"); + + // Check if the userId is null or "" + FacesContext context=FacesContext.getCurrentInstance(); + String err; + if (ownerUserId == null || "".equals(ownerUserId)) { + err = rb.getString("transfer_pool_userId_null_error"); + context.addMessage(null, new FacesMessage(err)); + return "transferPoolInputUser"; + } + + // Check if userId is valid + try { + User user = UserDirectoryService.getUserByEid(ownerUserId); + } catch (UserNotDefinedException e) { + log.debug("Unable to get user by eid: " + ownerUserId); + err = rb.getString("transfer_pool_user_invalid"); + context.addMessage(null, new FacesMessage(err)); + return "transferPoolInputUser"; + } + + this.ownerId = ownerUserId; + return "transferPoolConfirm"; + } + + // Transfer pool input user id page, click back button + public String transferPoolInputUserBack() { + buildTree(); + setQpDataModelByLevelTransferPool(); + return "transferPool"; + } + + public String getConfirmMessage() { + try { + User user = UserDirectoryService.getUserByEid(ownerId); + String userInfo = user.getDisplayName() + " (" + this.ownerId + ")"; + confirmMessage = rb.getFormattedMessage("transfer_pool_confirm_owner", new String[] {userInfo}); + return confirmMessage; + } catch(UserNotDefinedException e) { + log.warn("Unable to get user by eid: " + ownerId); + e.printStackTrace(); + return ""; + } + } + + public String transferPoolOwnership() { + QuestionPoolService delegate = new QuestionPoolService(); + try { + // Need to pass userId not eid to transfer pool. + String userId = UserDirectoryService.getUserId(ownerId); + delegate.transferPoolsOwnership(userId, transferPools); + + // Aggregate pool IDs + String poolIdString = ""; + String prefix = ""; + for (Long poolId : transferPools) { + poolIdString += prefix + poolId.toString(); + prefix = ","; + } + + // Post event + Date now = new Date(); + User currentUser = UserDirectoryService.getCurrentUser(); + String userEID = ""; + if (currentUser != null) { + userEID = currentUser.getEid(); + } else { + userEID = "[current user is null]"; + } + EventTrackingService.post(EventTrackingService.newEvent("sam.questionpool.transfer", "pool(s) [" + poolIdString + "] transferred " + + "from " + userEID + " to " + this.ownerId + " on " + now , true)); + + buildTree(); + setQpDataModelByLevel(); + return "poolList"; + } catch (UserNotDefinedException e) { + log.warn("Unable to get user by eid: " + ownerId); + e.printStackTrace(); + return ""; + } + } } Index: samigo-app/src/webapp/WEB-INF/faces-config.xml =================================================================== --- samigo-app/src/webapp/WEB-INF/faces-config.xml (revision 308089) +++ samigo-app/src/webapp/WEB-INF/faces-config.xml (working copy) @@ -1039,6 +1039,21 @@ copyPool /jsf/questionpool/copyPool.jsp + + + + transferPoolInputUser + /jsf/questionpool/transferPoolInputUser.jsp + + + transferPool + /jsf/questionpool/transferPool.jsp + + + transferPoolConfirm + /jsf/questionpool/transferPoolConfirm.jsp + + movePool /jsf/questionpool/movePool.jsp Index: samigo-app/src/webapp/js/samigotree.js =================================================================== --- samigo-app/src/webapp/js/samigotree.js (revision 308089) +++ samigo-app/src/webapp/js/samigotree.js (working copy) @@ -541,3 +541,148 @@ } } +// ********************************************** +// ****************** SAM-2049 ****************** +// ********************************************** + +function checkChildrenCheckboxes(item) { + var localItem = jQuery(item); + var itemChecked = localItem.is(':checked'); + + // Go to the item's parent table that has the tier. I would have used a wildcard selector but the version + // of jquery we are using doesn't seem to have that working well + var itemParentTable = localItem.parent().parent().parent().parent().parent(); + + // Make sure we found something. A length of 0 would be not found + if (itemParentTable.length == 1) { + // What is the css style of this parent table? we assume this is "tierX" + var itemTierClassName = itemParentTable.attr("class"); + var itemCheckboxTierDigit = getTierDigit(itemTierClassName); + var itemParentTr = itemParentTable.parent().parent().parent(); + + // Let's get all the other mega table rows + var itemPeerTrs = itemParentTr.nextAll(); // Get all sibling tr's AFTER this tr. + + // This will be used if we find a tier level that is at a level the same or higher than the one being checked + var isKeepLooping = true; + + for (var index = 0; (isKeepLooping && index < itemPeerTrs.length); index++) { + var siblingTr = jQuery(itemPeerTrs.get(index)); + var siblingTierTable = siblingTr.find("table"); + var siblingTierTableClassName = siblingTierTable.attr("class"); + var siblingCheckboxTierDigit = getTierDigit(siblingTierTableClassName); + + // If this tier level is greater than the initial item checked then these are child + // checkboxes that need to be set or unset. + if (siblingCheckboxTierDigit > itemCheckboxTierDigit) { + var siblingInputCheckbox = siblingTierTable.find("input:checkbox"); + if (itemChecked) { + siblingInputCheckbox.attr("checked", "checked"); + siblingInputCheckbox.attr("disabled", "disabled"); + } else { + siblingInputCheckbox.removeAttr("checked"); + siblingInputCheckbox.removeAttr("disabled"); + } + } else { + // This tier level is NOT a child tier. No need to look at any more checkboxes + isKeepLooping = false; + } + } + } +} + +function getTierDigit(tierString) { + var classNameDigit = tierString.substr(4, tierString.length - 4); + return classNameDigit; +} + +function checkAllCheckboxes(item) { + var selectAllCheckboxItem = jQuery(item); + var checkBoxChecked = selectAllCheckboxItem.is(':checked'); + var allCheckboxes = jQuery(':checkbox'); + + for (var index = 1; index < allCheckboxes.length; index++) { + var checkboxItem = jQuery(allCheckboxes.get(index)); + if (checkBoxChecked) { + checkboxItem.attr("checked", "checked"); + checkboxItem.attr("disabled", "disabled"); + } else { + checkboxItem.removeAttr("checked"); + checkboxItem.removeAttr("disabled"); + } + } +} + +function passSelectedPoolIds() { + var allCheckboxes = jQuery(':checkbox:checked'); + var poolIds = new Array(); + var checkAllChecked = jQuery('input[name$=checkAllCheckbox]').is(':checked'); + var checkboxValue; + + // If check all checked, ignore the first value; + if (checkAllChecked) { + for (var index = 0; index < (allCheckboxes.length - 1); index++) { + checkboxValue = jQuery(allCheckboxes.get(index + 1)).val(); + poolIds[index] = checkboxValue; + } + } else { + for (var index = 0; index < allCheckboxes.length; index++) { + checkboxValue = jQuery(allCheckboxes.get(index)).val(); + poolIds[index] = checkboxValue; + } + } + + var hideInput = jQuery('input[name$=transferPoolIds]'); + hideInput.val(poolIds); +} + +function checkChildrenCheckboxesDisable(item) { + var localItem = jQuery(item); + var itemChecked = localItem.is(':checked'); + var itemParentTable = localItem.parent().parent().parent().parent().parent(); + + if (itemParentTable.length == 1) { + var itemTierClassName = itemParentTable.attr("class"); + var itemCheckboxTierDigit = getTierDigit(itemTierClassName); + var itemParentTr = itemParentTable.parent().parent().parent(); + var itemPeerTrs = itemParentTr.nextAll(); // Get all sibling tr's AFTER this tr. + var isKeepLooping = true; + + for (var index = 0; (isKeepLooping && index < itemPeerTrs.length); index++) { + var siblingTr = jQuery(itemPeerTrs.get(index)); + var siblingTierTable = siblingTr.find("table"); + var siblingTierTableClassName = siblingTierTable.attr("class"); + var siblingCheckboxTierDigit = getTierDigit(siblingTierTableClassName); + + if (siblingCheckboxTierDigit > itemCheckboxTierDigit) { + var siblingInputCheckbox = siblingTierTable.find("input:checkbox"); + if (itemChecked) { + siblingInputCheckbox.attr("disabled", "disabled"); + } else { + siblingInputCheckbox.removeAttr("disabled"); + } + } else { + isKeepLooping = false; + } + } + } +} + +function disableCheckboxes() { + var allCheckboxes = jQuery(':checkbox'); + var checkAllChecked = jQuery('input[name$=checkAllCheckbox]').is(':checked'); + + for (var index = 1; index < allCheckboxes.length; index++) { + var checkboxItem = jQuery(allCheckboxes.get(index) ); + if (checkAllChecked) { + checkboxItem.attr("disabled", "disabled"); + } else { + checkboxItem.removeAttr("disabled"); + } + } + + var otherCheckboxes = jQuery('input[name$=radiobtn]'); + for (var i = 0; i < otherCheckboxes.length; i++) { + checkChildrenCheckboxesDisable(allCheckboxes.get(i)); + } +} Index: samigo-app/src/webapp/jsf/questionpool/poolList.jsp =================================================================== --- samigo-app/src/webapp/jsf/questionpool/poolList.jsp (revision 308089) +++ samigo-app/src/webapp/jsf/questionpool/poolList.jsp (working copy) @@ -107,6 +107,14 @@ + + + + + + + Index: samigo-app/src/webapp/jsf/questionpool/transferPool.jsp =================================================================== --- samigo-app/src/webapp/jsf/questionpool/transferPool.jsp (revision 0) +++ samigo-app/src/webapp/jsf/questionpool/transferPool.jsp (working copy) @@ -0,0 +1,57 @@ + + +<%@ page contentType="text/html;charset=utf-8" pageEncoding="utf-8" language="java" %> +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="http://www.sakaiproject.org/samigo" prefix="samigo" %> + + + + + <%= request.getAttribute("html.head") %> + + <h:outputText value="#{questionPoolMessages.transfer_pool}" /> + + + + + + + + "> + + +
+ + + +

+ +

+ + + +
+
+ + +
+ +
+ <%@ include file="/jsf/questionpool/transferPoolTree.jsp" %> +
+ +

+ + +

+
+
+ + +
Index: samigo-app/src/webapp/jsf/questionpool/transferPoolConfirm.jsp =================================================================== --- samigo-app/src/webapp/jsf/questionpool/transferPoolConfirm.jsp (revision 0) +++ samigo-app/src/webapp/jsf/questionpool/transferPoolConfirm.jsp (working copy) @@ -0,0 +1,104 @@ + + +<%@ page contentType="text/html;charset=utf-8" pageEncoding="utf-8" language="java" %> +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="http://www.sakaiproject.org/samigo" prefix="samigo" %> + + + + + + <%= request.getAttribute("html.head") %> + <h:outputText value="#{questionPoolMessages.transfer_pool_confirmation}" /> + + + "> +
+ + + +

+ +

+

+
+ +
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + +

+
+
+ + +
Index: samigo-app/src/webapp/jsf/questionpool/transferPoolInputUser.jsp =================================================================== --- samigo-app/src/webapp/jsf/questionpool/transferPoolInputUser.jsp (revision 0) +++ samigo-app/src/webapp/jsf/questionpool/transferPoolInputUser.jsp (working copy) @@ -0,0 +1,44 @@ + + +<%@ page contentType="text/html;charset=utf-8" pageEncoding="utf-8" language="java" %> +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="http://www.sakaiproject.org/samigo" prefix="samigo" %> + + + + + + <%= request.getAttribute("html.head") %> + <h:outputText value="#{questionPoolMessages.transfer_pool_user}"/> + + "> +
+ + + +

+ +

+

+
+ +
+

+
+ +
+ +

+ + + +

+
+
+ + +
Index: samigo-app/src/webapp/jsf/questionpool/transferPoolTree.jsp =================================================================== --- samigo-app/src/webapp/jsf/questionpool/transferPoolTree.jsp (revision 0) +++ samigo-app/src/webapp/jsf/questionpool/transferPoolTree.jsp (working copy) @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueries.java =================================================================== --- samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueries.java (revision 308089) +++ samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueries.java (working copy) @@ -23,6 +23,8 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; @@ -63,6 +65,9 @@ public class QuestionPoolFacadeQueries extends HibernateDaoSupport implements QuestionPoolFacadeQueriesAPI { private static Log log = LogFactory.getLog(QuestionPoolFacadeQueries.class); + + // SAM-2049 + private static final String VERSION_START = " - "; public QuestionPoolFacadeQueries() { } @@ -1456,4 +1461,200 @@ return agents; } + + // ********************************************** + // ****************** SAM-2049 ****************** + // ********************************************** + + public List getAllPoolsForTransfer(final List selectedPoolIds) { + final HibernateCallback hcb = new HibernateCallback() { + public Object doInHibernate(Session session) throws HibernateException, SQLException { + Query q = session.createQuery("FROM QuestionPoolData a WHERE a.questionPoolId IN (:ids)"); + q. setParameterList("ids", selectedPoolIds); + return q.list(); + }; + }; + List list = getHibernateTemplate().executeFind(hcb); + return list; + } + + private String createQueryString(List poolIds) { + String poolIdQueryString =""; + String prefix = ""; + for (Long poolId: poolIds) { + poolIdQueryString += prefix + poolId.toString(); + prefix = ","; + } + + return poolIdQueryString; + } + + private void updatePool(QuestionPoolData pooldata) { + try { + getHibernateTemplate().update(pooldata); + } catch (Exception e) { + log.warn("problem update the pool name" + e.getMessage()); + } + } + + private String renameDuplicate(String title) { + if (title == null) { + title = ""; + } + + String rename = ""; + int index = title.lastIndexOf(VERSION_START); + + // If it is versioned + if (index > -1) { + String mainPart = ""; + String versionPart = title.substring(index); + if(index > 0) { + mainPart = title.substring(0, index); + } + + int nIndex = index + VERSION_START.length(); + String version = title.substring(nIndex); + + int versionNumber = 0; + try { + versionNumber = Integer.parseInt(version); + if (versionNumber < 2) { + versionNumber = 2; + } + versionPart = VERSION_START + (versionNumber + 1); + rename = mainPart + versionPart; + } catch (NumberFormatException ex) { + rename = title + VERSION_START + "2"; + } + } else { + rename = title + VERSION_START + "2"; + } + + return rename; + } + + public void transferPoolsOwnership(String ownerId, final List transferPoolIds) { + Session session = null; + Connection conn = null; + PreparedStatement statement = null; + + // Get all pools to be transferred + List transferPoolsData = getAllPoolsForTransfer(transferPoolIds); + + // Get poolId which need to remove child-parent relationship + List needUpdatedPoolParentIdList = new ArrayList(); + List updatePoolOwnerIdList = new ArrayList(); + + for (QuestionPoolData poolTransfer : transferPoolsData) { + Long poolId = poolTransfer.getQuestionPoolId(); + updatePoolOwnerIdList.add(poolId); + + // Get remove child-parent relationship list + Long poolIdRemoveParent = poolTransfer.getParentPoolId(); + if (!poolIdRemoveParent.equals(new Long("0")) && !transferPoolIds.contains(poolIdRemoveParent)) { + needUpdatedPoolParentIdList.add(poolId); + } + } + + // updatePoolOwnerIdList will not be empty, so no need to check the size + String updateOwnerIdInPoolTableQueryString = createQueryString(updatePoolOwnerIdList); + + // If all parent-children structure transfer, needUpdatedPoolParentIdList will be empty. + String removeParentPoolString = ""; + if (needUpdatedPoolParentIdList.size() > 0) { + removeParentPoolString = createQueryString(needUpdatedPoolParentIdList); + } + + // I used jdbc update here since I met difficulties using hibernate to update SAM_QUESTIONPOOLACCESS_T. (it used composite-id there) + // For updating SAM_QUESTIONPOOL_T, I can use hibernate but it will have many db calls. (I didn't find an efficient way to bulk update.) So used jdbc here again. + try { + session = getSessionFactory().openSession(); + conn = session.connection(); + boolean autoCommit = conn.getAutoCommit(); + String query = ""; + if (!"".equals(updateOwnerIdInPoolTableQueryString)) { + query = "UPDATE sam_questionpoolaccess_t SET agentid = '" + ownerId +"' WHERE questionpoolid IN (" + updateOwnerIdInPoolTableQueryString + ")" + + " AND accesstypeid = 34"; + statement = conn.prepareStatement(query); + statement.executeUpdate(); + + query = "UPDATE sam_questionpool_t SET ownerid = '" + ownerId + "' WHERE questionpoolid IN (" + updateOwnerIdInPoolTableQueryString + ")"; + statement = conn.prepareStatement(query); + statement.executeUpdate(); + + if (!autoCommit) { + conn.commit(); + } + } + + // if the pool has parent but the parent doesn't transfer, need to remove the child-parent relationship. + if (!"".equals(removeParentPoolString)) { + query = "UPDATE sam_questionpool_t SET parentpoolid = " + 0 + " WHERE questionpoolid IN (" + removeParentPoolString + ")"; + statement = conn.prepareStatement(query); + statement.executeUpdate(); + + if (!autoCommit) { + conn.commit(); + } + } + } catch (Exception ex) { + log.warn(ex.getMessage()); + } finally { + if (statement != null) { + try { + statement.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + if (conn != null) { + try { + conn.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + if (session != null) { + try { + session.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + // Update pool name if there is a duplicate one. + for (QuestionPoolData pooldata : transferPoolsData) { + Long poolId = pooldata.getQuestionPoolId(); + String title = pooldata.getTitle(); + boolean isUnique = poolIsUnique(poolId, title, new Long("0"), ownerId); + if (!isUnique) { + synchronized (title) { + log.debug("Questionpool " + title + " is not unique."); + int count = 0; // Alternate exit condition + + while (!isUnique) { + title = renameDuplicate(title); + log.debug("renameDuplicate (title): " + title); + + // Recheck to confirm that new title is not a dplicate too + isUnique = poolIsUnique(poolId, title, new Long("0"), ownerId); + if (count++ > 99) { + break; // Exit condition in case bug is introduced + } + } + } + + pooldata.setTitle(title); + pooldata.setOwnerId(ownerId); + if (!"".equals(removeParentPoolString) && needUpdatedPoolParentIdList.contains(poolId)) { + pooldata.setParentPoolId(new Long("0")); + } + updatePool(pooldata); + } + } + } } Index: samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueriesAPI.java =================================================================== --- samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueriesAPI.java (revision 308089) +++ samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueriesAPI.java (working copy) @@ -221,5 +221,8 @@ public void removeQuestionPoolAccess(Tree tree, String user, Long questionPoolId, Long accessTypeId); public List getAgentsWithAccess(final Long questionPoolId); + + //SAM-2049 + public void transferPoolsOwnership(String ownerId, List poolIds); } Index: samigo-services/src/java/org/sakaiproject/tool/assessment/services/QuestionPoolService.java =================================================================== --- samigo-services/src/java/org/sakaiproject/tool/assessment/services/QuestionPoolService.java (revision 308089) +++ samigo-services/src/java/org/sakaiproject/tool/assessment/services/QuestionPoolService.java (working copy) @@ -595,4 +595,14 @@ return agents; } + + // SAM-2049 + public void transferPoolsOwnership(String ownerId, List poolIds) { + try { + PersistenceService.getInstance().getQuestionPoolFacadeQueries().transferPoolsOwnership(ownerId, poolIds); + } catch (Exception ex) { + log.error(ex); + throw new RuntimeException(ex); + } + } }