diff --git a/src/main/java/de/bps/course/condition/interpreter/score/GetOnyxTestOutcomeAnumFunction.java b/src/main/java/de/bps/course/condition/interpreter/score/GetOnyxTestOutcomeAnumFunction.java index b7d4242b2eaa76c903202b85d05a2c129c1e7298..b9cebaa3ddd25b1eb00da8717106d2193a1cd643 100644 --- a/src/main/java/de/bps/course/condition/interpreter/score/GetOnyxTestOutcomeAnumFunction.java +++ b/src/main/java/de/bps/course/condition/interpreter/score/GetOnyxTestOutcomeAnumFunction.java @@ -91,8 +91,11 @@ public class GetOnyxTestOutcomeAnumFunction extends AbstractFunction { "error.notfound.coursenodeid", "solution.copypastenodeid")); } if (!cev.isAssessable(nodeId)) { return handleException(new ArgumentParseException(ArgumentParseException.REFERENCE_NOT_FOUND, name, nodeId, "error.notassessable.coursenodid", "solution.takeassessablenode")); } - // remember the reference to the node id for this condtion - cev.addSoftReference("courseNodeId", nodeId); + // Remember the reference to the node id for this condition for cycle testing. + // Allow self-referencing but do not allow dependencies to parents as they create cycles. + if (!nodeId.equals(cev.getCurrentCourseNodeId())) { + cev.addSoftReference("courseNodeId", nodeId); + } } diff --git a/src/main/java/de/bps/course/condition/interpreter/score/GetOnyxTestOutcomeNumFunction.java b/src/main/java/de/bps/course/condition/interpreter/score/GetOnyxTestOutcomeNumFunction.java index bda29c9925e44ca2ffdbcab31d55bc54f20760af..22021db0099e3535a4d26ae4fe406c0e858b99ea 100644 --- a/src/main/java/de/bps/course/condition/interpreter/score/GetOnyxTestOutcomeNumFunction.java +++ b/src/main/java/de/bps/course/condition/interpreter/score/GetOnyxTestOutcomeNumFunction.java @@ -91,8 +91,11 @@ public class GetOnyxTestOutcomeNumFunction extends AbstractFunction { "error.notfound.coursenodeid", "solution.copypastenodeid")); } if (!cev.isAssessable(nodeId)) { return handleException(new ArgumentParseException(ArgumentParseException.REFERENCE_NOT_FOUND, name, nodeId, "error.notassessable.coursenodid", "solution.takeassessablenode")); } - // remember the reference to the node id for this condtion - cev.addSoftReference("courseNodeId", nodeId); + // Remember the reference to the node id for this condition for cycle testing. + // Allow self-referencing but do not allow dependencies to parents as they create cycles. + if (!nodeId.equals(cev.getCurrentCourseNodeId())) { + cev.addSoftReference("courseNodeId", nodeId); + } } //<OLATCE-1088> diff --git a/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java b/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java index 914ecca680f8aa72f048f643578e3fadd13529c2..1ab0227e5e56ca75357a122d3728a7dd6af6f522 100644 --- a/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java +++ b/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java @@ -137,6 +137,7 @@ public class ConditionInterpreter { env.addFunction(GetRecentCourseLaunchDateFunction.name, new GetRecentCourseLaunchDateFunction(userCourseEnv)); env.addFunction(GetAttemptsFunction.name, new GetAttemptsFunction(userCourseEnv)); + env.addFunction(GetLastAttemptDateFunction.name, new GetLastAttemptDateFunction(userCourseEnv)); // enrollment building block specific functions env.addFunction(GetInitialEnrollmentDateFunction.name, new GetInitialEnrollmentDateFunction(userCourseEnv)); diff --git a/src/main/java/org/olat/course/condition/interpreter/GetAttemptsFunction.java b/src/main/java/org/olat/course/condition/interpreter/GetAttemptsFunction.java index 2bf81aefecffc77fec8123c3f8dea4d45ad26e62..191bcb606513f835b8dad31a9e6b5634d9e0c3e4 100644 --- a/src/main/java/org/olat/course/condition/interpreter/GetAttemptsFunction.java +++ b/src/main/java/org/olat/course/condition/interpreter/GetAttemptsFunction.java @@ -80,8 +80,11 @@ public class GetAttemptsFunction extends AbstractFunction { if (cev != null) { if (!cev.existsNode(nodeId)) { return handleException(new ArgumentParseException(ArgumentParseException.REFERENCE_NOT_FOUND, name, nodeId, "error.notfound.coursenodeid", "solution.copypastenodeid")); } - // remember the reference to the node id for this condtion - cev.addSoftReference("courseNodeId", nodeId); + // Remember the reference to the node id for this condition for cycle testing. + // Allow self-referencing but do not allow dependencies to parents as they create cycles. + if (!nodeId.equals(cev.getCurrentCourseNodeId())) { + cev.addSoftReference("courseNodeId", nodeId); + } // return a valid value to continue with condition evaluation test return defaultValue(); } diff --git a/src/main/java/org/olat/course/condition/interpreter/GetInitialEnrollmentDateFunction.java b/src/main/java/org/olat/course/condition/interpreter/GetInitialEnrollmentDateFunction.java index 1ea3c949260031695047021a44775789a7e12fba..ddf254b322ed42179a0f82cc05b6f5131ce09b38 100644 --- a/src/main/java/org/olat/course/condition/interpreter/GetInitialEnrollmentDateFunction.java +++ b/src/main/java/org/olat/course/condition/interpreter/GetInitialEnrollmentDateFunction.java @@ -82,8 +82,11 @@ public class GetInitialEnrollmentDateFunction extends AbstractFunction { nodeId, "error.notfound.coursenodeid", "solution.copypastenodeid")); } if (!cev.isEnrollmentNode(nodeId)) { return handleException(new ArgumentParseException(ArgumentParseException.REFERENCE_NOT_FOUND, name, nodeId, "error.notenrollment.coursenodeid", "solution.chooseenrollment")); } - // remember the reference to the node id for this condtion - cev.addSoftReference("courseNodeId", nodeId); + // Remember the reference to the node id for this condition for cycle testing. + // Allow self-referencing but do not allow dependencies to parents as they create cycles. + if (!nodeId.equals(cev.getCurrentCourseNodeId())) { + cev.addSoftReference("courseNodeId", nodeId); + } // return a valid value to continue with condition evaluation test return defaultValue(); } diff --git a/src/main/java/org/olat/course/condition/interpreter/GetRecentEnrollmentDateFunction.java b/src/main/java/org/olat/course/condition/interpreter/GetRecentEnrollmentDateFunction.java index 77cc46a4c0d2b33446aa584c107ab3dbe1caeff6..9613b8699ab46b71c4e7c3b13ac0daa937d96ae8 100644 --- a/src/main/java/org/olat/course/condition/interpreter/GetRecentEnrollmentDateFunction.java +++ b/src/main/java/org/olat/course/condition/interpreter/GetRecentEnrollmentDateFunction.java @@ -81,8 +81,11 @@ public class GetRecentEnrollmentDateFunction extends AbstractFunction { "error.notfound.coursenodeid", "solution.copypastenodeid")); } if (!cev.isEnrollmentNode(nodeId)) { return handleException(new ArgumentParseException(ArgumentParseException.REFERENCE_NOT_FOUND, name, nodeId, "error.notenrollment.coursenodeid", "solution.chooseenrollment")); } - // remember the reference to the node id for this condtion - cev.addSoftReference("courseNodeId", nodeId); + // Remember the reference to the node id for this condition for cycle testing. + // Allow self-referencing but do not allow dependencies to parents as they create cycles. + if (!nodeId.equals(cev.getCurrentCourseNodeId())) { + cev.addSoftReference("courseNodeId", nodeId); + } // return a valid value to continue with condition evaluation test return defaultValue(); } diff --git a/src/main/java/org/olat/course/condition/interpreter/score/GetPassedFunction.java b/src/main/java/org/olat/course/condition/interpreter/score/GetPassedFunction.java index df9088608c421c666e3c4a2f867ef11121753917..15d56759d9eb14b7262d52c4e66981df1f2074c9 100644 --- a/src/main/java/org/olat/course/condition/interpreter/score/GetPassedFunction.java +++ b/src/main/java/org/olat/course/condition/interpreter/score/GetPassedFunction.java @@ -29,6 +29,7 @@ import org.olat.course.condition.interpreter.AbstractFunction; import org.olat.course.condition.interpreter.ArgumentParseException; import org.olat.course.condition.interpreter.ConditionInterpreter; import org.olat.course.editor.CourseEditorEnv; +import org.olat.course.nodes.STCourseNode; import org.olat.course.run.scoring.ScoreAccounting; import org.olat.course.run.userview.UserCourseEnvironment; @@ -76,8 +77,13 @@ public class GetPassedFunction extends AbstractFunction { "error.notfound.coursenodeid", "solution.copypastenodeid")); } if (!cev.isAssessable(childId)) { return handleException(new ArgumentParseException(ArgumentParseException.REFERENCE_NOT_FOUND, name, childId, "error.notassessable.coursenodid", "solution.takeassessablenode")); } - // remember the reference to the node id for this condtion - cev.addSoftReference("courseNodeId", childId); + // Remember the reference to the node id for this condition for cycle testing. + // Allow testing against own passed (self-referencing) except for ST + // course nodes as passed is calculated on these node. Do not allow + // dependencies to parents as they create cycles. + if (!childId.equals(cev.getCurrentCourseNodeId()) || cev.getNode(cev.getCurrentCourseNodeId()) instanceof STCourseNode) { + cev.addSoftReference("courseNodeId", childId); + } // return a valid value to continue with condition evaluation test return defaultValue(); } diff --git a/src/main/java/org/olat/course/condition/interpreter/score/GetScoreFunction.java b/src/main/java/org/olat/course/condition/interpreter/score/GetScoreFunction.java index b50eaea5a086b37e728a34d73f5ade3174e608ca..e599c657b31d06bcde21afa4afb062df361feaf0 100644 --- a/src/main/java/org/olat/course/condition/interpreter/score/GetScoreFunction.java +++ b/src/main/java/org/olat/course/condition/interpreter/score/GetScoreFunction.java @@ -28,6 +28,7 @@ package org.olat.course.condition.interpreter.score; import org.olat.course.condition.interpreter.AbstractFunction; import org.olat.course.condition.interpreter.ArgumentParseException; import org.olat.course.editor.CourseEditorEnv; +import org.olat.course.nodes.STCourseNode; import org.olat.course.run.scoring.ScoreAccounting; import org.olat.course.run.userview.UserCourseEnvironment; @@ -74,8 +75,13 @@ public class GetScoreFunction extends AbstractFunction { "error.notfound.coursenodeid", "solution.copypastenodeid")); } if (!cev.isAssessable(childId)) { return handleException(new ArgumentParseException(ArgumentParseException.REFERENCE_NOT_FOUND, name, childId, "error.notassessable.coursenodid", "solution.takeassessablenode")); } - // remember the reference to the node id for this condtion - cev.addSoftReference("courseNodeId", childId); + // Remember the reference to the node id for this condition for cycle testing. + // Allow testing against own score (self-referencing) except for ST + // course nodes as score is calculated on these node. Do not allow + // dependencies to parents as they create cycles. + if (!childId.equals(cev.getCurrentCourseNodeId()) || cev.getNode(cev.getCurrentCourseNodeId()) instanceof STCourseNode) { + cev.addSoftReference("courseNodeId", childId); + } // return a valid value to continue with condition evaluation test return defaultValue(); }