From 88b4bf05ea25e64cd270c1babd8ca4e1fac39dab Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Mon, 9 Jul 2012 09:18:28 +0200
Subject: [PATCH] OO-305. tightly couple the submit of the assessment results
 to the database and to "qti.ser"

---
 .../ims/qti/QTIResultDetailsController.java   |  6 +--
 .../ims/qti/navigator/DefaultNavigator.java   |  6 +++
 .../ims/qti/process/AssessmentFactory.java    | 16 +++++--
 .../ims/qti/process/AssessmentInstance.java   | 45 ++++++++++++++++++-
 .../olat/modules/iq/IQDisplayController.java  | 10 +++--
 .../java/org/olat/modules/iq/IQManager.java   | 11 +++--
 .../course/CourseAssessmentWebService.java    |  2 +-
 7 files changed, 77 insertions(+), 19 deletions(-)

diff --git a/src/main/java/org/olat/ims/qti/QTIResultDetailsController.java b/src/main/java/org/olat/ims/qti/QTIResultDetailsController.java
index ef78c9b1c5d..c2f45bf0dea 100644
--- a/src/main/java/org/olat/ims/qti/QTIResultDetailsController.java
+++ b/src/main/java/org/olat/ims/qti/QTIResultDetailsController.java
@@ -219,12 +219,12 @@ public class QTIResultDetailsController extends BasicController {
 		AssessableCourseNode testNode = (AssessableCourseNode)course.getRunStructure().getNode(nodeIdent);
 		ModuleConfiguration modConfig = testNode.getModuleConfiguration();
 
-		String resourcePathInfo = courseResourceableId + File.separator + nodeIdent; 
-		AssessmentInstance ai = AssessmentFactory.createAssessmentInstance(assessedIdentity, modConfig, false ,resourcePathInfo);
+		String resourcePathInfo = courseResourceableId + File.separator + nodeIdent;
+		AssessmentInstance ai = AssessmentFactory.createAssessmentInstance(assessedIdentity, "", modConfig, false, courseResourceableId, nodeIdent, resourcePathInfo);
 		//close the test
 		ai.close();
 		//persist the results
-		iqm.persistResults(ai, courseResourceableId.longValue(), nodeIdent, assessedIdentity, "");
+		iqm.persistResults(ai);
 
 		//reporting
 		Document docResReporting = iqm.getResultsReporting(ai, assessedIdentity, I18nModule.getDefaultLocale());
diff --git a/src/main/java/org/olat/ims/qti/navigator/DefaultNavigator.java b/src/main/java/org/olat/ims/qti/navigator/DefaultNavigator.java
index 1b68770c63f..16bd832384c 100644
--- a/src/main/java/org/olat/ims/qti/navigator/DefaultNavigator.java
+++ b/src/main/java/org/olat/ims/qti/navigator/DefaultNavigator.java
@@ -36,6 +36,7 @@ import org.olat.ims.qti.container.ItemsInput;
 import org.olat.ims.qti.container.Output;
 import org.olat.ims.qti.container.SectionContext;
 import org.olat.ims.qti.process.AssessmentInstance;
+import org.olat.modules.iq.IQManager;
 
 /**
  */
@@ -144,12 +145,17 @@ public class DefaultNavigator implements Serializable {
 	public void submitAssessment() {
 		Output pendingOutput = null;
 		boolean pendingFeedback = getInfo().isFeedback();
+		boolean alreadyClosed = getAssessmentInstance().isClosed();
 		if(pendingFeedback && getAssessmentInstance().getAssessmentContext().getCurrentSectionContext() != null) {
 			ItemContext itc = getAssessmentInstance().getAssessmentContext().getCurrentSectionContext().getCurrentItemContext();
 			pendingOutput = itc.getOutput();
 		}
 
 		getAssessmentInstance().close();
+		if(!getAssessmentInstance().isPreview() && !alreadyClosed) {
+			IQManager.getInstance().persistResults(getAssessmentInstance());
+		}
+		
 		AssessmentContext ac = getAssessmentContext();
 		
 		info.clear();
diff --git a/src/main/java/org/olat/ims/qti/process/AssessmentFactory.java b/src/main/java/org/olat/ims/qti/process/AssessmentFactory.java
index 26fb86a914f..b9466cf893c 100644
--- a/src/main/java/org/olat/ims/qti/process/AssessmentFactory.java
+++ b/src/main/java/org/olat/ims/qti/process/AssessmentFactory.java
@@ -28,6 +28,7 @@ package org.olat.ims.qti.process;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.CodeHelper;
+import org.olat.core.util.StringHelper;
 import org.olat.course.nodes.iq.IQEditController;
 import org.olat.modules.ModuleConfiguration;
 import org.olat.repository.RepositoryEntry;
@@ -45,7 +46,8 @@ public class AssessmentFactory {
 	 * @param resourcePathInfo
 	 * @return
 	 */
-	public static AssessmentInstance createAssessmentInstance(Identity subj, ModuleConfiguration modConfig, boolean preview, String resourcePathInfo) {
+	public static AssessmentInstance createAssessmentInstance(Identity subj, String remoteAddr, ModuleConfiguration modConfig, boolean preview,
+			long callingResId, String callingResDetail, String resourcePathInfo) {
 		AssessmentInstance ai = null;
 		Persister persister = null;
 
@@ -72,7 +74,7 @@ public class AssessmentFactory {
 			Resolver resolver = new ImsRepositoryResolver(re.getKey());
 			long aiID = CodeHelper.getForeverUniqueID();
 			try {
-				ai = new AssessmentInstance(re.getKey().longValue(), aiID, resolver, persister, modConfig);
+				ai = new AssessmentInstance(subj, remoteAddr, re.getKey().longValue(), aiID, callingResId, callingResDetail, resolver, persister, modConfig);
 			} catch (Exception e) { return null; }
 		}
 		else {
@@ -81,6 +83,12 @@ public class AssessmentFactory {
 			Resolver resolver = new ImsRepositoryResolver(new Long(ai.getRepositoryEntryKey()));
 			ai.setResolver(resolver);
 			ai.setPersister(persister);
+			ai.setAssessedIdentity(subj);
+			ai.setCallingResId(callingResId);
+			ai.setCallingResDetail(callingResDetail);
+			if(StringHelper.containsNonWhitespace(ai.getRemoteAddr())) {
+				ai.setRemoteAddr(remoteAddr);
+			}
 		}
 		return ai; 
 		
@@ -93,9 +101,9 @@ public class AssessmentFactory {
 	 * @param doc
 	 * @return
 	 */
-	public static AssessmentInstance createAssessmentInstance(Resolver resolver, Persister persister, ModuleConfiguration modConfig) {
+	public static AssessmentInstance createAssessmentInstance(Identity subj, String remoteAddr, long callingResId, String callingResDetail, Resolver resolver, Persister persister, ModuleConfiguration modConfig) {
 		long aiID = CodeHelper.getForeverUniqueID();
-		return new AssessmentInstance(0, aiID, resolver, persister, modConfig);
+		return new AssessmentInstance(null, remoteAddr, 0, aiID, callingResId, callingResDetail, resolver, persister, modConfig);
 	}
 
 }
diff --git a/src/main/java/org/olat/ims/qti/process/AssessmentInstance.java b/src/main/java/org/olat/ims/qti/process/AssessmentInstance.java
index 3a915ca9d47..e990a288a61 100644
--- a/src/main/java/org/olat/ims/qti/process/AssessmentInstance.java
+++ b/src/main/java/org/olat/ims/qti/process/AssessmentInstance.java
@@ -31,6 +31,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.olat.core.id.Identity;
 import org.olat.core.logging.AssertException;
 import org.olat.course.nodes.iq.IQEditController;
 import org.olat.ims.qti.container.AssessmentContext;
@@ -54,7 +55,12 @@ public class AssessmentInstance implements Serializable {
 	private long assessID; // the key given to this instance by the constructor; identifying the assessment within the olat context; needed after deserialisation to find the correct qti tree
 	private long repositoryEntryKey; // the key to a repository entry
 	private Navigator navigator; // optimise: make transient
+	
+	private long callingResId;
+	private String callingResDetail;
 	private List sourceBankRefs;
+	private String remoteAddr;
+	private Identity assessedIdentity;
 	
 	private AssessmentContext assessmentContext;
 	
@@ -132,7 +138,12 @@ public class AssessmentInstance implements Serializable {
 	 * @param persistor the Persistor, may be null
 	 * @param modConfig
 	 */
-	public AssessmentInstance(long repositoryEntryKey, long assessID, Resolver resolver, Persister persistor, ModuleConfiguration modConfig) {
+	public AssessmentInstance(Identity identity, String remoteAddr, long repositoryEntryKey, long assessID, long callingResId, String callingResDetail,
+			Resolver resolver, Persister persistor, ModuleConfiguration modConfig) {
+		this.assessedIdentity = identity;
+		this.remoteAddr = remoteAddr;
+		this.callingResId = callingResId;
+		this.callingResDetail = callingResDetail;
 		this.repositoryEntryKey = repositoryEntryKey;
 		this.assessID = assessID;
 		this.resolver = resolver;
@@ -203,6 +214,38 @@ public class AssessmentInstance implements Serializable {
 		createNavigator();
 	}
 
+	public Identity getAssessedIdentity() {
+		return assessedIdentity;
+	}
+	
+	public void setAssessedIdentity(Identity assessedIdentity) {
+		this.assessedIdentity = assessedIdentity;
+	}
+
+	public String getRemoteAddr() {
+		return remoteAddr;
+	}
+
+	public void setRemoteAddr(String remoteAddr) {
+		this.remoteAddr = remoteAddr;
+	}
+
+	public long getCallingResId() {
+		return callingResId;
+	}
+	
+	public void setCallingResId(long callingResId) {
+		this.callingResId = callingResId;
+	}
+	
+	public String getCallingResDetail() {
+		return callingResDetail;
+	}
+	
+	public void setCallingResDetail(String callingResDetail) {
+		this.callingResDetail = callingResDetail;
+	}
+
 	public int getType() { return type; }
 
 	/**
diff --git a/src/main/java/org/olat/modules/iq/IQDisplayController.java b/src/main/java/org/olat/modules/iq/IQDisplayController.java
index 9d8403cc5c3..6dc21fc7666 100644
--- a/src/main/java/org/olat/modules/iq/IQDisplayController.java
+++ b/src/main/java/org/olat/modules/iq/IQDisplayController.java
@@ -261,10 +261,12 @@ public class IQDisplayController extends DefaultController implements GenericEve
 		//try{
 			if (repositorySoftkey != null) { // instantiate from repository
 				// build path information which will be used to store tempory qti file
-				String resourcePathInfo = this.callingResId + File.separator + this.callingResDetail; 
-				ai = AssessmentFactory.createAssessmentInstance(ureq.getIdentity(), modConfig, iqsec.isPreview(),resourcePathInfo); 
+				String resourcePathInfo = callingResId + File.separator + callingResDetail; 
+				ai = AssessmentFactory.createAssessmentInstance(ureq.getIdentity(), ureq.getHttpReq().getRemoteAddr(),
+						modConfig, iqsec.isPreview(), callingResId, callingResDetail, resourcePathInfo); 
 			} else if (resolver != null) { // instantiate from given resolver
-				ai = AssessmentFactory.createAssessmentInstance(resolver, persister, modConfig);
+				ai = AssessmentFactory.createAssessmentInstance(ureq.getIdentity(), ureq.getHttpReq().getRemoteAddr(),
+						callingResId, callingResDetail, resolver, persister, modConfig);
 			}
 		//}finally{
 			//QTIEditorMainController.IS_SAVING_RWL.readLock().unlock();
@@ -528,7 +530,7 @@ public class IQDisplayController extends DefaultController implements GenericEve
 	 */
 	protected void postSubmitAssessment(UserRequest ureq, AssessmentInstance ai) {
 		if (!qtistatus.isPreview()) {
-			iqm.persistResults(ai, callingResId, callingResDetail, ureq.getIdentity(), ureq.getHttpReq().getRemoteAddr());
+			//iqm.persistResults(ai, callingResId, callingResDetail, ureq.getIdentity(), ureq.getHttpReq().getRemoteAddr());
 			getWindowControl().setInfo(translator.translate("status.results.saved"));
 		} else {
 			getWindowControl().setInfo(translator.translate("status.results.notsaved"));
diff --git a/src/main/java/org/olat/modules/iq/IQManager.java b/src/main/java/org/olat/modules/iq/IQManager.java
index e21fb5b107b..040336aa35d 100644
--- a/src/main/java/org/olat/modules/iq/IQManager.java
+++ b/src/main/java/org/olat/modules/iq/IQManager.java
@@ -317,20 +317,19 @@ public class IQManager extends BasicManager implements UserDataDeletable {
 	 * @param ureq
 	 */
 
-	public void persistResults(AssessmentInstance ai, long resId, String resDetail, Identity assessedIdentity, String remoteAddr) {
+	public void persistResults(AssessmentInstance ai) {
 		AssessmentContext ac = ai.getAssessmentContext();
 		
 		QTIResultSet qtiResultSet = new QTIResultSet();
 		qtiResultSet.setLastModified(new Date(System.currentTimeMillis()));
-		qtiResultSet.setOlatResource(resId);
-		qtiResultSet.setOlatResourceDetail(resDetail);
+		qtiResultSet.setOlatResource(ai.getCallingResId());
+		qtiResultSet.setOlatResourceDetail(ai.getCallingResDetail());
 		qtiResultSet.setRepositoryRef(ai.getRepositoryEntryKey());
-		qtiResultSet.setIdentity(assessedIdentity);
+		qtiResultSet.setIdentity(ai.getAssessedIdentity());
 		qtiResultSet.setQtiType(ai.getType());
 		qtiResultSet.setAssessmentID(ai.getAssessID());
 		
 		qtiResultSet.setDuration(new Long(ai.getAssessmentContext().getDuration()));
-		// TODO qtiResultSet.setLastModified();
 		
 		if (ai.isSurvey()){
 			qtiResultSet.setScore(0);
@@ -359,7 +358,7 @@ public class IQManager extends BasicManager implements UserDataDeletable {
 				else qtiResult.setScore(ic.getScore());
 				qtiResult.setTstamp(new Date(ic.getLatestAnswerTime()));
 				qtiResult.setLastModified(new Date(System.currentTimeMillis()));
-				qtiResult.setIp(remoteAddr);
+				qtiResult.setIp(ai.getRemoteAddr());
 				
 				// Get user answers for this item
 				StringBuilder sb = new StringBuilder();
diff --git a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
index c0d65e7fb40..4e4c794dfca 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
@@ -358,7 +358,7 @@ public class CourseAssessmentWebService {
 				// The consequence is that we must loop on section and items and set the
 				// navigator on
 				// the right position before submitting the inputs.
-				AssessmentInstance ai = AssessmentFactory.createAssessmentInstance(identity, modConfig, false, resourcePathInfo);
+				AssessmentInstance ai = AssessmentFactory.createAssessmentInstance(identity, "", modConfig, false, course.getResourceableId(), courseNode.getIdent(), resourcePathInfo);
 				Navigator navigator = ai.getNavigator();
 				navigator.startAssessment();
 				// The type of the navigator depends on the setting of the course node
-- 
GitLab