From fe55fa22f8d798e95d811212624f12aec2756c23 Mon Sep 17 00:00:00 2001 From: srosse <stephane.rosse@frentix.com> Date: Tue, 26 Feb 2019 01:11:56 +0100 Subject: [PATCH] OO-3902: fully implements position in curriculum elements --- .../core/gui/components/tree/MenuTree.java | 18 +- .../gui/components/tree/MenuTreeItem.java | 4 + .../gui/components/tree/TreePosition.java | 19 ++ .../editor/MoveCopySubtreeController.java | 25 +-- .../ui/main/EditMembershipController.java | 2 +- .../modules/curriculum/CurriculumElement.java | 8 + .../modules/curriculum/CurriculumService.java | 3 +- .../manager/CurriculumElementDAO.java | 162 +++++++++++-- .../manager/CurriculumServiceImpl.java | 6 +- .../model/CurriculumElementImpl.java | 31 ++- .../curriculum/model/CurriculumImpl.java | 20 ++ .../restapi/CurriculumElementsWebService.java | 2 +- .../CurriculumElementTreeRowComparator.java | 12 +- .../ui/CurriculumComposerController.java | 4 +- .../curriculum/ui/CurriculumElementRow.java | 4 + .../curriculum/ui/CurriculumTreeModel.java | 94 +++++++- .../ui/EditCurriculumElementController.java | 6 +- .../ui/MoveCurriculumElementController.java | 53 ++++- .../CurriculumElementSelectionController.java | 2 +- ...DataCollectionConfigurationController.java | 2 +- ...riculumElementUserSelectionController.java | 2 +- .../org/olat/upgrade/OLATUpgrade_13_2_0.java | 185 +++++++++++++++ .../olat/upgrade/_spring/upgradeContext.xml | 1 + .../upgrade/model/CurriculumElementPos.java | 133 +++++++++++ src/main/resources/META-INF/persistence.xml | 1 + .../database/mysql/alter_13_1_x_to_13_2_0.sql | 9 + .../database/mysql/setupDatabase.sql | 2 + .../oracle/alter_13_1_x_to_13_2_0.sql | 10 + .../database/oracle/setupDatabase.sql | 2 + .../postgresql/alter_13_1_x_to_13_2_0.sql | 8 + .../database/postgresql/setupDatabase.sql | 2 + .../manager/CurriculumElementDAOTest.java | 212 +++++++++++++++++- 32 files changed, 971 insertions(+), 73 deletions(-) rename src/main/java/org/olat/modules/curriculum/{ui => site}/CurriculumElementTreeRowComparator.java (90%) create mode 100644 src/main/java/org/olat/upgrade/OLATUpgrade_13_2_0.java create mode 100644 src/main/java/org/olat/upgrade/model/CurriculumElementPos.java diff --git a/src/main/java/org/olat/core/gui/components/tree/MenuTree.java b/src/main/java/org/olat/core/gui/components/tree/MenuTree.java index 22661d76377..e9e8c47a59e 100644 --- a/src/main/java/org/olat/core/gui/components/tree/MenuTree.java +++ b/src/main/java/org/olat/core/gui/components/tree/MenuTree.java @@ -438,22 +438,18 @@ public class MenuTree extends AbstractComponent { public TreePosition getInsertionPosition() { if(insertionPoint == null) return null; - int position; - TreeNode parent; TreeNode node = treeModel.getNodeById(insertionPoint.getNodeId()); if(insertionPoint.getPosition() == Position.under) { - parent = node; - position = 0; + return new TreePosition(node, 0); } else if(insertionPoint.getPosition() == Position.up) { - parent = (TreeNode)node.getParent(); - position = node.getPosition(); + TreeNode parent = (TreeNode)node.getParent(); + return new TreePosition(parent, node, Position.up, node.getPosition()); } else if(insertionPoint.getPosition() == Position.down) { - parent = (TreeNode)node.getParent(); - position = node.getPosition() + 1; - } else { - return null; + TreeNode parent = (TreeNode)node.getParent(); + int position = node.getPosition() + 1; + return new TreePosition(parent, node, Position.down, position); } - return new TreePosition(parent, position); + return null; } /** diff --git a/src/main/java/org/olat/core/gui/components/tree/MenuTreeItem.java b/src/main/java/org/olat/core/gui/components/tree/MenuTreeItem.java index 0d4362d6d07..331ac85e74b 100644 --- a/src/main/java/org/olat/core/gui/components/tree/MenuTreeItem.java +++ b/src/main/java/org/olat/core/gui/components/tree/MenuTreeItem.java @@ -246,6 +246,10 @@ public class MenuTreeItem extends FormItemImpl { public void setRootVisible(boolean rootVisible) { treeCmp.setRootVisible(rootVisible); } + + public void setInsertTool(boolean enabled) { + treeCmp.enableInsertTool(enabled); + } public void setSelectedNode(TreeNode node) { treeCmp.setSelectedNode(node); diff --git a/src/main/java/org/olat/core/gui/components/tree/TreePosition.java b/src/main/java/org/olat/core/gui/components/tree/TreePosition.java index b12f330ef42..a304593240c 100644 --- a/src/main/java/org/olat/core/gui/components/tree/TreePosition.java +++ b/src/main/java/org/olat/core/gui/components/tree/TreePosition.java @@ -25,6 +25,8 @@ package org.olat.core.gui.components.tree; +import org.olat.core.gui.components.tree.InsertionPoint.Position; + /** * Description:<br> * @@ -33,6 +35,8 @@ package org.olat.core.gui.components.tree; public class TreePosition { private TreeNode parent; + private TreeNode node; + private Position position; private int childpos; // the position of the existing treenode to which to new // node should be prepended (0 = at the beginning, also // works if there are no children yet) @@ -41,6 +45,13 @@ public class TreePosition { this.parent = parent; this.childpos = childpos; } + + public TreePosition(TreeNode parent, TreeNode node, Position position, int childpos) { + this.node = node; + this.parent = parent; + this.childpos = childpos; + this.position = position; + } /** * @return int @@ -55,5 +66,13 @@ public class TreePosition { public TreeNode getParentTreeNode() { return parent; } + + public TreeNode getNode() { + return node; + } + + public Position getPosition() { + return position; + } } diff --git a/src/main/java/org/olat/course/editor/MoveCopySubtreeController.java b/src/main/java/org/olat/course/editor/MoveCopySubtreeController.java index 9a7a8e74865..a960e37d7b9 100644 --- a/src/main/java/org/olat/course/editor/MoveCopySubtreeController.java +++ b/src/main/java/org/olat/course/editor/MoveCopySubtreeController.java @@ -45,26 +45,23 @@ import org.olat.core.gui.control.generic.messages.MessageUIFactory; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.activity.CourseLoggingAction; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; -import org.olat.core.util.nodes.INode; import org.olat.core.util.tree.TreeHelper; import org.olat.core.util.tree.TreeVisitor; -import org.olat.core.util.tree.Visitor; import org.olat.course.CourseFactory; import org.olat.course.CourseModule; import org.olat.course.ICourse; import org.olat.course.nodes.CourseNode; import org.olat.course.tree.CourseEditorTreeNode; import org.olat.util.logging.activity.LoggingResourceable; + /** - * - * Description:<br> - * TODO: guido Class Description for MoveCopySubtreeController - * + * @author: guido */ public class MoveCopySubtreeController extends BasicController { private MenuTree insertTree; - private Link selectButton, cancelButton; + private Link selectButton; + private Link cancelButton; private InsertTreeModel insertModel; private boolean copy; @@ -164,13 +161,10 @@ public class MoveCopySubtreeController extends BasicController { moveCopyFrom.setDirty(true); //mark subtree as dirty - TreeVisitor tv = new TreeVisitor( new Visitor() { - @Override - public void visit(INode node) { - CourseEditorTreeNode cetn = (CourseEditorTreeNode)node; - cetn.setDirty(true); - } - },moveCopyFrom,true); + TreeVisitor tv = new TreeVisitor(node -> { + CourseEditorTreeNode cetn = (CourseEditorTreeNode)node; + cetn.setDirty(true); + }, moveCopyFrom, true); tv.visitAll(); CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); showInfo("movecopynode.info.condmoved"); @@ -182,8 +176,7 @@ public class MoveCopySubtreeController extends BasicController { private CourseNode getCourseNode(TreeNode tn) { CourseEditorTreeNode ctn = (CourseEditorTreeNode) tn; - CourseNode cn = ctn.getCourseNode(); - return cn; + return ctn.getCourseNode(); } private void recursiveCopy(CourseEditorTreeNode copyFrom2, CourseEditorTreeNode insertParent, int pos, boolean firstIteration, ICourse course) { diff --git a/src/main/java/org/olat/group/ui/main/EditMembershipController.java b/src/main/java/org/olat/group/ui/main/EditMembershipController.java index 936c5fda948..1bfbb839cbb 100644 --- a/src/main/java/org/olat/group/ui/main/EditMembershipController.java +++ b/src/main/java/org/olat/group/ui/main/EditMembershipController.java @@ -79,8 +79,8 @@ import org.olat.modules.curriculum.CurriculumElementMembership; import org.olat.modules.curriculum.CurriculumElementStatus; import org.olat.modules.curriculum.CurriculumService; import org.olat.modules.curriculum.model.CurriculumElementMembershipChange; +import org.olat.modules.curriculum.site.CurriculumElementTreeRowComparator; import org.olat.modules.curriculum.ui.CurriculumElementRow; -import org.olat.modules.curriculum.ui.CurriculumElementTreeRowComparator; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryManagedFlag; import org.olat.repository.RepositoryManager; diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumElement.java b/src/main/java/org/olat/modules/curriculum/CurriculumElement.java index b514cfbda48..7dd7c0976be 100644 --- a/src/main/java/org/olat/modules/curriculum/CurriculumElement.java +++ b/src/main/java/org/olat/modules/curriculum/CurriculumElement.java @@ -78,8 +78,16 @@ public interface CurriculumElement extends CurriculumElementShort, CreateInfo, M public void setManagedFlags(CurriculumElementManagedFlag[] flags); + /** + * @return The position of an element as child of a parent element + */ public Long getPos(); + /** + * @return The position of a root element directly under the curriculum + */ + public Long getPosCurriculum(); + public Curriculum getCurriculum(); public CurriculumElement getParent(); diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumService.java b/src/main/java/org/olat/modules/curriculum/CurriculumService.java index 831afb09678..33778826d56 100644 --- a/src/main/java/org/olat/modules/curriculum/CurriculumService.java +++ b/src/main/java/org/olat/modules/curriculum/CurriculumService.java @@ -317,8 +317,9 @@ public interface CurriculumService { * * @param elementToMove The element to move * @param newParent The new parent or null if root + * @param siblingBefore The sibling before the new position or null if at the first place */ - public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent); + public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent, CurriculumElement siblingBefore); /** * The list of members of the specified curriculum element. diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java index 62420ba63df..ffa582cfaa5 100644 --- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java +++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java @@ -61,6 +61,7 @@ import org.olat.modules.curriculum.model.CurriculumElementInfos; import org.olat.modules.curriculum.model.CurriculumElementMembershipImpl; import org.olat.modules.curriculum.model.CurriculumElementSearchInfos; import org.olat.modules.curriculum.model.CurriculumElementSearchParams; +import org.olat.modules.curriculum.model.CurriculumImpl; import org.olat.repository.RepositoryEntryRef; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -101,6 +102,10 @@ public class CurriculumElementDAO { if(parent != null) { ((CurriculumElementImpl)parent).getChildren().add(element); dbInstance.getCurrentEntityManager().merge(parent); + } else { + element.setCurriculumParent(curriculum); + ((CurriculumImpl)curriculum).getRootElements().add(element); + dbInstance.getCurrentEntityManager().merge(curriculum); } element.setMaterializedPathKeys(getMaterializedPathKeys(parent, element)); dbInstance.getCurrentEntityManager().merge(element); @@ -150,6 +155,13 @@ public class CurriculumElementDAO { .getResultList(); } + /** + * Calculate the materialized path from the parent element. + * + * @param parent The parent element (can be null if the element is a root one) + * @param element The curriculum element + * @return The materialized path of the specified element + */ private String getMaterializedPathKeys(CurriculumElement parent, CurriculumElement element) { if(parent != null) { String parentPathOfKeys = parent.getMaterializedPathKeys(); @@ -167,23 +179,74 @@ public class CurriculumElementDAO { return dbInstance.getCurrentEntityManager().merge(element); } - public CurriculumElement move(CurriculumElement element, CurriculumElement newParentElement) { - CurriculumElement parentElement = element.getParent(); + public CurriculumElement move(CurriculumElement elementToMove, CurriculumElement newParentElement, CurriculumElement siblingBefore) { + CurriculumElement parentElement = elementToMove.getParent(); + CurriculumElementImpl element = (CurriculumElementImpl)elementToMove; + if(parentElement == null && newParentElement == null) { - return element;//already root - } else if(parentElement != null && parentElement.equals(newParentElement)) { - return element;//same parent + // reorder curriculum children + + CurriculumImpl curriculum = loadCurriculunByKey(element); + List<CurriculumElement> rootElements = curriculum.getRootElements(); + reorderList(element, rootElements, siblingBefore); + dbInstance.getCurrentEntityManager().merge(curriculum); + } else if(parentElement == null) { + // move from curriculum as root to a curriculum element + + CurriculumImpl curriculum = loadCurriculunByKey(element); + List<CurriculumElement> rootElements = curriculum.getRootElements(); + element.setCurriculumParent(null); + rootElements.remove(element); + curriculum = dbInstance.getCurrentEntityManager().merge(curriculum); + + newParentElement = loadByKey(newParentElement.getKey()); + List<CurriculumElement> newChildren = ((CurriculumElementImpl)newParentElement).getChildren(); + reorderList(element, newChildren, siblingBefore); + element.setParent(newParentElement); + dbInstance.getCurrentEntityManager().merge(newParentElement); + } else if(newParentElement == null) { + // move from a curriculum element to root level + + parentElement = loadByKey(parentElement.getKey()); + List<CurriculumElement> children = ((CurriculumElementImpl)parentElement).getChildren(); + children.remove(element); + element.setParent(null); + dbInstance.getCurrentEntityManager().merge(parentElement); + + CurriculumImpl curriculum = loadCurriculunByKey(element); + element.setCurriculumParent(curriculum); + List<CurriculumElement> rootElements = curriculum.getRootElements(); + reorderList(element, rootElements, siblingBefore); + dbInstance.getCurrentEntityManager().merge(curriculum); + } else if(parentElement.equals(newParentElement)) { + // reorder under the same parent curriculum element + + newParentElement = loadByKey(newParentElement.getKey()); + List<CurriculumElement> newChildren = ((CurriculumElementImpl)newParentElement).getChildren(); + reorderList(element, newChildren, siblingBefore); + dbInstance.getCurrentEntityManager().merge(newParentElement); + } else { + // move from a curriculum element to an other + + parentElement = loadByKey(parentElement.getKey()); + List<CurriculumElement> children = ((CurriculumElementImpl)parentElement).getChildren(); + children.remove(element); + element.setParent(newParentElement); + dbInstance.getCurrentEntityManager().merge(parentElement); + + newParentElement = loadByKey(newParentElement.getKey()); + List<CurriculumElement> newChildren = ((CurriculumElementImpl)newParentElement).getChildren(); + reorderList(element, newChildren, siblingBefore); + dbInstance.getCurrentEntityManager().merge(newParentElement); } String keysPath = element.getMaterializedPathKeys(); - List<CurriculumElement> descendants = getDescendants(element); - CurriculumElementImpl elementImpl = (CurriculumElementImpl)element; - elementImpl.setParent(newParentElement); - elementImpl.setLastModified(new Date()); - String newKeysPath = getMaterializedPathKeys(newParentElement, elementImpl); - elementImpl.setMaterializedPathKeys(newKeysPath); - elementImpl = dbInstance.getCurrentEntityManager().merge(elementImpl); + + element.setLastModified(new Date()); + String newKeysPath = getMaterializedPathKeys(newParentElement, element); + element.setMaterializedPathKeys(newKeysPath); + element = dbInstance.getCurrentEntityManager().merge(element); for(CurriculumElement descendant:descendants) { String descendantKeysPath = descendant.getMaterializedPathKeys(); @@ -195,7 +258,44 @@ public class CurriculumElementDAO { dbInstance.getCurrentEntityManager().merge(descendant); } dbInstance.commit(); - return elementImpl; + return element; + } + + private void reorderList(CurriculumElement element, List<CurriculumElement> elements, CurriculumElement siblingBefore) { + int currentIndex = elements.indexOf(element); + if(siblingBefore == null) { + if(currentIndex >= 0) { + elements.remove(element); + } + elements.add(0, element); + } else if(currentIndex < 0) { + int siblingIndex = elements.indexOf(siblingBefore) + 1; + if(siblingIndex >= 0 && siblingIndex < elements.size()) { + elements.add(siblingIndex, element); + } else { + elements.add(element); + } + } else { + int siblingIndex = elements.indexOf(siblingBefore) + 1; + int newIndex = siblingIndex; + if(currentIndex < siblingIndex) { + newIndex--; + } + elements.remove(element); + elements.add(newIndex, element); + } + } + + private CurriculumImpl loadCurriculunByKey(CurriculumElement element) { + StringBuilder sb = new StringBuilder(128); + sb.append("select cur from curriculum cur") + .append(" where cur.key=:key"); + + List<CurriculumImpl> curriculums = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), CurriculumImpl.class) + .setParameter("key", element.getCurriculum().getKey()) + .getResultList(); + return curriculums == null || curriculums.isEmpty() ? null : curriculums.get(0); } public List<CurriculumElement> loadElements(CurriculumRef curriculum, CurriculumElementStatus[] status) { @@ -556,6 +656,17 @@ public class CurriculumElementDAO { return elements; } + public int countChildren(CurriculumElementRef curriculumElement) { + StringBuilder sb = new StringBuilder(256); + sb.append("select count(el.key) from curriculumelement el") + .append(" where el.parent.key=:elementKey"); + List<Long> count = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Long.class) + .setParameter("elementKey", curriculumElement.getKey()) + .getResultList(); + return count != null && !count.isEmpty() && count.get(0) != null ? count.get(0).intValue() : 0; + } + /** * The method returns all the children, inclusive the marked as deleted. * @@ -568,13 +679,36 @@ public class CurriculumElementDAO { .append(" inner join fetch el.curriculum curriculum") .append(" inner join fetch el.group bGroup") .append(" left join fetch curriculum.organisation org") - .append(" where el.parent.key=:elementKey"); + .append(" where el.parent.key=:elementKey") + .append(" order by el.pos"); return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), CurriculumElement.class) .setParameter("elementKey", curriculumElement.getKey()) .getResultList(); } + /** + * The method returns all the children, inclusive the marked as deleted. + * + * @param curriculumElement The parent element + * @return A list of curriculum elements + */ + public List<CurriculumElement> getChildren(CurriculumRef curriculum) { + StringBuilder sb = new StringBuilder(256); + sb.append("select el from curriculumelement el") + .append(" inner join fetch el.curriculum curriculum") + .append(" inner join fetch el.group bGroup") + .append(" left join fetch curriculum.organisation org") + .append(" where el.curriculumParent.key=:curriculumKey") + .append(" order by el.posCurriculum"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), CurriculumElement.class) + .setParameter("curriculumKey", curriculum.getKey()) + .getResultList(); + } + + + public List<Identity> getMembersIdentity(CurriculumElementRef element, String role) { StringBuilder sb = new StringBuilder(256); sb.append("select ident from curriculumelement el") diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java index 44c2ce4ba07..0f4b7fe9d63 100644 --- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java +++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java @@ -361,10 +361,10 @@ public class CurriculumServiceImpl implements CurriculumService, OrganisationDat public CurriculumElement updateCurriculumElement(CurriculumElement element) { return curriculumElementDao.update(element); } - + @Override - public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent) { - return curriculumElementDao.move(elementToMove, newParent); + public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent, CurriculumElement siblingBefore) { + return curriculumElementDao.move(elementToMove, newParent, siblingBefore); } @Override diff --git a/src/main/java/org/olat/modules/curriculum/model/CurriculumElementImpl.java b/src/main/java/org/olat/modules/curriculum/model/CurriculumElementImpl.java index 61f3fe499bf..b22f6bc4e6b 100644 --- a/src/main/java/org/olat/modules/curriculum/model/CurriculumElementImpl.java +++ b/src/main/java/org/olat/modules/curriculum/model/CurriculumElementImpl.java @@ -26,7 +26,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; @@ -84,6 +83,11 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable { @Column(name="pos", insertable=false, updatable=false) private Long pos; + /** Only used for order by (hibernate hack) */ + @GeneratedValue + @Column(name="pos_cur", insertable=false, updatable=false) + private Long posCurriculum; + @Column(name="c_identifier", nullable=true, insertable=true, updatable=true) private String identifier; @Column(name="c_displayname", nullable=true, insertable=true, updatable=true) @@ -120,8 +124,7 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable { @JoinColumn(name="fk_parent", nullable=true, insertable=true, updatable=true) private CurriculumElement parent; - @OneToMany(targetEntity=CurriculumElementImpl.class, mappedBy="parent", fetch=FetchType.LAZY, - orphanRemoval=true, cascade={CascadeType.REMOVE}) + @OneToMany(targetEntity=CurriculumElementImpl.class, mappedBy="parent", fetch=FetchType.LAZY) @OrderColumn(name="pos") private List<CurriculumElement> children; @@ -129,6 +132,10 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable { @JoinColumn(name="fk_curriculum", nullable=true, insertable=true, updatable=true) private Curriculum curriculum; + @ManyToOne(targetEntity=CurriculumImpl.class) + @JoinColumn(name="fk_curriculum_parent", nullable=true, insertable=true, updatable=true) + private Curriculum curriculumParent; + @ManyToOne(targetEntity=CurriculumElementTypeImpl.class,fetch=FetchType.LAZY,optional=true) @JoinColumn(name="fk_type", nullable=true, insertable=true, updatable=true) private CurriculumElementType type; @@ -346,6 +353,16 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable { public void setPos(Long pos) { this.pos = pos; } + + + + public Long getPosCurriculum() { + return posCurriculum; + } + + public void setPosCurriculum(Long posCurriculum) { + this.posCurriculum = posCurriculum; + } @Override public Group getGroup() { @@ -365,6 +382,14 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable { this.parent = parent; } + public Curriculum getCurriculumParent() { + return curriculumParent; + } + + public void setCurriculumParent(Curriculum curriculumParent) { + this.curriculumParent = curriculumParent; + } + public List<CurriculumElement> getChildren() { if(children == null) { children = new ArrayList<>(); diff --git a/src/main/java/org/olat/modules/curriculum/model/CurriculumImpl.java b/src/main/java/org/olat/modules/curriculum/model/CurriculumImpl.java index 81a90fc7af4..395153824f6 100644 --- a/src/main/java/org/olat/modules/curriculum/model/CurriculumImpl.java +++ b/src/main/java/org/olat/modules/curriculum/model/CurriculumImpl.java @@ -19,7 +19,9 @@ */ package org.olat.modules.curriculum.model; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; @@ -29,6 +31,8 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OrderColumn; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @@ -39,6 +43,7 @@ import org.olat.basesecurity.model.OrganisationImpl; import org.olat.core.id.Organisation; import org.olat.core.id.Persistable; import org.olat.modules.curriculum.Curriculum; +import org.olat.modules.curriculum.CurriculumElement; import org.olat.modules.curriculum.CurriculumManagedFlag; /** @@ -88,6 +93,10 @@ public class CurriculumImpl implements Persistable, Curriculum { @ManyToOne(targetEntity=OrganisationImpl.class,fetch=FetchType.LAZY,optional=true) @JoinColumn(name="fk_organisation", nullable=true, insertable=true, updatable=true) private Organisation organisation; + + @OneToMany(targetEntity=CurriculumElementImpl.class, mappedBy="curriculumParent", fetch=FetchType.LAZY) + @OrderColumn(name="pos_cur") + private List<CurriculumElement> rootElements; @Override public Long getKey() { @@ -214,6 +223,17 @@ public class CurriculumImpl implements Persistable, Curriculum { this.organisation = organisation; } + public List<CurriculumElement> getRootElements() { + if(rootElements == null) { + rootElements = new ArrayList<>(); + } + return rootElements; + } + + public void setRootElements(List<CurriculumElement> rootElements) { + this.rootElements = rootElements; + } + @Override public int hashCode() { return key == null ? 261825789 : key.hashCode(); diff --git a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java index 9951ee53814..3bde07dc0b9 100644 --- a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java +++ b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java @@ -274,7 +274,7 @@ public class CurriculumElementsWebService { } CurriculumElement savedElement = curriculumService.updateCurriculumElement(elementToSave); if(move) { - curriculumService.moveCurriculumElement(savedElement, parentElement); + curriculumService.moveCurriculumElement(savedElement, parentElement, null); dbInstance.commit(); savedElement = curriculumService.getCurriculumElement(savedElement); } diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementTreeRowComparator.java b/src/main/java/org/olat/modules/curriculum/site/CurriculumElementTreeRowComparator.java similarity index 90% rename from src/main/java/org/olat/modules/curriculum/ui/CurriculumElementTreeRowComparator.java rename to src/main/java/org/olat/modules/curriculum/site/CurriculumElementTreeRowComparator.java index c09c39258e0..ebf6ebb49df 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementTreeRowComparator.java +++ b/src/main/java/org/olat/modules/curriculum/site/CurriculumElementTreeRowComparator.java @@ -17,15 +17,17 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.curriculum.ui; +package org.olat.modules.curriculum.site; import java.text.Collator; import java.util.Locale; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTreeNodeComparator; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTreeTableNode; +import org.olat.modules.curriculum.ui.CurriculumElementRow; /** + * This is based of the position of the elements. * * Initial date: 9 août 2018<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com @@ -52,7 +54,13 @@ public class CurriculumElementTreeRowComparator extends FlexiTreeNodeComparator int c = 0; if(parentKey1 == null && parentKey2 == null) { - c = compareCurriculumElements(c1, c2); + Long pos1 = c1.getPosCurriculum(); + Long pos2 = c2.getPosCurriculum(); + if(pos1 == null || pos2 == null) { + c = compareNullObjects(pos1, pos2); + } else { + c = Long.compare(pos1.longValue(), pos2.longValue()); + } } else if(parentKey1 != null && parentKey1.equals(parentKey2)) { Long pos1 = c1.getPos(); Long pos2 = c2.getPos(); diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumComposerController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumComposerController.java index d52b39eece3..bec79e86182 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumComposerController.java +++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumComposerController.java @@ -84,6 +84,7 @@ import org.olat.modules.curriculum.CurriculumSecurityCallback; import org.olat.modules.curriculum.CurriculumService; import org.olat.modules.curriculum.model.CurriculumElementInfos; import org.olat.modules.curriculum.model.CurriculumElementMembershipChange; +import org.olat.modules.curriculum.site.CurriculumElementTreeRowComparator; import org.olat.modules.curriculum.ui.CurriculumComposerTableModel.ElementCols; import org.olat.modules.curriculum.ui.copy.CopySettingsController; import org.olat.modules.curriculum.ui.event.SelectReferenceEvent; @@ -293,9 +294,8 @@ public class CurriculumComposerController extends FormBasicController implements } } Collections.sort(rows, new CurriculumElementTreeRowComparator(getLocale())); - tableModel.setObjects(rows); - tableEl.reset(false, true, true); + tableEl.reset(true, true, true); } private CurriculumElementRow forgeRow(CurriculumElementInfos element) { diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementRow.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementRow.java index 7afff278d42..ccbb3ba83e3 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementRow.java +++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementRow.java @@ -171,6 +171,10 @@ public class CurriculumElementRow implements CurriculumElementRef, FlexiTreeTabl return element.getPos(); } + public Long getPosCurriculum() { + return element.getPosCurriculum(); + } + public long getNumOfResources() { return numOfResources; } diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumTreeModel.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumTreeModel.java index 4bd5b926e36..bd88521b2bc 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumTreeModel.java +++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumTreeModel.java @@ -19,12 +19,19 @@ */ package org.olat.modules.curriculum.ui; +import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.olat.core.gui.components.tree.GenericTreeModel; import org.olat.core.gui.components.tree.GenericTreeNode; +import org.olat.core.gui.components.tree.InsertionPoint.Position; +import org.olat.core.gui.components.tree.InsertionTreeModel; +import org.olat.core.gui.components.tree.TreeNode; +import org.olat.core.util.nodes.INode; +import org.olat.modules.curriculum.Curriculum; import org.olat.modules.curriculum.CurriculumElement; import org.olat.modules.curriculum.CurriculumElementRef; @@ -34,15 +41,27 @@ import org.olat.modules.curriculum.CurriculumElementRef; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class CurriculumTreeModel extends GenericTreeModel { +public class CurriculumTreeModel extends GenericTreeModel implements InsertionTreeModel { private static final long serialVersionUID = 2911319509933144413L; public static final String LEVEL_PREFIX = "cur-el-lev-"; - + + private final List<CurriculumElement> sources; + public CurriculumTreeModel() { + this(null, new ArrayList<CurriculumElement>()); + } + + public CurriculumTreeModel(Curriculum curriculum) { + this(curriculum, new ArrayList<CurriculumElement>()); + } + + public CurriculumTreeModel(Curriculum curriculum, List<CurriculumElement> sources) { GenericTreeNode root = new GenericTreeNode(); - root.setTitle("ROOT"); + String title = curriculum == null ? "ROOT" : curriculum.getDisplayName(); + root.setTitle(title); + this.sources = new ArrayList<>(sources); setRootNode(root); } @@ -79,9 +98,78 @@ public class CurriculumTreeModel extends GenericTreeModel { } } } + + CurriculumElementComparator comparator = new CurriculumElementComparator(); + getRootNode().sort(comparator); + for(GenericTreeNode node:fieldKeyToNode.values()) { + node.sort(comparator); + } + } + + @Override + public boolean isSource(TreeNode node) { + if(node instanceof GenericTreeNode) { + GenericTreeNode gNode = (GenericTreeNode)node; + return gNode.getUserObject() instanceof CurriculumElement && sources.contains(gNode.getUserObject()); + } + return false; } + public boolean isInParentLine(TreeNode node) { + for(INode iteratorNode=node; node.getParent() != null && iteratorNode != null; iteratorNode=iteratorNode.getParent()) { + if(iteratorNode instanceof TreeNode && isSource((TreeNode)iteratorNode)) { + return true; + } + } + return false; + } + + @Override + public Position[] getInsertionPosition(TreeNode node) { + Position[] positions; + if(isSource(node)) { + positions = new Position[0]; + } else if(getRootNode() == node) { + positions = new Position[] { Position.under }; + } else if(isInParentLine(node)) { + positions = new Position[0]; + } else { + positions = new Position[] { Position.up, Position.down, Position.under }; + } + return positions; + } + public static final String nodeKey(CurriculumElementRef element) { return LEVEL_PREFIX + element.getKey(); } + + private static class CurriculumElementComparator implements Comparator<INode> { + + @Override + public int compare(INode n1, INode n2) { + CurriculumElement o1 = (CurriculumElement)((TreeNode)n1).getUserObject(); + CurriculumElement o2 = (CurriculumElement)((TreeNode)n2).getUserObject(); + + Long p1 = null; + Long p2 = null; + + if(o1.getParent() == null && o2.getParent() == null) { + p1 = o1.getPosCurriculum(); + p2 = o2.getPosCurriculum(); + } else if(o1.getParent() != null && o2.getParent() != null) { + p1 = o1.getPos(); + p2 = o2.getPos(); + } + + int c = 0; + if(p1 != null && p2 != null) { + c = p1.compareTo(p2); + } else if(p1 != null) { + c = -1; + } else if(p2 != null) { + c = 1; + } + return c; + } + } } diff --git a/src/main/java/org/olat/modules/curriculum/ui/EditCurriculumElementController.java b/src/main/java/org/olat/modules/curriculum/ui/EditCurriculumElementController.java index 65954c38a8f..114694fc101 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/EditCurriculumElementController.java +++ b/src/main/java/org/olat/modules/curriculum/ui/EditCurriculumElementController.java @@ -24,6 +24,7 @@ import java.util.Date; import java.util.List; import java.util.Set; +import org.olat.core.commons.persistence.DB; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -91,6 +92,8 @@ public class EditCurriculumElementController extends FormBasicController { private CurriculumElement parentElement; private final CurriculumSecurityCallback secCallback; + @Autowired + private DB dbInstance; @Autowired private CurriculumService curriculumService; @@ -375,7 +378,8 @@ public class EditCurriculumElementController extends FormBasicController { element.setLectures(lectures); element = curriculumService.updateCurriculumElement(element); } - + + dbInstance.commitAndCloseSession(); // need to relaod properly the tree fireEvent(ureq, Event.DONE_EVENT); } diff --git a/src/main/java/org/olat/modules/curriculum/ui/MoveCurriculumElementController.java b/src/main/java/org/olat/modules/curriculum/ui/MoveCurriculumElementController.java index 991caa6e1e5..ce21de00086 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/MoveCurriculumElementController.java +++ b/src/main/java/org/olat/modules/curriculum/ui/MoveCurriculumElementController.java @@ -27,12 +27,15 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.olat.core.commons.persistence.DB; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.tree.GenericTreeNode; +import org.olat.core.gui.components.tree.InsertionPoint.Position; import org.olat.core.gui.components.tree.MenuTreeItem; import org.olat.core.gui.components.tree.TreeNode; +import org.olat.core.gui.components.tree.TreePosition; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; @@ -54,13 +57,15 @@ import org.springframework.beans.factory.annotation.Autowired; public class MoveCurriculumElementController extends FormBasicController { private MenuTreeItem curriculumTreeEl; - private final CurriculumTreeModel curriculumModel = new CurriculumTreeModel(); + private final CurriculumTreeModel curriculumModel; private final Curriculum curriculum; private Set<CurriculumElementType> allowedTypes; private List<CurriculumElement> curriculumElementsToMove; private Set<TreeNode> targetableNodes = new HashSet<>(); + @Autowired + private DB dbInstance; @Autowired private CurriculumService curriculumService; @@ -69,6 +74,7 @@ public class MoveCurriculumElementController extends FormBasicController { super(ureq, wControl, "move_curriculum_element"); this.curriculum = curriculum; this.curriculumElementsToMove = new ArrayList<>(curriculumElementsToMove); + curriculumModel = new CurriculumTreeModel(curriculum, curriculumElementsToMove); allowedTypes = getAllowedTypes(); initForm(ureq); @@ -80,7 +86,8 @@ public class MoveCurriculumElementController extends FormBasicController { curriculumTreeEl = uifactory.addTreeMultiselect("elements", null, formLayout, curriculumModel, this); curriculumTreeEl.setMultiSelect(false); - curriculumTreeEl.setRootVisible(false); + curriculumTreeEl.setRootVisible(true); + curriculumTreeEl.setInsertTool(true); uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl()); uifactory.addFormSubmitButton("move.element", formLayout); @@ -229,18 +236,44 @@ public class MoveCurriculumElementController extends FormBasicController { if(isParent()) { showWarning("error.target.no.parent"); } else { - TreeNode selectedNode = curriculumTreeEl.getSelectedNode(); - if(selectedNode == curriculumModel.getRootNode()) { - for(CurriculumElement elementToMove:curriculumElementsToMove) { - curriculumService.moveCurriculumElement(elementToMove, null); + TreePosition tp = curriculumTreeEl.getInsertionPosition(); + TreeNode parentNode = tp.getParentTreeNode(); + CurriculumElement newParent = (CurriculumElement)parentNode.getUserObject(); + if(newParent == curriculumModel.getRootNode()) { + newParent = null; // root element + } + + CurriculumElement siblingBefore; + if(tp.getNode() == null) { + siblingBefore = null; + } else if(tp.getPosition() == Position.down) { + siblingBefore = (CurriculumElement)tp.getNode().getUserObject(); + } else if(tp.getPosition() == Position.up) { + TreeNode selectedNode = tp.getNode(); + int index = -1; + for(int i=tp.getParentTreeNode().getChildCount(); i-->0; ) { + if(selectedNode.equals(tp.getParentTreeNode().getChildAt(i))) { + index = i; + break; + } } - } else { - CurriculumElement newParent = (CurriculumElement)selectedNode.getUserObject(); - for(CurriculumElement elementToMove:curriculumElementsToMove) { - curriculumService.moveCurriculumElement(elementToMove, newParent); + + if(index == 0) { + siblingBefore = null; + } else { + INode nodeBefore = tp.getParentTreeNode().getChildAt(index -1); + siblingBefore = (CurriculumElement)((TreeNode)nodeBefore).getUserObject(); } + } else { + siblingBefore = null; + } + + for(CurriculumElement elementToMove:curriculumElementsToMove) { + curriculumService.moveCurriculumElement(elementToMove, newParent, siblingBefore); + dbInstance.commit(); } } + dbInstance.commitAndCloseSession(); fireEvent(ureq, Event.DONE_EVENT); } } diff --git a/src/main/java/org/olat/modules/quality/generator/ui/CurriculumElementSelectionController.java b/src/main/java/org/olat/modules/quality/generator/ui/CurriculumElementSelectionController.java index 9711b9f1bd4..c6ab7bc2540 100644 --- a/src/main/java/org/olat/modules/quality/generator/ui/CurriculumElementSelectionController.java +++ b/src/main/java/org/olat/modules/quality/generator/ui/CurriculumElementSelectionController.java @@ -108,7 +108,7 @@ class CurriculumElementSelectionController extends FormBasicController { if (curriculum != null) { List<CurriculumElement> curriculumElements = curriculumService.getCurriculumElements(curriculum, CurriculumElementStatus.notDeleted()); - CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(); + CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(curriculum); curriculumTreeModel.loadTreeModel(curriculumElements); KeysValues curriculumElementKeysValues = QualityUIFactory .getCurriculumElementKeysValues(curriculumTreeModel, null); diff --git a/src/main/java/org/olat/modules/quality/ui/DataCollectionConfigurationController.java b/src/main/java/org/olat/modules/quality/ui/DataCollectionConfigurationController.java index c3a0220a7b0..bf6605e1758 100644 --- a/src/main/java/org/olat/modules/quality/ui/DataCollectionConfigurationController.java +++ b/src/main/java/org/olat/modules/quality/ui/DataCollectionConfigurationController.java @@ -321,7 +321,7 @@ public class DataCollectionConfigurationController extends FormBasicController { if (topicCurriculum != null) { topicCurriculumEl.select(QualityUIFactory.getCurriculumKey(topicCurriculum), true); List<CurriculumElement> curriculumElements = curriculumService.getCurriculumElements(topicCurriculum, CurriculumElementStatus.values()); - CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(); + CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(topicCurriculum); curriculumTreeModel.loadTreeModel(curriculumElements); KeysValues curriculumElementKeysValues = QualityUIFactory.getCurriculumElementKeysValues(curriculumTreeModel, topicCurriculumElement); topicCurriculumElementEl.setKeysAndValues(curriculumElementKeysValues.getKeys(), curriculumElementKeysValues.getValues(), null); diff --git a/src/main/java/org/olat/modules/quality/ui/wizard/AddCurriculumElementUserSelectionController.java b/src/main/java/org/olat/modules/quality/ui/wizard/AddCurriculumElementUserSelectionController.java index 49649e550f6..2db8e642bb1 100644 --- a/src/main/java/org/olat/modules/quality/ui/wizard/AddCurriculumElementUserSelectionController.java +++ b/src/main/java/org/olat/modules/quality/ui/wizard/AddCurriculumElementUserSelectionController.java @@ -106,7 +106,7 @@ public class AddCurriculumElementUserSelectionController extends StepFormBasicCo Curriculum curriculum = curriculumService.getCurriculum(curriculumRef); if (curriculum != null) { List<CurriculumElement> curriculumElements = curriculumService.getCurriculumElements(curriculum, CurriculumElementStatus.notDeleted()); - CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(); + CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(curriculum); curriculumTreeModel.loadTreeModel(curriculumElements); KeysValues curriculumElementKeysValues = QualityUIFactory.getCurriculumElementKeysValues(curriculumTreeModel, null); curriculumElementEl.setKeysAndValues(curriculumElementKeysValues.getKeys(), curriculumElementKeysValues.getValues(), null); diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_13_2_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_13_2_0.java new file mode 100644 index 00000000000..fedb17b4817 --- /dev/null +++ b/src/main/java/org/olat/upgrade/OLATUpgrade_13_2_0.java @@ -0,0 +1,185 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.upgrade; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.olat.core.commons.persistence.DB; +import org.olat.upgrade.model.CurriculumElementPos; +import org.springframework.beans.factory.annotation.Autowired; + +import edu.emory.mathcs.backport.java.util.Collections; + +/** + * + * Initial date: 4 janv. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class OLATUpgrade_13_2_0 extends OLATUpgrade { + + private static final String VERSION = "OLAT_13.2.0"; + private static final String UPDATE_CURRICULUM_CHILDREN = "UPDATE CURRICULUM CHILDREN"; + + @Autowired + private DB dbInstance; + + public OLATUpgrade_13_2_0() { + super(); + } + + @Override + public String getVersion() { + return VERSION; + } + + @Override + public boolean doPreSystemInitUpgrade(UpgradeManager upgradeManager) { + return false; + } + + @Override + public boolean doPostSystemInitUpgrade(UpgradeManager upgradeManager) { + UpgradeHistoryData uhd = upgradeManager.getUpgradesHistory(VERSION); + if (uhd == null) { + // has never been called, initialize + uhd = new UpgradeHistoryData(); + } else if (uhd.isInstallationComplete()) { + return false; + } + + boolean allOk = true; + allOk &= updateCurriculumElementChildren(upgradeManager, uhd); + + uhd.setInstallationComplete(allOk); + upgradeManager.setUpgradesHistory(uhd, VERSION); + if(allOk) { + log.audit("Finished OLATUpgrade_13_2_0 successfully!"); + } else { + log.audit("OLATUpgrade_13_2_0 not finished, try to restart OpenOLAT!"); + } + return allOk; + } + + /** + * Recalculate pos of children + * + * @param upgradeManager The upgrade manager + * @param uhd The upgrade history + * @return true if successful + */ + private boolean updateCurriculumElementChildren(UpgradeManager upgradeManager, UpgradeHistoryData uhd) { + boolean allOk = true; + if (!uhd.getBooleanDataValue(UPDATE_CURRICULUM_CHILDREN)) { + List<CurriculumElementPos> elements = getCurriculumElements(); + Map<Long, List<CurriculumElementPos>> parentToChildren = new HashMap<>(); + Map<Long, List<CurriculumElementPos>> curriculumToChildren = new HashMap<>(); + + // pre warm the maps + for(CurriculumElementPos element:elements) { + parentToChildren.put(element.getKey(), new ArrayList<>()); + } + for(CurriculumElementPos element:elements) { + curriculumToChildren.put(element.getCurriculumKey(), new ArrayList<>()); + } + + // fill the data + for(CurriculumElementPos element:elements) { + if(element.getParentKey() != null) { + parentToChildren.get(element.getParentKey()).add(element); + } else { + curriculumToChildren.get(element.getCurriculumKey()).add(element); + } + } + + // reorder curriculum elements + for(List<CurriculumElementPos> children:parentToChildren.values()) { + if(children.isEmpty()) continue; + // reorder the children + Collections.sort(children, new PosComparator()); + // assign a position + for(int i=0; i<children.size(); i++) { + children.get(i).setPos(Long.valueOf(i)); + } + // merge + for(CurriculumElementPos child:children) { + dbInstance.getCurrentEntityManager().merge(child); + } + dbInstance.commit(); + } + dbInstance.commitAndCloseSession(); + + // reorder root elements + for(List<CurriculumElementPos> children:curriculumToChildren.values()) { + if(children.isEmpty()) continue; + // reorder the roots + Collections.sort(children, new PosComparator()); + // assign a position under curriculum + for(int i=0; i<children.size(); i++) { + children.get(i).setPosCurriculum(Long.valueOf(i)); + children.get(i).setParentCurriculumKey(children.get(i).getCurriculumKey()); + } + // merge + for(CurriculumElementPos child:children) { + dbInstance.getCurrentEntityManager().merge(child); + } + dbInstance.commit(); + } + dbInstance.commitAndCloseSession(); + + + uhd.setBooleanDataValue(UPDATE_CURRICULUM_CHILDREN, allOk); + upgradeManager.setUpgradesHistory(uhd, VERSION); + } + return allOk; + } + + private List<CurriculumElementPos> getCurriculumElements() { + String q = "select curEl from curriculumelementpos as curEl"; + return dbInstance.getCurrentEntityManager() + .createQuery(q, CurriculumElementPos.class) + .getResultList(); + } + + private static class PosComparator implements Comparator<CurriculumElementPos> { + @Override + public int compare(CurriculumElementPos o1, CurriculumElementPos o2) { + Long p1 = o1.getPos(); + Long p2 = o2.getPos(); + + int c = 0; + if(p1 != null && p2 != null) { + c = p1.compareTo(p2); + } else if(p1 != null) { + c = 1; + } else if(p2 != null) { + c = -1; + } + if(c == 0) { + c = o1.getKey().compareTo(o2.getKey()); + } + return c; + } + } +} diff --git a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml index c3090d77681..397770715be 100644 --- a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml +++ b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml @@ -47,6 +47,7 @@ <bean id="upgrade_13_0_0_beta7" class="org.olat.upgrade.OLATUpgrade_13_0_0_beta7"/> <bean id="upgrade_13_0_0_beta9" class="org.olat.upgrade.OLATUpgrade_13_0_0_beta9"/> <bean id="upgrade_13_1_0" class="org.olat.upgrade.OLATUpgrade_13_1_0"/> + <bean id="upgrade_13_2_0" class="org.olat.upgrade.OLATUpgrade_13_2_0"/> </list> </property> </bean> diff --git a/src/main/java/org/olat/upgrade/model/CurriculumElementPos.java b/src/main/java/org/olat/upgrade/model/CurriculumElementPos.java new file mode 100644 index 00000000000..692959490fb --- /dev/null +++ b/src/main/java/org/olat/upgrade/model/CurriculumElementPos.java @@ -0,0 +1,133 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.upgrade.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.olat.core.id.Persistable; +import org.olat.modules.curriculum.model.CurriculumElementImpl; + +/** + * Only use to rewrite the position of curriculum elements. + * + * Initial date: 25 févr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Entity(name="curriculumelementpos") +@Table(name="o_cur_curriculum_element") +public class CurriculumElementPos implements Persistable { + + private static final long serialVersionUID = 547658342562646552L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Column(name="pos", insertable=true, updatable=true) + private Long pos; + @Column(name="fk_parent", nullable=true, insertable=false, updatable=false) + private Long parentKey; + + @Column(name="pos_cur", insertable=true, updatable=true) + private Long posCurriculum; + @Column(name="fk_curriculum", nullable=true, insertable=false, updatable=false) + private Long curriculumKey; + @Column(name="fk_curriculum_parent", nullable=true, insertable=false, updatable=true) + private Long parentCurriculumKey; + + + @Override + public Long getKey() { + return key; + } + + public void setKey(Long key) { + this.key = key; + } + + public Long getPos() { + return pos; + } + + public void setPos(Long pos) { + this.pos = pos; + } + + public Long getParentKey() { + return parentKey; + } + + public void setParentKey(Long parentKey) { + this.parentKey = parentKey; + } + + public Long getPosCurriculum() { + return posCurriculum; + } + + public void setPosCurriculum(Long posCurriculum) { + this.posCurriculum = posCurriculum; + } + + public Long getCurriculumKey() { + return curriculumKey; + } + + public void setCurriculumKey(Long curriculumKey) { + this.curriculumKey = curriculumKey; + } + + public Long getParentCurriculumKey() { + return parentCurriculumKey; + } + + public void setParentCurriculumKey(Long parentCurriculumKey) { + this.parentCurriculumKey = parentCurriculumKey; + } + + @Override + public int hashCode() { + return key == null ? 28562153 : key.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(obj == this) { + return true; + } + if(obj instanceof CurriculumElementImpl) { + CurriculumElementImpl el = (CurriculumElementImpl)obj; + return getKey() != null && getKey().equals(el.getKey()); + } + return false; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } +} diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index d1713575036..3546993e17b 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -56,6 +56,7 @@ <class>org.olat.upgrade.model.InvitationUpgrade</class> <class>org.olat.upgrade.model.UpgradeTaxonomyLevel</class> <class>org.olat.upgrade.model.UpgradeQuestionItem</class> + <class>org.olat.upgrade.model.CurriculumElementPos</class> <!-- End upgraders mapping --> diff --git a/src/main/resources/database/mysql/alter_13_1_x_to_13_2_0.sql b/src/main/resources/database/mysql/alter_13_1_x_to_13_2_0.sql index f9b111b7683..2a3e1434960 100644 --- a/src/main/resources/database/mysql/alter_13_1_x_to_13_2_0.sql +++ b/src/main/resources/database/mysql/alter_13_1_x_to_13_2_0.sql @@ -66,3 +66,12 @@ alter table o_vid_metadata add vid_url varchar(512); alter table o_cur_curriculum_element add c_lectures varchar(16); alter table o_cur_element_type add c_lectures varchar(16); + +-- curriculum element +alter table o_cur_curriculum_element add pos_cur bigint; +alter table o_cur_curriculum_element add fk_curriculum_parent bigint; +alter table o_cur_curriculum_element add constraint cur_el_to_pcur_idx foreign key (fk_curriculum_parent) references o_cur_curriculum (id); + + + + diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql index 6cb21def5ba..28bf0d20d4d 100644 --- a/src/main/resources/database/mysql/setupDatabase.sql +++ b/src/main/resources/database/mysql/setupDatabase.sql @@ -2631,6 +2631,7 @@ create table o_cur_curriculum_element ( creationdate datetime not null, lastmodified datetime not null, pos bigint, + pos_cur bigint, c_identifier varchar(64), c_displayname varchar(255) not null, c_description mediumtext, @@ -2645,6 +2646,7 @@ create table o_cur_curriculum_element ( fk_group bigint not null, fk_parent bigint, fk_curriculum bigint not null, + fk_curriculum_parentbigint not null, fk_type bigint, primary key (id) ); diff --git a/src/main/resources/database/oracle/alter_13_1_x_to_13_2_0.sql b/src/main/resources/database/oracle/alter_13_1_x_to_13_2_0.sql index 495a760fcb4..2d23ecee159 100644 --- a/src/main/resources/database/oracle/alter_13_1_x_to_13_2_0.sql +++ b/src/main/resources/database/oracle/alter_13_1_x_to_13_2_0.sql @@ -63,3 +63,13 @@ alter table o_vid_metadata add vid_url varchar(512); -- lectures alter table o_cur_curriculum_element add c_lectures varchar(16); alter table o_cur_element_type add c_lectures varchar(16); + + +-- curriculum element +alter table o_cur_curriculum_element add pos_cur number(20); +alter table o_cur_curriculum_element add fk_curriculum_parent number(20); +alter table o_cur_curriculum_element add constraint cur_el_to_pcur_idx foreign key (fk_curriculum_parent) references o_cur_curriculum (id); +create index idx_cur_el_to_pcur_idx on o_cur_curriculum_element (fk_curriculum_parent); + + + diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql index 23d3c0ab8bf..560fa0cc9ed 100644 --- a/src/main/resources/database/oracle/setupDatabase.sql +++ b/src/main/resources/database/oracle/setupDatabase.sql @@ -2713,6 +2713,7 @@ create table o_cur_curriculum_element ( creationdate date not null, lastmodified date not null, pos number(20), + pos_cur number(20), c_identifier varchar(64), c_displayname varchar(255) not null, c_description CLOB, @@ -2727,6 +2728,7 @@ create table o_cur_curriculum_element ( fk_group number(20) not null, fk_parent number(20), fk_curriculum number(20) not null, + fk_curriculum_parent number(20), fk_type number(20), primary key (id) ); diff --git a/src/main/resources/database/postgresql/alter_13_1_x_to_13_2_0.sql b/src/main/resources/database/postgresql/alter_13_1_x_to_13_2_0.sql index 1719756473b..8917b2f3f81 100644 --- a/src/main/resources/database/postgresql/alter_13_1_x_to_13_2_0.sql +++ b/src/main/resources/database/postgresql/alter_13_1_x_to_13_2_0.sql @@ -65,3 +65,11 @@ alter table o_cur_curriculum_element add c_lectures varchar(16); alter table o_cur_element_type add c_lectures varchar(16); +-- curriculum element +alter table o_cur_curriculum_element add pos_cur int8; +alter table o_cur_curriculum_element add fk_curriculum_parent int8; +alter table o_cur_curriculum_element add constraint cur_el_to_pcur_idx foreign key (fk_curriculum_parent) references o_cur_curriculum (id); +create index idx_cur_el_to_pcur_idx on o_cur_curriculum_element (fk_curriculum_parent); + + + diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql index 678cfbb0cc9..3352ab6ae2e 100644 --- a/src/main/resources/database/postgresql/setupDatabase.sql +++ b/src/main/resources/database/postgresql/setupDatabase.sql @@ -2657,6 +2657,7 @@ create table o_cur_curriculum_element ( creationdate timestamp not null, lastmodified timestamp not null, pos int8, + pos_cur int8, c_identifier varchar(64), c_displayname varchar(255) not null, c_description text, @@ -2671,6 +2672,7 @@ create table o_cur_curriculum_element ( fk_group int8 not null, fk_parent int8, fk_curriculum int8 not null, + fk_curriculum_parent int8, fk_type int8, primary key (id) ); diff --git a/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java b/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java index 24bdbb584a3..2ff51111dbe 100644 --- a/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java +++ b/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java @@ -45,6 +45,7 @@ import org.olat.modules.curriculum.CurriculumRoles; import org.olat.modules.curriculum.CurriculumService; import org.olat.modules.curriculum.model.CurriculumElementImpl; import org.olat.modules.curriculum.model.CurriculumElementInfos; +import org.olat.modules.curriculum.model.CurriculumImpl; import org.olat.repository.RepositoryEntry; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; @@ -90,6 +91,42 @@ public class CurriculumElementDAOTest extends OlatTestCase { Assert.assertEquals(type, element.getType()); } + /** + * Check if the root elements come in curriculum list + */ + @Test + public void createCurriculumElement_rootElement() { + Curriculum curriculum = curriculumDao.createAndPersist("Cur-for-el-1", "Curriculum for element", "Curriculum", null); + CurriculumElementType type = curriculumElementTypeDao.createCurriculumElementType("typ-for-cur-el-1", "Type for", "First element", "AC-234"); + CurriculumElement root1 = curriculumElementDao.createCurriculumElement("Element-1", "1. Element", new Date(), new Date(), null, + type, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + Assert.assertNotNull(root1); + dbInstance.commit(); + curriculum = curriculumDao.loadByKey(curriculum.getKey()); + CurriculumElement root2 = curriculumElementDao.createCurriculumElement("Element-2", "2. Element", new Date(), new Date(), null, + type, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + dbInstance.commit(); + curriculum = curriculumDao.loadByKey(curriculum.getKey()); + CurriculumElement root3 = curriculumElementDao.createCurriculumElement("Element-3", "3. Element", new Date(), new Date(), null, + type, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element3_1 = curriculumElementDao.createCurriculumElement("Element-2", "2. Element", new Date(), new Date(), root3, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + dbInstance.commitAndCloseSession(); + + //check the curriculum to elements list + CurriculumImpl reloadedCurriculum = (CurriculumImpl)curriculumDao.loadByKey(curriculum.getKey()); + List<CurriculumElement> rootElements = reloadedCurriculum.getRootElements(); + Assert.assertEquals(3, rootElements.size()); + Assert.assertEquals(root1, rootElements.get(0)); + Assert.assertEquals(root2, rootElements.get(1)); + Assert.assertEquals(root3, rootElements.get(2)); + + //check the element to elements list + List<CurriculumElement> root3Children = curriculumElementDao.getChildren(root3); + Assert.assertEquals(1, root3Children.size()); + Assert.assertEquals(element3_1, root3Children.get(0)); + } + @Test public void loadByKey() { Curriculum curriculum = curriculumDao.createAndPersist("Cur-for-el-2", "Curriculum for element", "Curriculum", null); @@ -358,7 +395,7 @@ public class CurriculumElementDAOTest extends OlatTestCase { } @Test - public void moveCurriculumElement() { + public void moveCurriculumElement_elementToOtherElement() { Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-7", "Curriculum for element", "Curriculum", null); CurriculumElement rootElement = curriculumElementDao.createCurriculumElement("Element-7", "7. Element", null, null, null, null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); @@ -375,7 +412,7 @@ public class CurriculumElementDAOTest extends OlatTestCase { dbInstance.commitAndCloseSession(); // move element1_1 under element2 - curriculumElementDao.move(element1_1, element2); + curriculumElementDao.move(element1_1, element2, null); dbInstance.commit(); // check parent line of element1_1_2 @@ -397,6 +434,177 @@ public class CurriculumElementDAOTest extends OlatTestCase { Assert.assertTrue(descendants1_1.contains(element1_1_2)); } + @Test + public void moveCurriculumElement_underSameElement() { + Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-8", "Curriculum for element", "Curriculum", null); + CurriculumElement rootElement = curriculumElementDao.createCurriculumElement("Element-8", "8. Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1 = curriculumElementDao.createCurriculumElement("Element-8-1-1", "8.1.1 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_2 = curriculumElementDao.createCurriculumElement("Element-8-1-2", "8.1.2 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_3 = curriculumElementDao.createCurriculumElement("Element-8-1-3", "8.1.3 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_4 = curriculumElementDao.createCurriculumElement("Element-8-1-4", "8.1.4 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_5 = curriculumElementDao.createCurriculumElement("Element-8-1-5", "8.1.5 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + dbInstance.commitAndCloseSession(); + + // move element1_1 at third posistion + curriculumElementDao.move(element1_2, rootElement, element1_4); + dbInstance.commit(); + + CurriculumElementImpl element = (CurriculumElementImpl)curriculumElementDao.loadByKey(rootElement.getKey()); + List<CurriculumElement> children = element.getChildren(); + Assert.assertEquals(children.get(0), element1_1); + Assert.assertEquals(children.get(1), element1_3); + Assert.assertEquals(children.get(2), element1_4); + Assert.assertEquals(children.get(3), element1_2); + Assert.assertEquals(children.get(4), element1_5); + } + + @Test + public void moveCurriculumElement_underSameElement_v2() { + Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-8", "Curriculum for element", "Curriculum", null); + CurriculumElement rootElement = curriculumElementDao.createCurriculumElement("Element-8", "8. Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1 = curriculumElementDao.createCurriculumElement("Element-8-1-1", "8.1.1 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_2 = curriculumElementDao.createCurriculumElement("Element-8-1-2", "8.1.2 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_3 = curriculumElementDao.createCurriculumElement("Element-8-1-3", "8.1.3 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_4 = curriculumElementDao.createCurriculumElement("Element-8-1-4", "8.1.4 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_5 = curriculumElementDao.createCurriculumElement("Element-8-1-5", "8.1.5 Element", null, null, rootElement, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + dbInstance.commitAndCloseSession(); + + // move element1_5 at third position + curriculumElementDao.move(element1_5, rootElement, element1_2); + dbInstance.commit(); + + CurriculumElementImpl element = (CurriculumElementImpl)curriculumElementDao.loadByKey(rootElement.getKey()); + List<CurriculumElement> children = element.getChildren(); + Assert.assertEquals(element1_1, children.get(0)); + Assert.assertEquals(element1_2, children.get(1)); + Assert.assertEquals(element1_5, children.get(2)); + Assert.assertEquals(element1_3, children.get(3)); + Assert.assertEquals(element1_4, children.get(4)); + } + + @Test + public void moveCurriculumElement_rootElement() { + Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-", "Curriculum for element", "Curriculum", null); + + CurriculumElement element1 = curriculumElementDao.createCurriculumElement("Element-9-1", "9.1 Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element2 = curriculumElementDao.createCurriculumElement("Element-9-2", "9.2 Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element3 = curriculumElementDao.createCurriculumElement("Element-9-3", "9.3 Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element4 = curriculumElementDao.createCurriculumElement("Element-9-4", "9.4 Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element5 = curriculumElementDao.createCurriculumElement("Element-9-5", "9.5 Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + dbInstance.commitAndCloseSession(); + + // move element1_1 under element2 + curriculumElementDao.move(element2, null, element4); + dbInstance.commit(); + + // check parent line of element1_1_2 + CurriculumImpl reloadedCurriculum = (CurriculumImpl)curriculumDao.loadByKey(curriculum.getKey()); + List<CurriculumElement> rootElements = reloadedCurriculum.getRootElements(); + Assert.assertEquals(element1, rootElements.get(0)); + Assert.assertEquals(element3, rootElements.get(1)); + Assert.assertEquals(element4, rootElements.get(2)); + Assert.assertEquals(element2, rootElements.get(3)); + Assert.assertEquals(element5, rootElements.get(4)); + } + + @Test + public void moveCurriculumElement_rootToElement() { + Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-7", "Curriculum for element", "Curriculum", null); + CurriculumElement rootElement1 = curriculumElementDao.createCurriculumElement("Element-10-1", "10.1 Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1 = curriculumElementDao.createCurriculumElement("Element-10-1-1", "10.1.1 Element", null, null, rootElement1, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1_1 = curriculumElementDao.createCurriculumElement("Element-10-1-1-1", "10.1.1.1 Element", null, null, element1_1, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1_2 = curriculumElementDao.createCurriculumElement("Element-10-1-1-2", "10.1.1.2 Element", null, null, element1_1, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_2 = curriculumElementDao.createCurriculumElement("Element-10-1-2", "10.1.2 Element", null, null, rootElement1, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + dbInstance.commit(); + Assert.assertNotNull(element1_2); + + curriculum = curriculumDao.loadByKey(curriculum.getKey()); + CurriculumElement rootElement2 = curriculumElementDao.createCurriculumElement("Element-10-2", "10.2 Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + dbInstance.commitAndCloseSession(); + + // move element1_1 under element2 + CurriculumElement reloadedElement1_1 = curriculumElementDao.loadByKey(element1_1.getKey()); + curriculumElementDao.move(rootElement2, reloadedElement1_1, element1_1_1); + dbInstance.commit(); + + // check children element1_1 + CurriculumElementImpl reloadElement1_1 = (CurriculumElementImpl)curriculumElementDao.loadByKey(element1_1.getKey()); + List<CurriculumElement> element11children = reloadElement1_1.getChildren(); + Assert.assertEquals(3, element11children.size()); + Assert.assertEquals(element1_1_1, element11children.get(0)); + Assert.assertEquals(rootElement2, element11children.get(1)); + Assert.assertEquals(element1_1_2, element11children.get(2)); + + + // check children curriculum + CurriculumImpl reloadedCurriculum = (CurriculumImpl)curriculumDao.loadByKey(curriculum.getKey()); + List<CurriculumElement> rootElements = reloadedCurriculum.getRootElements(); + Assert.assertEquals(1, rootElements.size()); + Assert.assertEquals(rootElement1, rootElements.get(0)); + } + + @Test + public void moveCurriculumElement_elementToRoot() { + Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-7", "Curriculum for element", "Curriculum", null); + CurriculumElement rootElement1 = curriculumElementDao.createCurriculumElement("Element-10-1", "10.1 Element", null, null, null, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1 = curriculumElementDao.createCurriculumElement("Element-10-1-1", "10.1.1 Element", null, null, rootElement1, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1_1 = curriculumElementDao.createCurriculumElement("Element-10-1-1-1", "10.1.1.1 Element", null, null, element1_1, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1_2 = curriculumElementDao.createCurriculumElement("Element-10-1-1-2", "10.1.1.2 Element", null, null, element1_1, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + CurriculumElement element1_1_3 = curriculumElementDao.createCurriculumElement("Element-10-1-1-3", "10.1.1.3 Element", null, null, element1_1, + null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum); + dbInstance.commit(); + + + // move element1_1 under element2 + CurriculumElement reloadedElement1_1_3 = curriculumElementDao.loadByKey(element1_1_3.getKey()); + curriculumElementDao.move(reloadedElement1_1_3, null, rootElement1); + dbInstance.commit(); + + // check children element1_1 + CurriculumElementImpl reloadElement1_1 = (CurriculumElementImpl)curriculumElementDao.loadByKey(element1_1.getKey()); + List<CurriculumElement> element11children = reloadElement1_1.getChildren(); + Assert.assertEquals(2, element11children.size()); + Assert.assertEquals(element1_1_1, element11children.get(0)); + Assert.assertEquals(element1_1_2, element11children.get(1)); + + + // check children curriculum + CurriculumImpl reloadedCurriculum = (CurriculumImpl)curriculumDao.loadByKey(curriculum.getKey()); + List<CurriculumElement> rootElements = reloadedCurriculum.getRootElements(); + Assert.assertEquals(2, rootElements.size()); + Assert.assertEquals(rootElement1, rootElements.get(0)); + Assert.assertEquals(element1_1_3, rootElements.get(1)); + } + + + @Test public void getMembersIdentity() { Identity supervisor = JunitTestHelper.createAndPersistIdentityAsRndUser("cur-supervisor-1"); -- GitLab