From 60d6a0cfb236658ccb4d1db6563aa5a1e11312d5 Mon Sep 17 00:00:00 2001
From: uhensler <urs.hensler@frentix.com>
Date: Fri, 23 Aug 2019 10:21:27 +0200
Subject: [PATCH] OO-4186: Move methods from persisted course node to the
 assessment handler

---
 .../assessment/AssessedIdentityWrapper.java   |  1 +
 .../assessment/CourseAssessmentService.java   | 82 ++++++++++++++++++-
 .../assessment/handler/AssessmentConfig.java  |  7 +-
 .../assessment/handler/AssessmentHandler.java | 27 ++++++
 .../handler/ModuleAssessmentConfig.java       |  5 ++
 .../handler/NonAssessmentConfig.java          |  5 ++
 .../handler/NonAssessmentHandler.java         | 13 +++
 .../manager/CourseAssessmentServiceImpl.java  | 54 +++++++++++-
 .../ui/Certificates_1_SelectionStep.java      |  1 +
 .../course/nodes/AssessableCourseNode.java    |  3 -
 .../olat/course/nodes/BasicLTICourseNode.java | 19 +----
 .../course/nodes/CheckListCourseNode.java     | 32 +++-----
 .../org/olat/course/nodes/GTACourseNode.java  | 16 +---
 .../olat/course/nodes/IQTESTCourseNode.java   | 39 +--------
 .../org/olat/course/nodes/MSCourseNode.java   | 20 ++---
 .../nodes/PersistentAssessableCourseNode.java |  4 -
 .../course/nodes/PortfolioCourseNode.java     | 10 +--
 .../course/nodes/ProjectBrokerCourseNode.java | 10 +--
 .../org/olat/course/nodes/STCourseNode.java   | 26 +-----
 .../olat/course/nodes/ScormCourseNode.java    | 10 +--
 .../org/olat/course/nodes/TACourseNode.java   | 16 +---
 .../nodes/basiclti/LTIAssessmentConfig.java   |  5 ++
 .../nodes/basiclti/LTIAssessmentHandler.java  | 16 ++++
 .../nodes/cl/CheckListAssessmentHandler.java  | 16 ++++
 .../nodes/cl/ui/CheckListRunController.java   |  2 +-
 .../gta/AbstractGTAAssessmentHandler.java     | 17 ++++
 .../gta/ui/GroupAssessmentController.java     |  6 +-
 .../olat/course/nodes/iq/IQRunController.java |  2 +-
 .../nodes/iq/IQTESTAssessmentConfig.java      |  5 ++
 .../nodes/iq/IQTESTAssessmentHandler.java     | 23 ++++++
 .../iq/QTI21AssessmentRunController.java      |  4 +-
 .../course/nodes/ms/MSAssessmentHandler.java  | 17 ++++
 .../nodes/ms/MSCourseNodeRunController.java   |  2 +-
 .../portfolio/PortfolioAssessmentHandler.java | 37 +++++++++
 .../ProjectBrokerAssessmentHandler.java       | 17 ++++
 .../nodes/scorm/ScormAssessmentConfig.java    |  5 ++
 .../nodes/scorm/ScormAssessmentHandler.java   | 17 ++++
 .../course/nodes/st/STAssessmentConfig.java   |  5 ++
 .../course/nodes/st/STAssessmentHandler.java  | 39 ++++++++-
 .../course/nodes/ta/TAAssessmentHandler.java  | 17 ++++
 .../run/scoring/AssessmentEvaluation.java     |  9 +-
 .../course/run/scoring/ScoreAccounting.java   | 10 +--
 42 files changed, 473 insertions(+), 198 deletions(-)

diff --git a/src/main/java/org/olat/course/assessment/AssessedIdentityWrapper.java b/src/main/java/org/olat/course/assessment/AssessedIdentityWrapper.java
index 9f807d69c96..baace173301 100644
--- a/src/main/java/org/olat/course/assessment/AssessedIdentityWrapper.java
+++ b/src/main/java/org/olat/course/assessment/AssessedIdentityWrapper.java
@@ -38,6 +38,7 @@ import org.olat.course.run.userview.UserCourseEnvironment;
  * Wrapper class that contains an identity and the associated score, attempts and oder 
  * variables that should be displayed in the user list table.
  */
+//TODO uh delete?
 public class AssessedIdentityWrapper {
 	private final Long identityKey;
     private final UserCourseEnvironment userCourseEnvironment;
diff --git a/src/main/java/org/olat/course/assessment/CourseAssessmentService.java b/src/main/java/org/olat/course/assessment/CourseAssessmentService.java
index edebf5097be..803d403e214 100644
--- a/src/main/java/org/olat/course/assessment/CourseAssessmentService.java
+++ b/src/main/java/org/olat/course/assessment/CourseAssessmentService.java
@@ -31,10 +31,12 @@ import org.olat.core.id.Identity;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
+import org.olat.course.run.scoring.AssessmentEvaluation;
 import org.olat.course.run.scoring.ScoreCalculator;
 import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.Role;
 import org.olat.modules.assessment.model.AssessmentRunStatus;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
@@ -50,14 +52,75 @@ import org.olat.repository.RepositoryEntry;
  */
 public interface CourseAssessmentService {
 	
-	public AssessmentConfig getAssessmentConfig(CourseNode node);
-
+	public AssessmentConfig getAssessmentConfig(CourseNode courseNode);
+	
+	/**
+	 * Returns the persisted AssessmentEntry of the user. Check
+	 * AssessmentConfig.isScoreEvaluationPersisted() before invoking this method.
+	 *
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return
+	 */
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+	
+	/**
+	 * Returns the current, persisted AssessmentEvaluation of the user for a course
+	 * node. The loaded values are modified according to the AssessmentConfig of the
+	 * course node, e.g. if a user has a saved score but the the score is disabled
+	 * in the config, the AssessmentEvaluation has a score of null.
+	 *
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return
+	 */
+	public AssessmentEvaluation getUserAssessmentEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+	
+	/**
+	 * Converts the assessmentEntry to an AssessmentEvaluation in respect of the
+	 * AssessmentConfig. If the assessmentEntry is null, the method returns
+	 * AssessmentEvaluation.EMPTY_EVAL.
+	 * 
+	 * @param assessmentEntry
+	 * @param assessmentConfig
+	 * 
+	 * @return
+	 */
+	public AssessmentEvaluation toAssessmentEvaluation(AssessmentEntry assessmentEntry, AssessmentConfig assessmentConfig);
+	
+	/**
+	 * Converts the assessmentEntry to an AssessmentEvaluation in respect of the
+	 * AssessmentConfig of the courseNode. If the assessmentEntry is null, the
+	 * method returns AssessmentEvaluation.EMPTY_EVAL.
+	 * 
+	 * @param assessmentEntry
+	 * @param courseNode
+	 * 
+	 * @return
+	 */
+	public AssessmentEvaluation toAssessmentEvaluation(AssessmentEntry assessmentEntry, CourseNode courseNode);
+	
+	/**
+	 * This method implementation must not cache any results!
+	 * 
+	 * The user has no scoring results yet (e.g. made no test yet), then the
+	 * ScoreEvaluation.NA has to be returned!
+	 * 
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return null, if this node cannot deliver any useful scoring info (this is
+	 *         not the case for a test never tried or manual scoring: those have
+	 *         default values 0.0f / false for score/passed; currently only the
+	 *         STNode returns null, if there are no scoring rules defined.
+	 */
+	public ScoreEvaluation getUserScoreEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+	
 	public void updateUserScoreEvaluation(CourseNode courseNode, ScoreEvaluation scoreEvaluation,
 			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, boolean incrementAttempts, Role by);
 	
 	/**
 	 * Returns the ScoreCalculator if the course nod can calculate its score. Check
-	 * AssessmentConfig.isScoreCalculated() before invoking this method.
+	 * AssessmentConfig.isScoreEvaluationCalculated() before invoking this method.
 	 *
 	 * @param courseNode
 	 * @return
@@ -190,6 +253,19 @@ public interface CourseAssessmentService {
 	 */
 	public String getUserLog(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
 	
+	/**
+	 * Save the users achieved ScoreEvaluation for this node. If there is already a
+	 * score property available, it will be overwritten with the new value.
+	 * 
+	 * @param courseNode            The course element
+	 * @param identity              The identity who make the changes
+	 * @param scoreEvaluation       The updated score evaluation
+	 * @param userCourseEnvironment The user course env. of the assessed identity
+	 * @param incrementUserAttempts
+	 */
+	public void saveScoreEvaluation(CourseNode courseNode, Identity identity, ScoreEvaluation scoreEvaluation,
+			UserCourseEnvironment userCourseEnvironment, boolean incrementUserAttempts, Role by);
+	
 	/**
 	 * Returns a controller to edit the node specific details. Check
 	 * AssessmentConfig.hasEditableDetails() before invoking this method.
diff --git a/src/main/java/org/olat/course/assessment/handler/AssessmentConfig.java b/src/main/java/org/olat/course/assessment/handler/AssessmentConfig.java
index 60db63b3c38..667ba7d83fd 100644
--- a/src/main/java/org/olat/course/assessment/handler/AssessmentConfig.java
+++ b/src/main/java/org/olat/course/assessment/handler/AssessmentConfig.java
@@ -28,7 +28,12 @@ package org.olat.course.assessment.handler;
 public interface AssessmentConfig {
 	
 	/**
-	 * @return true if the score evaluation is calculated e.g as sum of other assessments
+	 * @return true if the score evaluation is persisted
+	 */
+	public boolean isScoreEvaluationPersisted();
+	
+	/**
+	 * @return true if the score evaluation is calculated e.g as sum of other assessments.
 	 */
 	public boolean isScoreEvaluationCalculated();
 	
diff --git a/src/main/java/org/olat/course/assessment/handler/AssessmentHandler.java b/src/main/java/org/olat/course/assessment/handler/AssessmentHandler.java
index 6b454b76fbb..aa26d4f007e 100644
--- a/src/main/java/org/olat/course/assessment/handler/AssessmentHandler.java
+++ b/src/main/java/org/olat/course/assessment/handler/AssessmentHandler.java
@@ -27,8 +27,10 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -47,7 +49,32 @@ public interface AssessmentHandler {
 	public String acceptCourseNodeType();
 	
 	public AssessmentConfig getAssessmentConfig(CourseNode courseNode);
+	
+	/**
+	 * This method has to be implemented if the AssessmentConfig.isScoreEvaluationPersisted() return true.
+	 *
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return
+	 */
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
 
+	/**
+	 * This method has to be implemented if the AssessmentConfig.isScoreEvaluationCalculated() return true.
+	 *
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return
+	 */
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+	
+	/**
+	 * This method has to be implemented if the AssessmentConfig.isScoreEvaluationCalculated() return true.
+	 *
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return
+	 */
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode);
 	
 	public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel,
diff --git a/src/main/java/org/olat/course/assessment/handler/ModuleAssessmentConfig.java b/src/main/java/org/olat/course/assessment/handler/ModuleAssessmentConfig.java
index f83a31ed08a..4d8c4101962 100644
--- a/src/main/java/org/olat/course/assessment/handler/ModuleAssessmentConfig.java
+++ b/src/main/java/org/olat/course/assessment/handler/ModuleAssessmentConfig.java
@@ -37,6 +37,11 @@ public abstract class ModuleAssessmentConfig implements AssessmentConfig {
 		this.config = config;
 	}
 
+	@Override
+	public boolean isScoreEvaluationPersisted() {
+		return true;
+	}
+
 	@Override
 	public boolean isScoreEvaluationCalculated() {
 		return false;
diff --git a/src/main/java/org/olat/course/assessment/handler/NonAssessmentConfig.java b/src/main/java/org/olat/course/assessment/handler/NonAssessmentConfig.java
index 475d7870158..7fd1f591000 100644
--- a/src/main/java/org/olat/course/assessment/handler/NonAssessmentConfig.java
+++ b/src/main/java/org/olat/course/assessment/handler/NonAssessmentConfig.java
@@ -33,6 +33,11 @@ public class NonAssessmentConfig implements AssessmentConfig {
 		return INSATNCE;
 	}
 
+	@Override
+	public boolean isScoreEvaluationPersisted() {
+		return false;
+	}
+
 	@Override
 	public boolean isScoreEvaluationCalculated() {
 		return false;
diff --git a/src/main/java/org/olat/course/assessment/handler/NonAssessmentHandler.java b/src/main/java/org/olat/course/assessment/handler/NonAssessmentHandler.java
index 52d3651d29d..681da2988b2 100644
--- a/src/main/java/org/olat/course/assessment/handler/NonAssessmentHandler.java
+++ b/src/main/java/org/olat/course/assessment/handler/NonAssessmentHandler.java
@@ -27,8 +27,10 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -55,6 +57,17 @@ public class NonAssessmentHandler implements AssessmentHandler {
 		return NonAssessmentConfig.create();
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java
index c254597c9f6..fb6b5270b3d 100644
--- a/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java
+++ b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java
@@ -40,10 +40,12 @@ import org.olat.course.assessment.handler.NonAssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.nodes.CourseNode;
+import org.olat.course.run.scoring.AssessmentEvaluation;
 import org.olat.course.run.scoring.ScoreCalculator;
 import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.Role;
 import org.olat.modules.assessment.model.AssessmentRunStatus;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
@@ -88,8 +90,44 @@ public class CourseAssessmentServiceImpl implements CourseAssessmentService {
 	}
 
 	@Override
-	public AssessmentConfig getAssessmentConfig(CourseNode node) {
-		return getAssessmentHandler(node).getAssessmentConfig(node);
+	public AssessmentConfig getAssessmentConfig(CourseNode courseNode) {
+		return getAssessmentHandler(courseNode).getAssessmentConfig(courseNode);
+	}
+
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		return getAssessmentHandler(courseNode).getAssessmentEntry(courseNode, userCourseEnvironment);
+	}
+
+	@Override
+	public AssessmentEvaluation getUserAssessmentEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentEntry assessmentEntry = getAssessmentHandler(courseNode).getAssessmentEntry(courseNode, userCourseEnvironment);
+		return toAssessmentEvaluation(assessmentEntry, courseNode);
+	}
+	
+	@Override
+	public AssessmentEvaluation toAssessmentEvaluation(AssessmentEntry assessmentEntry, AssessmentConfig assessmentConfig) {
+		return AssessmentEvaluation.toAssessmentEvaluation(assessmentEntry, assessmentConfig);
+	}
+	
+	@Override
+	public AssessmentEvaluation toAssessmentEvaluation(AssessmentEntry assessmentEntry, CourseNode courseNode) {
+		AssessmentConfig assessmentConfig = getAssessmentConfig(courseNode);
+		return toAssessmentEvaluation(assessmentEntry, assessmentConfig);
+	}
+
+	@Override
+	public ScoreEvaluation getUserScoreEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentConfig assessmentConfig = getAssessmentConfig(courseNode);
+		AssessmentHandler assessmentHandler = getAssessmentHandler(courseNode);
+		
+		ScoreEvaluation scoreEvaluation = AssessmentEvaluation.EMPTY_EVAL;
+		if (assessmentConfig.isScoreEvaluationCalculated()) {
+			scoreEvaluation = assessmentHandler.getCalculatedScoreEvaluation(courseNode, userCourseEnvironment);
+		} else if (assessmentConfig.isScoreEvaluationPersisted()) {
+			scoreEvaluation = getUserAssessmentEvaluation(courseNode, userCourseEnvironment);
+		}
+		return scoreEvaluation;
 	}
 	
 	@Override
@@ -103,7 +141,8 @@ public class CourseAssessmentServiceImpl implements CourseAssessmentService {
 
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
-		return getAssessmentHandler(courseNode).getScoreCalculator(courseNode);
+		ScoreCalculator scoreCalculator = getAssessmentHandler(courseNode).getScoreCalculator(courseNode);
+		return scoreCalculator != null? scoreCalculator: new ScoreCalculator();
 	}
 
 	@Override
@@ -222,6 +261,15 @@ public class CourseAssessmentServiceImpl implements CourseAssessmentService {
 		return am.getUserNodeLog(courseNode, assessedIdentity);
 	}
 
+	@Override
+	public void saveScoreEvaluation(CourseNode courseNode, Identity identity, ScoreEvaluation scoreEvaluation,
+			UserCourseEnvironment userCourseEnvironment, boolean incrementUserAttempts, Role by) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		am.saveScoreEvaluation(courseNode, identity, assessedIdentity, scoreEvaluation, userCourseEnvironment,
+				incrementUserAttempts, by);
+	}
+
 	@Override
 	public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel,
 			CourseNode courseNode, UserCourseEnvironment coachCourseEnv,
diff --git a/src/main/java/org/olat/course/certificate/ui/Certificates_1_SelectionStep.java b/src/main/java/org/olat/course/certificate/ui/Certificates_1_SelectionStep.java
index b6baf30649d..85e5ab004fa 100644
--- a/src/main/java/org/olat/course/certificate/ui/Certificates_1_SelectionStep.java
+++ b/src/main/java/org/olat/course/certificate/ui/Certificates_1_SelectionStep.java
@@ -37,6 +37,7 @@ import org.olat.repository.RepositoryEntry;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
+//TODO uh delete?
 public class Certificates_1_SelectionStep extends BasicStep {
 	
 	private final boolean hasAssessableNodes;
diff --git a/src/main/java/org/olat/course/nodes/AssessableCourseNode.java b/src/main/java/org/olat/course/nodes/AssessableCourseNode.java
index 9d853ddb9a5..e1a013f2e63 100644
--- a/src/main/java/org/olat/course/nodes/AssessableCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/AssessableCourseNode.java
@@ -28,7 +28,6 @@ package org.olat.course.nodes;
 
 import org.olat.course.run.scoring.AssessmentEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
-import org.olat.modules.assessment.AssessmentEntry;
 
 
 /**
@@ -41,8 +40,6 @@ import org.olat.modules.assessment.AssessmentEntry;
  * tool.
  */
 public interface AssessableCourseNode extends CourseNode {
-	
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry); 
 
 	/**
 	 * this method implementation must not cache any results!
diff --git a/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java b/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java
index ee4c597ba84..2fdd4f9721f 100644
--- a/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java
+++ b/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java
@@ -36,12 +36,10 @@ import org.olat.core.gui.control.generic.iframe.DeliveryOptions;
 import org.olat.core.gui.control.generic.messages.MessageUIFactory;
 import org.olat.core.gui.control.generic.tabbable.TabbableController;
 import org.olat.core.gui.translator.Translator;
-import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.course.ICourse;
-import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.editor.NodeEditController;
 import org.olat.course.editor.StatusDescription;
@@ -55,7 +53,6 @@ import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.ims.lti.LTIDisplayOptions;
 import org.olat.ims.lti.LTIManager;
 import org.olat.modules.ModuleConfiguration;
-import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.repository.RepositoryEntry;
 import org.olat.resource.OLATResource;
 
@@ -266,24 +263,10 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode implements
 		}
 		config.setConfigurationVersion(CURRENT_VERSION);
 	}
-	
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
-		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
-		return am.getAssessmentEntry(this, userCourseEnv.getIdentityEnvironment().getIdentity());
-	}
 
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
-		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
-		AssessmentEntry entry = am.getAssessmentEntry(this, mySelf);
-		return getUserScoreEvaluation(entry) ;
-	}
-
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
+		return null; // moved
 	}
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
index ca264eac046..f7b74085b6b 100644
--- a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
@@ -55,6 +55,7 @@ import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.editor.NodeEditController;
@@ -160,20 +161,10 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements
 	 */
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		AssessmentConfig assessmentConfig = new CheckListAssessmentConfig(getModuleConfiguration());
-		if(assessmentConfig.hasPassed() || assessmentConfig.hasScore()) {
-			return getUserScoreEvaluation(getUserAssessmentEntry(userCourseEnv));
-		}
-		return AssessmentEvaluation.EMPTY_EVAL;
-	}
-	
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
+		return null; // moved
 	}
 
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
+	public AssessmentEntry getUserAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnv) {
 		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
 		return am.getAssessmentEntry(this, mySelf);
@@ -422,8 +413,8 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements
 		}
 		ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(score), passed);
 		
-		AssessmentManager am = assessedUserCourseEnv.getCourseEnvironment().getAssessmentManager();
-		am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false, by);
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+		courseAssessmentService.saveScoreEvaluation(this, identity, sceval, assessedUserCourseEnv, false, by);
 	}
 	
 	private void doUpdateAssessmentBySum(Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity, Role by) {
@@ -452,8 +443,8 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements
 
 		ScoreEvaluation sceval = new ScoreEvaluation(score, new Boolean(passed));
 		
-		AssessmentManager am = assessedUserCourseEnv.getCourseEnvironment().getAssessmentManager();
-		am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false, by);
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+		courseAssessmentService.saveScoreEvaluation(this, identity, sceval, assessedUserCourseEnv, false, by);
 	}
 	
 	private void doUpdateScoreOnly(Float maxScore, Identity identity, UserCourseEnvironment assessedUserCourseEnv, Identity assessedIdentity, Role by) {
@@ -466,10 +457,10 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements
 			score = maxScore.floatValue();
 		}
 
-		AssessmentManager am = assessedUserCourseEnv.getCourseEnvironment().getAssessmentManager();
-		ScoreEvaluation currentEval = getUserScoreEvaluation(am.getAssessmentEntry(this, assessedIdentity));
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+		ScoreEvaluation currentEval = courseAssessmentService.getUserAssessmentEvaluation(this, assessedUserCourseEnv);
 		ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), currentEval.getPassed());
-		am.saveScoreEvaluation(this, identity, assessedIdentity, sceval, assessedUserCourseEnv, false, by);
+		courseAssessmentService.saveScoreEvaluation(this, identity, sceval, assessedUserCourseEnv, false, by);
 	}
 	
 	@Override
@@ -615,7 +606,8 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements
 			ScoreEvaluation scoreEval = new ScoreEvaluation(updatedScore, updatedPassed);
 			IdentityEnvironment identityEnv = new IdentityEnvironment(assessedIdentity, null);
 			UserCourseEnvironment uce = new UserCourseEnvironmentImpl(identityEnv, course.getCourseEnvironment());
-			am.saveScoreEvaluation(this, coachIdentity, assessedIdentity, scoreEval, uce, false, Role.coach);
+			CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+			courseAssessmentService.saveScoreEvaluation(this, coachIdentity, scoreEval, uce, false, Role.coach);
 		}
 	}
 
diff --git a/src/main/java/org/olat/course/nodes/GTACourseNode.java b/src/main/java/org/olat/course/nodes/GTACourseNode.java
index 4ff06b19a0b..9044a0cb416 100644
--- a/src/main/java/org/olat/course/nodes/GTACourseNode.java
+++ b/src/main/java/org/olat/course/nodes/GTACourseNode.java
@@ -62,14 +62,12 @@ import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.archiver.ScoreAccountingHelper;
 import org.olat.course.assessment.AssessmentManager;
-import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.editor.NodeEditController;
 import org.olat.course.editor.PublishEvents;
 import org.olat.course.editor.StatusDescription;
 import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.groupsandrights.CourseGroupManager;
-import org.olat.course.nodes.gta.GTAAssessmentConfig;
 import org.olat.course.nodes.gta.GTAManager;
 import org.olat.course.nodes.gta.GTAType;
 import org.olat.course.nodes.gta.Task;
@@ -793,20 +791,10 @@ public class GTACourseNode extends AbstractAccessableCourseNode implements Persi
 
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		AssessmentConfig assessmentConfig = new GTAAssessmentConfig(getModuleConfiguration());
-		if(assessmentConfig.hasPassed() || assessmentConfig.hasScore()) {
-			return getUserScoreEvaluation(getUserAssessmentEntry(userCourseEnv));
-		}
-		return AssessmentEvaluation.EMPTY_EVAL;
+		return null; // moved;
 	}
 
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
-	}
-
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
+	public AssessmentEntry getUserAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnv) {
 		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
 		Identity assessedIdentity = userCourseEnv.getIdentityEnvironment().getIdentity();
 		return am.getAssessmentEntry(this, assessedIdentity);
diff --git a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
index 5a0a12e38f2..54a990f9e30 100644
--- a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
@@ -104,7 +104,6 @@ import org.olat.ims.qti21.resultexport.QTI21ResultsExportMediaResource;
 import org.olat.ims.qti21.ui.statistics.QTI21StatisticResourceResult;
 import org.olat.ims.qti21.ui.statistics.QTI21StatisticsSecurityCallback;
 import org.olat.modules.ModuleConfiguration;
-import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.Role;
 import org.olat.modules.assessment.model.AssessmentEntryStatus;
 import org.olat.modules.assessment.model.AssessmentRunStatus;
@@ -380,57 +379,21 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe
 	 */
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		// read score from properties save score, passed and attempts information
-		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
-		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
-		AssessmentEntry entry = am.getAssessmentEntry(this, mySelf);
-		return getUserScoreEvaluation(entry);
+		return null; // moved
 	}
 
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		if(entry != null) {
-			return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
-		}	
-		return AssessmentEvaluation.EMPTY_EVAL;
-	}
-
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
-		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
-		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
-		if(getRepositoryEntrySoftKey() != null) {
-			return am.getAssessmentEntry(this, mySelf);
-		}
-		return null;
-	}
-
-	/**
-	 * @see org.olat.course.nodes.CourseNode#getReferencedRepositoryEntry()
-	 */
 	@Override
 	public RepositoryEntry getReferencedRepositoryEntry() {
 		// ",false" because we do not want to be strict, but just indicate whether
 		// the reference still exists or not
 		return IQEditController.getIQReference(getModuleConfiguration(), false);
 	}
-	
-	private String getRepositoryEntrySoftKey() {
-		return (String)getModuleConfiguration().get(IQEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
-	}
 
-	/**
-	 * @see org.olat.course.nodes.CourseNode#needsReferenceToARepositoryEntry()
-	 */
 	@Override
 	public boolean needsReferenceToARepositoryEntry() {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.course.nodes.CourseNode#informOnDelete(org.olat.core.gui.UserRequest,
-	 *      org.olat.course.ICourse)
-	 */
 	@Override
 	public String informOnDelete(Locale locale, ICourse course) {
 		// Check if there are qtiresults for this test
diff --git a/src/main/java/org/olat/course/nodes/MSCourseNode.java b/src/main/java/org/olat/course/nodes/MSCourseNode.java
index 714d856fd1e..960e4643320 100644
--- a/src/main/java/org/olat/course/nodes/MSCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/MSCourseNode.java
@@ -50,6 +50,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.condition.ConditionEditController;
 import org.olat.course.editor.CourseEditorEnv;
@@ -275,18 +276,13 @@ public class MSCourseNode extends AbstractAccessableCourseNode implements Persis
 		updateModuleConfigDefaults(false); //TODO uh remove
 		AssessmentConfig assessmentConfig =  new MSAssessmentConfig(getModuleConfiguration());
 		if(assessmentConfig.hasPassed() || assessmentConfig.hasScore() || assessmentConfig.hasComment()) {
-			return getUserScoreEvaluation(getUserAssessmentEntry(userCourseEnv));
+			AssessmentEntry userAssessmentEntry = getUserAssessmentEntry(null, userCourseEnv);
+			return AssessmentEvaluation.toAssessmentEvaluation(userAssessmentEntry, assessmentConfig);
 		}
 		return AssessmentEvaluation.EMPTY_EVAL;
 	}
 
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
-	}
-
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
+	public AssessmentEntry getUserAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnv) {
 		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
 		return am.getAssessmentEntry(this, mySelf);
@@ -416,7 +412,9 @@ public class MSCourseNode extends AbstractAccessableCourseNode implements Persis
 			score = msService.scaleScore(score, scale);
 		}
 		if (score == null) {
-			ScoreEvaluation currentEval = getUserScoreEvaluation(am.getAssessmentEntry(this, assessedIdentity));
+			CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+			AssessmentEntry assessmentEntry = am.getAssessmentEntry(this, assessedIdentity);
+			ScoreEvaluation currentEval = courseAssessmentService.toAssessmentEvaluation(assessmentEntry, this);
 			score = currentEval.getScore();
 		}
 		
@@ -441,7 +439,9 @@ public class MSCourseNode extends AbstractAccessableCourseNode implements Persis
 			boolean aboveCutValue = score.floatValue() >= cutConfig.floatValue();
 			passed = Boolean.valueOf(aboveCutValue);
 		} else {
-			ScoreEvaluation currentEval = getUserScoreEvaluation(am.getAssessmentEntry(this, assessedIdentity));
+			CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+			AssessmentEntry assessmentEntry = am.getAssessmentEntry(this, assessedIdentity);
+			ScoreEvaluation currentEval = courseAssessmentService.toAssessmentEvaluation(assessmentEntry, this);
 			passed = currentEval.getPassed();
 		}
 		return passed;
diff --git a/src/main/java/org/olat/course/nodes/PersistentAssessableCourseNode.java b/src/main/java/org/olat/course/nodes/PersistentAssessableCourseNode.java
index d7757f9f80c..4ea8b9f6e68 100644
--- a/src/main/java/org/olat/course/nodes/PersistentAssessableCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/PersistentAssessableCourseNode.java
@@ -19,9 +19,6 @@
  */
 package org.olat.course.nodes;
 
-import org.olat.course.run.userview.UserCourseEnvironment;
-import org.olat.modules.assessment.AssessmentEntry;
-
 /**
  * Most of the course node saved their data on the database with the
  * assessment service.
@@ -32,6 +29,5 @@ import org.olat.modules.assessment.AssessmentEntry;
  */
 public interface PersistentAssessableCourseNode extends AssessableCourseNode {
 	
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv);
 
 }
diff --git a/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java b/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java
index 0d5c78dfa8a..13c08630257 100644
--- a/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java
@@ -292,16 +292,10 @@ public class PortfolioCourseNode extends AbstractAccessableCourseNode implements
 
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		return getUserScoreEvaluation(getUserAssessmentEntry(userCourseEnv));
+		return null; // moved
 	}
 
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
-	}
-
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
+	public AssessmentEntry getUserAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnv) {
 		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
 		String referenceSoftkey = getReferencedRepositoryEntrySoftkey();
diff --git a/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java b/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java
index 26d60c66402..7c9e7919ca2 100644
--- a/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java
@@ -466,16 +466,10 @@ public class ProjectBrokerCourseNode extends GenericCourseNode implements Persis
 
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		return getUserScoreEvaluation(getUserAssessmentEntry(userCourseEnv));
+		return null; // moved
 	}
 
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
-	}
-
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
+	public AssessmentEntry getUserAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnv) {
 		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
 		return am.getAssessmentEntry(this, mySelf);
diff --git a/src/main/java/org/olat/course/nodes/STCourseNode.java b/src/main/java/org/olat/course/nodes/STCourseNode.java
index 664491089bd..9cf34ddf90f 100644
--- a/src/main/java/org/olat/course/nodes/STCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/STCourseNode.java
@@ -56,7 +56,6 @@ import org.olat.course.ICourse;
 import org.olat.course.condition.Condition;
 import org.olat.course.condition.KeyAndNameConverter;
 import org.olat.course.condition.interpreter.ConditionExpression;
-import org.olat.course.condition.interpreter.ConditionInterpreter;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.editor.NodeEditController;
 import org.olat.course.editor.StatusDescription;
@@ -77,7 +76,6 @@ import org.olat.course.run.userview.NodeEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.course.tree.CourseInternalLinkTreeModel;
 import org.olat.modules.ModuleConfiguration;
-import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.repository.RepositoryEntry;
 import org.olat.util.logging.activity.LoggingResourceable;
 
@@ -253,29 +251,7 @@ public class STCourseNode extends AbstractAccessableCourseNode implements Assess
 	 */
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		Float score = null;
-		Boolean passed = null;
-
-		if (scoreCalculator == null) { 
-			// this is a not-computable course node at the moment (no scoring/passing rules defined)
-			return null; 
-		}
-		String scoreExpressionStr = scoreCalculator.getScoreExpression();
-		String passedExpressionStr = scoreCalculator.getPassedExpression();
-
-		ConditionInterpreter ci = userCourseEnv.getConditionInterpreter();
-		if (scoreExpressionStr != null) {
-			score = new Float(ci.evaluateCalculation(scoreExpressionStr));
-		}
-		if (passedExpressionStr != null) {
-			passed = new Boolean(ci.evaluateCondition(passedExpressionStr));
-		}
-		return new AssessmentEvaluation(score, passed);
-	}
-
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
+		return null; // moved
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/nodes/ScormCourseNode.java b/src/main/java/org/olat/course/nodes/ScormCourseNode.java
index 43f02de6e4a..468b5d2947f 100644
--- a/src/main/java/org/olat/course/nodes/ScormCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/ScormCourseNode.java
@@ -360,16 +360,10 @@ public class ScormCourseNode extends AbstractAccessableCourseNode implements Per
 
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		return getUserScoreEvaluation(getUserAssessmentEntry(userCourseEnv));
-	}
-	
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
+		return null; // moved
 	}
 
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
+	public AssessmentEntry getUserAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnv) {
 		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
 		return am.getAssessmentEntry(this, mySelf);//we want t
diff --git a/src/main/java/org/olat/course/nodes/TACourseNode.java b/src/main/java/org/olat/course/nodes/TACourseNode.java
index 6ee91f88a4f..2ae33ed9579 100644
--- a/src/main/java/org/olat/course/nodes/TACourseNode.java
+++ b/src/main/java/org/olat/course/nodes/TACourseNode.java
@@ -70,7 +70,6 @@ import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.course.ICourse;
 import org.olat.course.archiver.ScoreAccountingHelper;
 import org.olat.course.assessment.AssessmentManager;
-import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.condition.Condition;
 import org.olat.course.condition.interpreter.ConditionExpression;
 import org.olat.course.condition.interpreter.ConditionInterpreter;
@@ -82,7 +81,6 @@ import org.olat.course.nodes.ms.MSEditFormController;
 import org.olat.course.nodes.ta.ConvertToGTACourseNode;
 import org.olat.course.nodes.ta.DropboxController;
 import org.olat.course.nodes.ta.ReturnboxController;
-import org.olat.course.nodes.ta.TAAssessmentConfig;
 import org.olat.course.nodes.ta.TACourseNodeEditController;
 import org.olat.course.nodes.ta.TACourseNodeRunController;
 import org.olat.course.nodes.ta.TaskController;
@@ -447,20 +445,10 @@ public class TACourseNode extends GenericCourseNode implements PersistentAssessa
 
 	@Override
 	public AssessmentEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv) {
-		AssessmentConfig assessmentConfig = new TAAssessmentConfig(getModuleConfiguration());
-		if(assessmentConfig.hasPassed() || assessmentConfig.hasScore()) {
-			return getUserScoreEvaluation(getUserAssessmentEntry(userCourseEnv));
-		}
-		return AssessmentEvaluation.EMPTY_EVAL;
-	}
-	
-	@Override
-	public AssessmentEvaluation getUserScoreEvaluation(AssessmentEntry entry) {
-		return AssessmentEvaluation.toAssessmentEvalutation(entry, this);
+		return null; // moved
 	}
 
-	@Override
-	public AssessmentEntry getUserAssessmentEntry(UserCourseEnvironment userCourseEnv) {
+	public AssessmentEntry getUserAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnv) {
 		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnv.getIdentityEnvironment().getIdentity();
 		return am.getAssessmentEntry(this, mySelf);
diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentConfig.java b/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentConfig.java
index 0e27932751b..05d79b05c1a 100644
--- a/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentConfig.java
+++ b/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentConfig.java
@@ -39,6 +39,11 @@ public class LTIAssessmentConfig implements AssessmentConfig {
 		this.config = config;
 	}
 
+	@Override
+	public boolean isScoreEvaluationPersisted() {
+		return true;
+	}
+
 	@Override
 	public boolean isScoreEvaluationCalculated() {
 		return false;
diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentHandler.java b/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentHandler.java
index b88165b7431..8a41714faa9 100644
--- a/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentHandler.java
@@ -25,15 +25,18 @@ import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.BasicLTICourseNode;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
 import org.olat.ims.lti.ui.LTIResultDetailsController;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -59,6 +62,19 @@ public class LTIAssessmentHandler implements AssessmentHandler {
 		return new LTIAssessmentConfig(courseNode.getModuleConfiguration());
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getAssessmentEntry(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/nodes/cl/CheckListAssessmentHandler.java b/src/main/java/org/olat/course/nodes/cl/CheckListAssessmentHandler.java
index 7013adf1f3f..6ec5baa8dcf 100644
--- a/src/main/java/org/olat/course/nodes/cl/CheckListAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/cl/CheckListAssessmentHandler.java
@@ -27,6 +27,7 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.resource.OresHelper;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
@@ -34,8 +35,10 @@ import org.olat.course.nodes.CheckListCourseNode;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.cl.ui.AssessedIdentityCheckListController;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -60,6 +63,19 @@ public class CheckListAssessmentHandler implements AssessmentHandler {
 		return new CheckListAssessmentConfig(courseNode.getModuleConfiguration());
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getAssessmentEntry(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java
index 93862a2755b..f3b73576e6c 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java
@@ -203,7 +203,7 @@ public class CheckListRunController extends FormBasicController implements Contr
 	}
 	
 	private void exposeUserDataToVC(UserRequest ureq, FormLayoutContainer layoutCont) {
-		AssessmentEntry scoreEval = courseNode.getUserAssessmentEntry(userCourseEnv);
+		AssessmentEntry scoreEval = courseNode.getUserAssessmentEntry(null, userCourseEnv);
 		if(scoreEval == null) {
 			layoutCont.contextPut("score", null);
 			layoutCont.contextPut("hasPassedValue", Boolean.FALSE);
diff --git a/src/main/java/org/olat/course/nodes/gta/AbstractGTAAssessmentHandler.java b/src/main/java/org/olat/course/nodes/gta/AbstractGTAAssessmentHandler.java
index adb0b708b4c..7cd755d6c9e 100644
--- a/src/main/java/org/olat/course/nodes/gta/AbstractGTAAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/gta/AbstractGTAAssessmentHandler.java
@@ -25,6 +25,8 @@ import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BlankController;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
@@ -33,8 +35,10 @@ import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.ui.GTAAssessmentDetailsController;
 import org.olat.course.nodes.gta.ui.GTAIdentityListCourseNodeController;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -52,6 +56,19 @@ public abstract class AbstractGTAAssessmentHandler implements AssessmentHandler
 		return new GTAAssessmentConfig(courseNode.getModuleConfiguration());
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getAssessmentEntry(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
index f32c59579e9..23a6b044003 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
@@ -27,6 +27,7 @@ import java.util.Map;
 import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.IdentityRef;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -321,8 +322,9 @@ public class GroupAssessmentController extends FormBasicController {
 			AssessmentEntry entry = identityToEntryMap.get(identity);
 			
 			ScoreEvaluation scoreEval = null;
-			if(withScore || withPassed) {	
-				scoreEval = gtaNode.getUserScoreEvaluation(entry);
+			if(withScore || withPassed) {
+				CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+				scoreEval = courseAssessmentService.toAssessmentEvaluation(entry, gtaNode);
 				if (scoreEval == null) {
 					scoreEval = ScoreEvaluation.EMPTY_EVALUATION;
 				}
diff --git a/src/main/java/org/olat/course/nodes/iq/IQRunController.java b/src/main/java/org/olat/course/nodes/iq/IQRunController.java
index 03b8eee3738..79df8bf6f8b 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQRunController.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQRunController.java
@@ -639,7 +639,7 @@ public class IQRunController extends BasicController implements GenericEventList
 		Identity identity = userCourseEnv.getIdentityEnvironment().getIdentity();
     	if(courseNode instanceof PersistentAssessableCourseNode) {
     		PersistentAssessableCourseNode acn = (PersistentAssessableCourseNode)courseNode;
-    		AssessmentEntry assessmentEntry = acn.getUserAssessmentEntry(userCourseEnv);
+    		AssessmentEntry assessmentEntry = courseAssessmentService.getAssessmentEntry(courseNode, userCourseEnv);
     		if(assessmentEntry == null) {
     			myContent.contextPut("blockAfterSuccess", Boolean.FALSE);
 	    		myContent.contextPut("score", null);
diff --git a/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentConfig.java b/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentConfig.java
index f732816c48f..eeae3a7e303 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentConfig.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentConfig.java
@@ -41,6 +41,11 @@ public class IQTESTAssessmentConfig implements AssessmentConfig {
 		this.courseNode = courseNode;
 	}
 
+	@Override
+	public boolean isScoreEvaluationPersisted() {
+		return true;
+	}
+
 	@Override
 	public boolean isScoreEvaluationCalculated() {
 		return false;
diff --git a/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentHandler.java b/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentHandler.java
index e8f6a400850..bbce039ec6b 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentHandler.java
@@ -29,6 +29,7 @@ import org.olat.core.gui.control.generic.messages.MessageUIFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.util.Util;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.handler.NonAssessmentConfig;
@@ -36,12 +37,14 @@ import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.IQTESTCourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.fileresource.types.ImsQTI21Resource;
 import org.olat.group.BusinessGroup;
 import org.olat.ims.qti.QTI12ResultDetailsController;
 import org.olat.ims.qti.process.AssessmentInstance;
 import org.olat.ims.qti21.ui.QTI21AssessmentDetailsController;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -71,6 +74,26 @@ public class IQTESTAssessmentHandler implements AssessmentHandler {
 		return NonAssessmentConfig.create();
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		if(getRepositoryEntrySoftKey(courseNode) != null) {
+			return am.getAssessmentEntry(courseNode, assessedIdentity);
+		}
+		return null;
+	}
+	
+	private String getRepositoryEntrySoftKey(CourseNode courseNode) {
+		return (String)courseNode.getModuleConfiguration().get(IQEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java
index 79205dc3fdb..5463acb5037 100644
--- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java
+++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java
@@ -273,7 +273,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 			}
 		} else if(courseNode instanceof IQTESTCourseNode) {
 			IQTESTCourseNode testCourseNode = (IQTESTCourseNode)courseNode;
-			AssessmentEntry assessmentEntry = testCourseNode.getUserAssessmentEntry(userCourseEnv);
+			AssessmentEntry assessmentEntry = courseAssessmentService.getAssessmentEntry(testCourseNode, userCourseEnv);
 			if(assessmentEntry == null) {
 				mainVC.contextPut("blockAfterSuccess", Boolean.FALSE);
 				mainVC.contextPut("score", null);
@@ -605,7 +605,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 		MediaResource resource = null;
 		if(courseNode instanceof IQTESTCourseNode) {
 			IQTESTCourseNode testCourseNode = (IQTESTCourseNode)courseNode;
-			AssessmentEntry assessmentEntry = testCourseNode.getUserAssessmentEntry(userCourseEnv);
+			AssessmentEntry assessmentEntry = courseAssessmentService.getAssessmentEntry(courseNode, userCourseEnv);
 			AssessmentTestSession session = qtiService.getAssessmentTestSession(assessmentEntry.getAssessmentId());
 			File signature = qtiService.getAssessmentResultSignature(session);
 			if(signature.exists()) {
diff --git a/src/main/java/org/olat/course/nodes/ms/MSAssessmentHandler.java b/src/main/java/org/olat/course/nodes/ms/MSAssessmentHandler.java
index 34ccb82e445..0dd8ddd21e8 100644
--- a/src/main/java/org/olat/course/nodes/ms/MSAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/ms/MSAssessmentHandler.java
@@ -24,14 +24,18 @@ import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.MSCourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -57,6 +61,19 @@ public class MSAssessmentHandler implements AssessmentHandler {
 		return new MSAssessmentConfig(courseNode.getModuleConfiguration());
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getAssessmentEntry(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java
index 2e2865dcedd..d9ea6ec5930 100644
--- a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java
+++ b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java
@@ -216,7 +216,7 @@ public class MSCourseNodeRunController extends BasicController implements Activa
 	}
 	
 	private void exposeUserDataToVC(UserRequest ureq) {
-		AssessmentEntry assessmentEntry = courseNode.getUserAssessmentEntry(userCourseEnv);
+		AssessmentEntry assessmentEntry = courseAssessmentService.getAssessmentEntry(courseNode, userCourseEnv);
 		if(assessmentEntry == null) {
 			myContent.contextPut("hasPassedValue", Boolean.FALSE);
 			myContent.contextPut("passed", Boolean.FALSE);
diff --git a/src/main/java/org/olat/course/nodes/portfolio/PortfolioAssessmentHandler.java b/src/main/java/org/olat/course/nodes/portfolio/PortfolioAssessmentHandler.java
index 7af4e51496b..6fd9ea28dd1 100644
--- a/src/main/java/org/olat/course/nodes/portfolio/PortfolioAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/portfolio/PortfolioAssessmentHandler.java
@@ -19,24 +19,29 @@
  */
 package org.olat.course.nodes.portfolio;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.PortfolioCourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.modules.portfolio.handler.BinderTemplateResource;
 import org.olat.modules.portfolio.ui.PortfolioAssessmentDetailsController;
+import org.olat.portfolio.manager.EPStructureManager;
 import org.olat.repository.RepositoryEntry;
 import org.springframework.stereotype.Service;
 
@@ -59,6 +64,38 @@ public class PortfolioAssessmentHandler implements AssessmentHandler {
 		return new PortfolioAssessmentConfig(courseNode.getModuleConfiguration());
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		String referenceSoftkey = getReferenceSoftkey(courseNode);
+		if(referenceSoftkey != null) {
+			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+			return am.getAssessmentEntry(courseNode, assessedIdentity);
+		}
+		return null;
+	}
+
+	private String getReferenceSoftkey(CourseNode courseNode) {
+		String referenceSoftkey = (String)courseNode.getModuleConfiguration().get(PortfolioCourseNodeConfiguration.REPO_SOFT_KEY);
+		if(referenceSoftkey == null) {
+			Long mapKey = (Long)courseNode.getModuleConfiguration().get(PortfolioCourseNodeConfiguration.MAP_KEY);
+			if(mapKey != null) {
+				RepositoryEntry re = CoreSpringFactory.getImpl(EPStructureManager.class)
+						.loadPortfolioRepositoryEntryByMapKey(mapKey);
+				if(re != null) {
+					referenceSoftkey = re.getSoftkey();
+				}
+			}
+		}
+		return referenceSoftkey;
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentHandler.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentHandler.java
index d575b8c1b6d..1ee627cb3ab 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentHandler.java
@@ -24,14 +24,18 @@ import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.ProjectBrokerCourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -56,6 +60,19 @@ public class ProjectBrokerAssessmentHandler implements AssessmentHandler {
 		return new ProjectBrokerAssessmentConfig(courseNode.getModuleConfiguration());
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getAssessmentEntry(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentConfig.java b/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentConfig.java
index 23fce129458..5c2326f1c58 100644
--- a/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentConfig.java
+++ b/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentConfig.java
@@ -36,6 +36,11 @@ public class ScormAssessmentConfig implements AssessmentConfig {
 		this.config = config;
 	}
 
+	@Override
+	public boolean isScoreEvaluationPersisted() {
+		return true;
+	}
+
 	@Override
 	public boolean isScoreEvaluationCalculated() {
 		return false;
diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentHandler.java b/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentHandler.java
index 33919eb1c86..5e8bbeaf5c5 100644
--- a/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentHandler.java
@@ -24,14 +24,18 @@ import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.ScormCourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.modules.scorm.assessment.ScormResultDetailsController;
@@ -57,6 +61,19 @@ public class ScormAssessmentHandler implements AssessmentHandler {
 		return new ScormAssessmentConfig(courseNode.getModuleConfiguration());
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getAssessmentEntry(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/nodes/st/STAssessmentConfig.java b/src/main/java/org/olat/course/nodes/st/STAssessmentConfig.java
index c13c44045c5..32e14710f5e 100644
--- a/src/main/java/org/olat/course/nodes/st/STAssessmentConfig.java
+++ b/src/main/java/org/olat/course/nodes/st/STAssessmentConfig.java
@@ -38,6 +38,11 @@ public class STAssessmentConfig implements AssessmentConfig {
 		this.scoreCalculator = scoreCalculator;
 	}
 
+	@Override
+	public boolean isScoreEvaluationPersisted() {
+		return true;
+	}
+
 	@Override
 	public boolean isScoreEvaluationCalculated() {
 		return true;
diff --git a/src/main/java/org/olat/course/nodes/st/STAssessmentHandler.java b/src/main/java/org/olat/course/nodes/st/STAssessmentHandler.java
index 694924eb5b3..4f71bb02e92 100644
--- a/src/main/java/org/olat/course/nodes/st/STAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/st/STAssessmentHandler.java
@@ -24,15 +24,21 @@ import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.handler.NonAssessmentConfig;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
+import org.olat.course.condition.interpreter.ConditionInterpreter;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.STCourseNode;
+import org.olat.course.run.scoring.AssessmentEvaluation;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -61,13 +67,44 @@ public class STAssessmentHandler implements AssessmentHandler {
 		return NonAssessmentConfig.create();
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getAssessmentEntry(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		ScoreCalculator scoreCalculator = getScoreCalculator(courseNode);
+		if (scoreCalculator == null) { 
+			// this is a not-computable course node at the moment (no scoring/passing rules defined)
+			return null; 
+		}
+		
+		Float score = null;
+		Boolean passed = null;
+
+		String scoreExpressionStr = scoreCalculator.getScoreExpression();
+		String passedExpressionStr = scoreCalculator.getPassedExpression();
+
+		ConditionInterpreter ci = userCourseEnvironment.getConditionInterpreter();
+		if (scoreExpressionStr != null) {
+			score = new Float(ci.evaluateCalculation(scoreExpressionStr));
+		}
+		if (passedExpressionStr != null) {
+			passed = new Boolean(ci.evaluateCondition(passedExpressionStr));
+		}
+		return new AssessmentEvaluation(score, passed);
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		if (courseNode instanceof STCourseNode) {
 			STCourseNode stCourseNode = (STCourseNode) courseNode;
 			return stCourseNode.getScoreCalculator();
 		}
-		return new ScoreCalculator();
+		return null;
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/nodes/ta/TAAssessmentHandler.java b/src/main/java/org/olat/course/nodes/ta/TAAssessmentHandler.java
index cf547f3eb29..28dcca487ea 100644
--- a/src/main/java/org/olat/course/nodes/ta/TAAssessmentHandler.java
+++ b/src/main/java/org/olat/course/nodes/ta/TAAssessmentHandler.java
@@ -24,14 +24,18 @@ import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.AssessmentHandler;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.TACourseNode;
 import org.olat.course.run.scoring.ScoreCalculator;
+import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.ui.AssessmentToolContainer;
 import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.repository.RepositoryEntry;
@@ -57,6 +61,19 @@ public class TAAssessmentHandler implements AssessmentHandler {
 		return new TAAssessmentConfig(courseNode.getModuleConfiguration());
 	}
 
+	@Override
+	public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getAssessmentEntry(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public ScoreEvaluation getCalculatedScoreEvaluation(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment) {
+		return null;
+	}
+
 	@Override
 	public ScoreCalculator getScoreCalculator(CourseNode courseNode) {
 		return null;
diff --git a/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java b/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java
index cb1153a475d..940f43cdbb5 100644
--- a/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java
+++ b/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java
@@ -21,10 +21,7 @@ package org.olat.course.run.scoring;
 
 import java.util.Date;
 
-import org.olat.core.CoreSpringFactory;
-import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
-import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.modules.assessment.model.AssessmentEntryStatus;
 import org.olat.modules.assessment.model.AssessmentRunStatus;
@@ -120,15 +117,11 @@ public class AssessmentEvaluation extends ScoreEvaluation {
 		return lastCoachModified;
 	}
 
-	//TODO uh config instead of node?
-	public static final AssessmentEvaluation toAssessmentEvalutation(AssessmentEntry entry, AssessableCourseNode node) {
+	public static final AssessmentEvaluation toAssessmentEvaluation(AssessmentEntry entry, AssessmentConfig assessmentConfig) {
 		if(entry == null) {
 			return AssessmentEvaluation.EMPTY_EVAL;
 		}
 		
-		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
-		AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(node);
-		
 		Integer attempts = null;
 		if(assessmentConfig.hasAttempts()) {
 			attempts = entry.getAttempts();
diff --git a/src/main/java/org/olat/course/run/scoring/ScoreAccounting.java b/src/main/java/org/olat/course/run/scoring/ScoreAccounting.java
index 6d9ec18e6b0..e2e7440d855 100644
--- a/src/main/java/org/olat/course/run/scoring/ScoreAccounting.java
+++ b/src/main/java/org/olat/course/run/scoring/ScoreAccounting.java
@@ -105,7 +105,8 @@ public class ScoreAccounting {
 			CourseNode courseNode = userCourseEnvironment.getCourseEnvironment().getRunStructure().getNode(nodeIdent);
 			if(courseNode instanceof AssessableCourseNode) {
 				AssessableCourseNode acn = (AssessableCourseNode)courseNode;
-				AssessmentEvaluation se = AssessmentEvaluation.toAssessmentEvalutation(entry, acn);
+				CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+				AssessmentEvaluation se = courseAssessmentService.toAssessmentEvaluation(entry, courseNode);
 				cachedScoreEvals.put(acn, se);
 			}
 		}
@@ -154,7 +155,6 @@ public class ScoreAccounting {
 			recursionLevel++;
 			AssessmentEvaluation se = null;
 			if (recursionLevel <= 15) {
-				
 				CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 				AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(cn);
 				if (update && assessmentConfig.isScoreEvaluationCalculated()) {
@@ -164,9 +164,9 @@ public class ScoreAccounting {
 				} else {
 					se = cachedScoreEvals.get(cn);
 					if (se == null) { // result of this node has not been cached yet, do it
-						AssessmentEntry entry = identToEntries.get(cn.getIdent());
-						if(cn instanceof AssessableCourseNode) { // check isScoreEvaluationPersited()
-							se = cn.getUserScoreEvaluation(entry);
+						if(assessmentConfig.isScoreEvaluationPersisted()) {
+							AssessmentEntry entry = identToEntries.get(cn.getIdent());
+							se = courseAssessmentService.toAssessmentEvaluation(entry, assessmentConfig);
 						} else {
 							se = cn.getUserScoreEvaluation(userCourseEnvironment);
 						}
-- 
GitLab