From 62835b26f058192cd6d939f1448ba55bc039214a Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Mon, 20 Feb 2017 13:51:49 +0100
Subject: [PATCH] OO-2560: show the result of the last test session for
 self-test course elements

---
 .../olat/course/nodes/IQSELFCourseNode.java   | 29 +++++++++++++++----
 .../nodes/SelfAssessableCourseNode.java       | 13 +++++++++
 .../iq/QTI21AssessmentRunController.java      | 25 +++++++++++-----
 .../nodes/iq/_content/assessment_run.html     |  8 ++---
 .../java/org/olat/ims/qti21/QTI21Service.java | 11 +++++++
 .../manager/AssessmentTestSessionDAO.java     | 29 +++++++++++++++++++
 .../ims/qti21/manager/QTI21ServiceImpl.java   |  6 ++++
 .../ui/AssessmentTestDisplayController.java   | 14 ++++-----
 8 files changed, 111 insertions(+), 24 deletions(-)

diff --git a/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java b/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java
index 0b8c19d7f7b..a8d2eec19d8 100644
--- a/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java
@@ -63,6 +63,8 @@ import org.olat.ims.qti.export.QTIExportFormatterCSVType2;
 import org.olat.ims.qti.export.QTIExportManager;
 import org.olat.ims.qti.fileresource.TestFileResource;
 import org.olat.ims.qti.process.AssessmentInstance;
+import org.olat.ims.qti21.AssessmentTestSession;
+import org.olat.ims.qti21.QTI21Service;
 import org.olat.ims.qti21.manager.AssessmentTestSessionDAO;
 import org.olat.modules.ModuleConfiguration;
 import org.olat.modules.iq.IQManager;
@@ -315,6 +317,7 @@ public class IQSELFCourseNode extends AbstractAccessableCourseNode implements Se
 	@Override
 	public ScoreEvaluation getUserScoreEvaluation(final UserCourseEnvironment userCourseEnv) {
 		// read score from properties save score, passed and attempts information
+		ScoreEvaluation scoreEvaluation = null;
 		RepositoryEntry referencedRepositoryEntry = getReferencedRepositoryEntry();
 		if (referencedRepositoryEntry != null && OnyxModule.isOnyxTest(getReferencedRepositoryEntry().getOlatResource())) {
 			AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
@@ -324,9 +327,18 @@ public class IQSELFCourseNode extends AbstractAccessableCourseNode implements Se
 			Long assessmentID = am.getAssessmentID(this, mySelf);
 			// <OLATCE-374>
 			Boolean fullyAssessed = am.getNodeFullyAssessed(this, mySelf);
-			ScoreEvaluation se = new ScoreEvaluation(score, passed, fullyAssessed, assessmentID);
+			scoreEvaluation = new ScoreEvaluation(score, passed, fullyAssessed, assessmentID);
 			// </OLATCE-374>
-			return se;
+		} else if(referencedRepositoryEntry != null && ImsQTI21Resource.TYPE_NAME.equals(referencedRepositoryEntry.getOlatResource().getResourceableTypeName())) {
+			RepositoryEntry courseEntry = userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry();
+			Identity assessedIdentity = userCourseEnv.getIdentityEnvironment().getIdentity();
+			AssessmentTestSession testSession = CoreSpringFactory.getImpl(QTI21Service.class)
+					.getLastAssessmentTestSessions(courseEntry, getIdent(), referencedRepositoryEntry, assessedIdentity);
+			if(testSession != null) {
+				boolean fullyAssessed = (testSession.getFinishTime() != null || testSession.getTerminationTime() != null);
+				Float score = testSession.getScore() == null ? null : testSession.getScore().floatValue();
+				scoreEvaluation = new ScoreEvaluation(score, testSession.getPassed(), fullyAssessed, testSession.getKey());
+			}
 		} else {
 			Identity identity = userCourseEnv.getIdentityEnvironment().getIdentity();
 			long olatResourceId = userCourseEnv.getCourseEnvironment().getCourseResourceableId().longValue();
@@ -334,16 +346,23 @@ public class IQSELFCourseNode extends AbstractAccessableCourseNode implements Se
 			if (qTIResultSet != null) {
 				Boolean passed = qTIResultSet.getIsPassed();
 				Boolean fullyAssessed = qTIResultSet.getFullyAssessed();
-				ScoreEvaluation scoreEvaluation = new ScoreEvaluation(new Float(qTIResultSet.getScore()), passed, fullyAssessed, new Long(qTIResultSet.getAssessmentID()));
-				return scoreEvaluation;
+				scoreEvaluation = new ScoreEvaluation(new Float(qTIResultSet.getScore()), passed, fullyAssessed, new Long(qTIResultSet.getAssessmentID()));
 			}
 		}
-		return null;
+		return scoreEvaluation;
 	}
 	
+	@Override
+	public Integer getUserAttempts(UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getNodeAttempts(this, mySelf);
+	}
+
 	/**
 	 * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment)
 	 */
+	@Override
 	public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment) {
 		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity();
diff --git a/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java b/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java
index cb431bedd4b..5e9a0957567 100644
--- a/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java
@@ -45,4 +45,17 @@ public interface SelfAssessableCourseNode extends CourseNode {
 	 * @return Returns the ScoreEvaluation.
 	 */
 	public ScoreEvaluation getUserScoreEvaluation(UserCourseEnvironment userCourseEnv);
+	
+	/**
+	 * @param userCourseEnvironment
+	 * @return The users attempts of this node
+	 */
+	public Integer getUserAttempts(UserCourseEnvironment userCourseEnvironment);
+	
+	/**
+	 * Increments the users attempts for this node and this user + 1. 
+	 * @param userCourseEnvironment
+	 */
+	public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment);
+	
 }
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 42d1fc208eb..4a23c7a5db0 100644
--- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java
+++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java
@@ -56,6 +56,7 @@ import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.IQSELFCourseNode;
 import org.olat.course.nodes.IQTESTCourseNode;
 import org.olat.course.nodes.QTICourseNode;
+import org.olat.course.nodes.SelfAssessableCourseNode;
 import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.fileresource.FileResourceManager;
@@ -187,9 +188,21 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 		} else {
 			mainVC.contextPut("attemptsConfig", Boolean.FALSE);
 		}
-	    // user data
 		
-		if(courseNode instanceof IQTESTCourseNode) {
+	    // user data
+		if (courseNode instanceof SelfAssessableCourseNode) {
+			SelfAssessableCourseNode acn = (SelfAssessableCourseNode)courseNode; 
+			ScoreEvaluation scoreEval = acn.getUserScoreEvaluation(userCourseEnv);
+			Integer attempts = acn.getUserAttempts(userCourseEnv);
+			if (scoreEval != null) {
+				mainVC.contextPut("hasResults", Boolean.TRUE);
+				mainVC.contextPut("score", AssessmentHelper.getRoundedScore(scoreEval.getScore()));
+				mainVC.contextPut("hasPassedValue", (scoreEval.getPassed() == null ? Boolean.FALSE : Boolean.TRUE));
+				mainVC.contextPut("passed", scoreEval.getPassed());
+				mainVC.contextPut("attempts", attempts); //at least one attempt
+				exposeResults(ureq);
+			}
+		} else if(courseNode instanceof IQTESTCourseNode) {
 			IQTESTCourseNode testCourseNode = (IQTESTCourseNode)courseNode;
 			AssessmentEntry assessmentEntry = testCourseNode.getUserAssessmentEntry(userCourseEnv);
 			if(assessmentEntry == null) {
@@ -223,9 +236,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 					mainVC.contextPut("log", am.getUserNodeLog(courseNode, identity));
 				}
 			}
-		}
-						
-		exposeResults(ureq);
+		}	
 	}
 	
 	private void checkChats (UserRequest ureq) {
@@ -505,10 +516,10 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 			if(increment) {
 				ThreadLocalUserActivityLogger.log(QTI21LoggingAction.QTI_CLOSE_IN_COURSE, getClass());
 			}
-		} else if(courseNode instanceof IQSELFCourseNode) {
+		} else if(courseNode instanceof SelfAssessableCourseNode) {
 			boolean increment = incrementAttempts.getAndSet(false);
 			if(increment) {
-				((IQSELFCourseNode)courseNode).incrementUserAttempts(userCourseEnv);
+				((SelfAssessableCourseNode)courseNode).incrementUserAttempts(userCourseEnv);
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/course/nodes/iq/_content/assessment_run.html b/src/main/java/org/olat/course/nodes/iq/_content/assessment_run.html
index 66b5812c886..1b0dbd4dde8 100644
--- a/src/main/java/org/olat/course/nodes/iq/_content/assessment_run.html
+++ b/src/main/java/org/olat/course/nodes/iq/_content/assessment_run.html
@@ -1,5 +1,5 @@
 #if ($enableScoreInfo)
-	#if($attempts && $attempts > 0)
+	#if($r.isNotNull($attempts) && $attempts > 0)
 		<div class="panel panel-default o_personal">
 		  	<div class="panel-heading">
 	  			<h4 class="panel-title">$r.translate("personal.title")</h4>
@@ -19,11 +19,11 @@
 				<tr class="o_attempts">
 					<th>$r.translate("attempts.yourattempts")</th>
 					<td>$attempts</td> 
-				</tr> 
+				</tr>
 				<tr class="o_score">
 					<th>$r.translate("score.yourscore")</th>
-					<td>$score</td> 
-				</tr> 
+					<td>#if($r.isNotNull($score))$score#end</td>
+				</tr>
 				<tr class="o_state #if ($hasPassedValue && $passed) o_passed #elseif($hasPassedValue && !$passed) o_failed #else o_unknown #end">
 					<th>$r.translate("passed.yourpassed")</th>
 					<td>
diff --git a/src/main/java/org/olat/ims/qti21/QTI21Service.java b/src/main/java/org/olat/ims/qti21/QTI21Service.java
index ce066d90961..de122275db6 100644
--- a/src/main/java/org/olat/ims/qti21/QTI21Service.java
+++ b/src/main/java/org/olat/ims/qti21/QTI21Service.java
@@ -228,6 +228,17 @@ public interface QTI21Service {
 	 */
 	public List<AssessmentTestSession> getAssessmentTestSessions(RepositoryEntryRef courseEntry, String subIdent, IdentityRef identity);
 	
+	/**
+	 * Retrieve the last finished test session.
+	 * 
+	 * @param courseEntry
+	 * @param subIdent
+	 * @param testEntry
+	 * @param identity
+	 * @return
+	 */
+	public AssessmentTestSession getLastAssessmentTestSessions(RepositoryEntryRef courseEntry, String subIdent, RepositoryEntry testEntry, IdentityRef identity);
+	
 	/**
 	 * Retrieve the sessions for a test.
 	 * 
diff --git a/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java b/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java
index 053582b7822..f45e969ae95 100644
--- a/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java
+++ b/src/main/java/org/olat/ims/qti21/manager/AssessmentTestSessionDAO.java
@@ -354,6 +354,35 @@ public class AssessmentTestSessionDAO {
 		return query.getResultList();
 	}
 	
+	public AssessmentTestSession getLastUserTestSession(RepositoryEntryRef courseEntry, String courseSubIdent, RepositoryEntry testEntry, IdentityRef identity) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select session from qtiassessmenttestsession session")
+		  .append(" left join fetch session.testEntry testEntry")
+		  .append(" left join fetch testEntry.olatResource testResource")
+		  .append(" where session.repositoryEntry.key=:repositoryEntryKey and session.identity.key=:identityKey ")
+		  .append(" and session.testEntry.key=:testEntryKey and (session.finishTime is not null or session.terminationTime is not null) and ");
+		if(StringHelper.containsNonWhitespace(courseSubIdent)) {
+			sb.append("session.subIdent=:subIdent");
+		} else {
+			sb.append("session.subIdent is null");
+		}
+		sb.append(" order by session.creationDate desc");
+		
+		TypedQuery<AssessmentTestSession> query = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), AssessmentTestSession.class)
+				.setParameter("repositoryEntryKey", courseEntry.getKey())
+				.setParameter("testEntryKey", testEntry.getKey())
+				.setParameter("identityKey", identity.getKey());
+		if(StringHelper.containsNonWhitespace(courseSubIdent)) {
+			query.setParameter("subIdent", courseSubIdent);
+		}
+		List<AssessmentTestSession> sessions = query
+				.setFirstResult(0)
+				.setMaxResults(1)
+				.getResultList();
+		return sessions.size() > 0 ? sessions.get(0) : null;
+	}
+	
 	public List<AssessmentTestSession> getRunningTestSessions(RepositoryEntryRef entry, String courseSubIdent, RepositoryEntry testEntry) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select session from qtiassessmenttestsession session")
diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
index 49bd29f58a0..957d5e2c123 100644
--- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
+++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
@@ -476,6 +476,12 @@ public class QTI21ServiceImpl implements QTI21Service, UserDataDeletable, Initia
 	public List<AssessmentTestSession> getAssessmentTestSessions(RepositoryEntryRef courseEntry, String subIdent, IdentityRef identity) {
 		return testSessionDao.getUserTestSessions(courseEntry, subIdent, identity);
 	}
+	
+	@Override
+	public AssessmentTestSession getLastAssessmentTestSessions(RepositoryEntryRef courseEntry, String subIdent,
+			RepositoryEntry testEntry, IdentityRef identity) {
+		return testSessionDao.getLastUserTestSession(courseEntry, subIdent, testEntry, identity);
+	}
 
 	@Override
 	public List<AssessmentTestSession> getAssessmentTestSessions(RepositoryEntryRef courseEntry, String subIdent, RepositoryEntry testEntry) {
diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java
index fd8079b5046..af61754803f 100644
--- a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java
@@ -1196,14 +1196,12 @@ public class AssessmentTestDisplayController extends BasicController implements
             	}
             }
         }
-        
-        if(score != null || pass != null) {
-        	if(submit) {
-        		outcomesListener.submit(score, pass, candidateSession.getKey());
-        	} else {
-        		outcomesListener.updateOutcomes(score, pass);
-        	}
-        }
+
+    	if(submit) {
+    		outcomesListener.submit(score, pass, candidateSession.getKey());
+    	} else {
+    		outcomesListener.updateOutcomes(score, pass);
+    	}
     }
 	
     private AssessmentResult computeTestAssessmentResult(UserRequest ureq, final AssessmentTestSession testSession) {
-- 
GitLab