Skip to content
Snippets Groups Projects
Commit be9852de authored by srosse's avatar srosse
Browse files

OO-716: add download of raw data from the archive tool

parent 5c65446f
No related branches found
No related tags found
No related merge requests found
Showing
with 404 additions and 171 deletions
......@@ -219,7 +219,7 @@ public class IQSELFCourseNode extends AbstractAccessableCourseNode implements Se
try {
QTIExportFormatter qef = new QTIExportFormatterCSVType2(locale, null, "\t", "\"", "\\", "\r\n", false);
return qem.selectAndExportResults(qef, course.getResourceableId(), getShortTitle(), getIdent(), re, exportStream, charset, ".xls");
return qem.selectAndExportResults(qef, course.getResourceableId(), getShortTitle(), getIdent(), re, exportStream, ".xls");
} catch (IOException e) {
log.error("", e);
return false;
......
......@@ -150,7 +150,7 @@ public class IQSURVCourseNode extends AbstractAccessableCourseNode implements QT
QTIStatisticSearchParams searchParams = new QTIStatisticSearchParams(courseOres.getResourceableId(), getIdent());
searchParams.setLimitToSecGroups(limitMemberships);
QTIStatisticResourceResult result = new QTIStatisticResourceResult(this, searchParams);
QTIStatisticResourceResult result = new QTIStatisticResourceResult(courseOres, this, searchParams);
return result;
}
......@@ -256,7 +256,7 @@ public class IQSURVCourseNode extends AbstractAccessableCourseNode implements QT
QTIExportFormatter qef = new QTIExportFormatterCSVType3(locale, null,"\t", "\"", "\\", "\r\n", false);
try {
return qem.selectAndExportResults(qef, course.getResourceableId(), getShortTitle(), getIdent(), re, exportStream, charset, ".xls");
return qem.selectAndExportResults(qef, course.getResourceableId(), getShortTitle(), getIdent(), re, exportStream, ".xls");
} catch (IOException e) {
log.error("", e);
return false;
......
......@@ -164,7 +164,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements As
QTIStatisticSearchParams searchParams = new QTIStatisticSearchParams(courseOres.getResourceableId(), getIdent());
searchParams.setLimitToSecGroups(limitMemberships);
QTIStatisticResourceResult result = new QTIStatisticResourceResult(this, searchParams);
QTIStatisticResourceResult result = new QTIStatisticResourceResult(courseOres, this, searchParams);
return result;
}
......@@ -437,7 +437,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements As
String shortTitle = getShortTitle();
QTIExportManager qem = QTIExportManager.getInstance();
QTIExportFormatter qef = new QTIExportFormatterCSVType1(locale, "\t", "\"", "\\", "\r\n", false);
return qem.selectAndExportResults(qef, courseResourceableId, shortTitle, getIdent(), re, exportStream, charset, ".xls");
return qem.selectAndExportResults(qef, courseResourceableId, shortTitle, getIdent(), re, exportStream, ".xls");
}
} catch (IOException e) {
log.error("", e);
......
......@@ -510,10 +510,7 @@ public class IQEditController extends ActivateableTabbableDefaultController impl
onyxSuccess = surveyDir.listFiles().length;
}
} else {
List<QTIResult> results = QTIResultManager.getInstance().selectResults(course.getResourceableId(), courseNode.getIdent(), repKey, 1);
if (results != null && results.size() > 0) {
onyxSuccess = results.size();
}
onyxSuccess = QTIResultManager.getInstance().countResults(course.getResourceableId(), courseNode.getIdent(), repKey);
}
}
if (moduleConfiguration.get(CONFIG_KEY_TYPE_QTI) != null
......@@ -523,7 +520,7 @@ public class IQEditController extends ActivateableTabbableDefaultController impl
replaceWizard.addControllerListener(this);
cmc = new CloseableModalController(getWindowControl(), translate("close"), replaceWizard.getInitialComponent());
} else {
List<QTIResult> results = QTIResultManager.getInstance().selectResults(course.getResourceableId(), courseNode.getIdent(), repKey, 1);
List<QTIResult> results = QTIResultManager.getInstance().selectResults(course.getResourceableId(), courseNode.getIdent(), repKey, null, 1);
// test was passed from an user
boolean passed = (results != null && results.size() > 0) ? true : false;
// test was started and not passed
......
......@@ -40,7 +40,7 @@ package org.olat.ims.qti;
*
* @author patrick
*/
public class QTIChangeLogMessage implements Comparable{
public class QTIChangeLogMessage implements Comparable<QTIChangeLogMessage> {
private boolean isPublic;
private String logMessage;
......@@ -87,8 +87,8 @@ public class QTIChangeLogMessage implements Comparable{
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Object arg0) {
QTIChangeLogMessage b = (QTIChangeLogMessage)arg0;
@Override
public int compareTo(QTIChangeLogMessage b) {
long diff = this.getTimestmp() - b.getTimestmp();
//this ordering makes Arrays.sort(..) to sort the change log messages ascending
//whereas ascending means older timestamp before newer timestamp
......
......@@ -34,7 +34,9 @@ import org.olat.core.commons.persistence.PersistentObject;
*
* @author gnaegi
*/
public class QTIResult extends PersistentObject{
public class QTIResult extends PersistentObject{
private static final long serialVersionUID = 5999697754463201896L;
private QTIResultSet resultSet;
......@@ -169,4 +171,20 @@ public class QTIResult extends PersistentObject{
this.lastModified = lastModified;
}
@Override
public int hashCode() {
return getKey() == null ? 97520 : getKey().hashCode();
}
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(obj instanceof QTIResult) {
QTIResult result = (QTIResult)obj;
return getKey() != null && getKey().equals(result.getKey());
}
return false;
}
}
......@@ -27,14 +27,16 @@ package org.olat.ims.qti;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import org.olat.basesecurity.SecurityGroup;
import org.olat.basesecurity.SecurityGroupMembershipImpl;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.id.Identity;
import org.olat.core.id.UserConstants;
import org.olat.core.logging.OLog;
......@@ -51,6 +53,8 @@ public class QTIResultManager implements UserDataDeletable {
private static final OLog log = Tracing.createLoggerFor(QTIResultManager.class);
private static QTIResultManager instance;
private DB dbInstance;
/**
* Constructor for QTIResultManager.
......@@ -65,6 +69,14 @@ public class QTIResultManager implements UserDataDeletable {
public static QTIResultManager getInstance() {
return instance;
}
/**
* [user by Spring]
* @param dbInstance
*/
public void setDbInstance(DB dbInstance) {
this.dbInstance = dbInstance;
}
/**
* @param olatResource
......@@ -73,7 +85,16 @@ public class QTIResultManager implements UserDataDeletable {
* @return True if true, false otherwise.
*/
public boolean hasResultSets(Long olatResource, String olatResourceDetail, Long repositoryRef) {
return (getResultSets(olatResource, olatResourceDetail, repositoryRef, null).size() > 0);
StringBuilder sb = new StringBuilder();
sb.append("select count(rset.key) from ").append(QTIResultSet.class.getName()).append(" as rset ")
.append("where rset.olatResource=:resId and rset.olatResourceDetail=:resSubPath and rset.repositoryRef=:repoKey");
Number count = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Number.class)
.setParameter("resId", olatResource)
.setParameter("resSubPath", olatResourceDetail)
.setParameter("repoKey", repositoryRef).getSingleResult();
return count == null ? false : count.intValue() > 0;
}
/**
......@@ -85,27 +106,22 @@ public class QTIResultManager implements UserDataDeletable {
* @return List of resultsets
*/
public List<QTIResultSet> getResultSets(Long olatResource, String olatResourceDetail, Long repositoryRef, Identity identity) {
Long olatRes = olatResource;
String olatResDet = olatResourceDetail;
Long repRef = repositoryRef;
DB db = DBFactory.getInstance();
StringBuilder slct = new StringBuilder();
slct.append("select rset from ");
slct.append("org.olat.ims.qti.QTIResultSet rset ");
slct.append("where ");
slct.append("rset.olatResource=? ");
slct.append("and rset.olatResourceDetail=? ");
slct.append("and rset.repositoryRef=? ");
StringBuilder sb = new StringBuilder();
sb.append("select rset from ").append(QTIResultSet.class.getName()).append(" as rset ")
.append("where rset.olatResource=:resId and rset.olatResourceDetail=:resSubPath and rset.repositoryRef=:repoKey");
if (identity != null) {
slct.append("and rset.identity.key=? ");
return db.find(slct.toString(), new Object[] { olatRes, olatResDet, repRef, identity.getKey() }, new Type[] { StandardBasicTypes.LONG, StandardBasicTypes.STRING,
StandardBasicTypes.LONG, StandardBasicTypes.LONG });
} else {
return db.find(slct.toString(), new Object[] { olatRes, olatResDet, repRef }, new Type[] { StandardBasicTypes.LONG, StandardBasicTypes.STRING,
StandardBasicTypes.LONG });
sb.append(" and rset.identity.key=:identityKey ");
}
TypedQuery<QTIResultSet> query = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), QTIResultSet.class)
.setParameter("resId", olatResource)
.setParameter("resSubPath", olatResourceDetail)
.setParameter("repoKey", repositoryRef);
if (identity != null) {
query.setParameter("identityKey", identity.getKey());
}
return query.getResultList();
}
/**
......@@ -116,43 +132,67 @@ public class QTIResultManager implements UserDataDeletable {
* @param repositoryRef
* @return List of QTIResult objects
*/
public List<QTIResult> selectResults(Long olatResource, String olatResourceDetail, Long repositoryRef, int type) {
Long olatRes = olatResource;
String olatResDet = olatResourceDetail;
Long repRef = repositoryRef;
DB db = DBFactory.getInstance();
// join with user to sort by name
StringBuilder slct = new StringBuilder();
slct.append("select res from ");
slct.append("org.olat.ims.qti.QTIResultSet rset, ");
slct.append("org.olat.ims.qti.QTIResult res, ");
slct.append("org.olat.core.id.Identity identity, ");
slct.append("org.olat.user.UserImpl usr ");
slct.append("where ");
slct.append("rset.key = res.resultSet ");
slct.append("and rset.identity = identity.key ");
slct.append("and identity.user = usr.key ");
slct.append("and rset.olatResource=? ");
slct.append("and rset.olatResourceDetail=? ");
slct.append("and rset.repositoryRef=? ");
// 1 -> iqtest, 2 -> iqself
if(type == 1 || type == 2)
slct.append("order by usr.properties['").append(UserConstants.LASTNAME).append("'] , rset.assessmentID, res.itemIdent");
public List<QTIResult> selectResults(Long olatResource, String olatResourceDetail, Long repositoryRef,
List<SecurityGroup> limitToSecGroups, int type) {
StringBuilder sb = new StringBuilder();
sb.append("select res from ").append(QTIResult.class.getName()).append(" as res ")
.append(" inner join res.resultSet as rset")
.append(" inner join rset.identity as ident")
.append(" inner join ident.user as usr")
.append(" where rset.olatResource=:resId and rset.olatResourceDetail=:resSubPath and rset.repositoryRef=:repoKey");
if(limitToSecGroups != null && limitToSecGroups.size() > 0) {
sb.append(" and rset.identity.key in ( select secMembership.identity.key from ").append(SecurityGroupMembershipImpl.class.getName()).append(" secMembership ")
.append(" where secMembership.securityGroup in (:secGroups)")
.append(" )");
}
if(type == 1 || type == 2) {
// 1 -> iqtest, 2 -> iqself
sb.append(" order by usr.properties['").append(UserConstants.LASTNAME).append("'] , rset.assessmentID, res.itemIdent");
} else {
//3 -> iqsurv: the alphabetical assortment above could destroy the anonymization
// if names and quantity of the persons is well-known
else
slct.append("order by rset.creationDate, rset.assessmentID, res.itemIdent");
// if names and quantity of the persons is well-known
sb.append(" order by rset.creationDate, rset.assessmentID, res.itemIdent");
}
List results = null;
results = db.find(slct.toString(), new Object[] { olatRes, olatResDet, repRef }, new Type[] { StandardBasicTypes.LONG, StandardBasicTypes.STRING,
StandardBasicTypes.LONG });
TypedQuery<QTIResult> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), QTIResult.class)
.setParameter("resId", olatResource)
.setParameter("resSubPath", olatResourceDetail)
.setParameter("repoKey", repositoryRef);
return results;
if(limitToSecGroups != null && limitToSecGroups.size() > 0) {
query.setParameter("secGroups", limitToSecGroups);
}
return query.getResultList();
}
/**
* Same as above but only count the number of results
* @param olatResource
* @param olatResourceDetail
* @param repositoryRef
* @return
*/
public int countResults(Long olatResource, String olatResourceDetail, Long repositoryRef) {
StringBuilder sb = new StringBuilder();
sb.append("select count(res.key) from ").append(QTIResult.class.getName()).append(" as res ")
.append(" inner join res.resultSet as rset")
.append(" inner join rset.identity as ident")
.append(" inner join ident.user as usr")
.append(" where rset.olatResource=:resId and rset.olatResourceDetail=:resSubPath and rset.repositoryRef=:repoKey");
Number count = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class)
.setParameter("resId", olatResource)
.setParameter("resSubPath", olatResourceDetail)
.setParameter("repoKey", repositoryRef)
.getSingleResult();
return count == null ? 0 : count.intValue();
}
/**
* deletes all Results and ResultSets of a test, selftest or survey
* Deletes all Results and ResultSets of a test, selftest or survey
*
* @param olatRes
* @param olatResDet
......@@ -160,37 +200,28 @@ public class QTIResultManager implements UserDataDeletable {
* @return deleted ResultSets
*/
public int deleteAllResults(Long olatRes, String olatResDet, Long repRef) {
DB db = DBFactory.getInstance();
StringBuilder slct = new StringBuilder();
slct.append("select rset from ");
slct.append("org.olat.ims.qti.QTIResultSet rset ");
slct.append("where ");
slct.append("rset.olatResource=? ");
slct.append("and rset.olatResourceDetail=? ");
slct.append("and rset.repositoryRef=? ");
List results = null;
results = db.find(slct.toString(), new Object[] { olatRes, olatResDet, repRef }, new Type[] { StandardBasicTypes.LONG, StandardBasicTypes.STRING,
StandardBasicTypes.LONG });
String delRes = "from res in class org.olat.ims.qti.QTIResult where res.resultSet.key = ?";
String delRset = "from rset in class org.olat.ims.qti.QTIResultSet where rset.key = ?";
int deletedRset = 0;
StringBuilder sb = new StringBuilder();
sb.append("select rset from ").append(QTIResultSet.class.getName()).append(" as rset ");
sb.append(" where rset.olatResource=:resId and rset.olatResourceDetail=:resSubPath and rset.repositoryRef=:repoKey ");
EntityManager em = dbInstance.getCurrentEntityManager();
List<QTIResultSet> sets = em.createQuery(sb.toString(), QTIResultSet.class).setParameter("resId", olatRes)
.setParameter("resSubPath", olatResDet)
.setParameter("repoKey", repRef)
.getResultList();
for (Iterator iter = results.iterator(); iter.hasNext();) {
QTIResultSet rSet = (QTIResultSet) iter.next();
Long rSetKey = rSet.getKey();
db.delete(delRes, rSetKey, StandardBasicTypes.LONG);
db.delete(delRset, rSetKey, StandardBasicTypes.LONG);
deletedRset++;
StringBuilder delSb = new StringBuilder();
delSb.append("delete from ").append(QTIResult.class.getName()).append(" as res where res.resultSet.key=:setKey");
Query delResults = em.createQuery(delSb.toString());
for (QTIResultSet set:sets) {
delResults.setParameter("setKey", set.getKey()).executeUpdate();
em.remove(set);
}
return deletedRset;
return sets.size();
}
/**
* Deletes all Results and ResultSets for certain QTI-ResultSet.
* Deletes all Results AND all ResultSets for certain QTI-ResultSet.
* @param qtiResultSet
*/
public void deleteResults(QTIResultSet qtiResultSet) {
......@@ -289,8 +320,14 @@ public class QTIResultManager implements UserDataDeletable {
* @param assessmentID
* @return
*/
public List findQtiResultSets(Identity identity) {
return DBFactory.getInstance().find("from q in class org.olat.ims.qti.QTIResultSet where q.identity =?", identity.getKey(), StandardBasicTypes.LONG);
public List<QTIResultSet> findQtiResultSets(Identity identity) {
StringBuilder sb = new StringBuilder();
sb.append("select rset from ").append(QTIResultSet.class.getName()).append(" as rset")
.append(" where rset.identity.key=:identityKey");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), QTIResultSet.class)
.setParameter("identityKey", identity.getKey())
.getResultList();
}
/**
......@@ -298,9 +335,9 @@ public class QTIResultManager implements UserDataDeletable {
* @param identity
*/
public void deleteUserData(Identity identity, String newDeletedUserName) {
List qtiResults = findQtiResultSets(identity);
for (Iterator iter = qtiResults.iterator(); iter.hasNext();) {
deleteResultSet((QTIResultSet)iter.next());
List<QTIResultSet> qtiResults = findQtiResultSets(identity);
for (QTIResultSet set:qtiResults) {
deleteResultSet(set);
}
if(log.isDebug()) {
log.debug("Delete all QTI result data in db for identity=" + identity);
......@@ -311,11 +348,16 @@ public class QTIResultManager implements UserDataDeletable {
* Delete all qti-results and qti-result-set entry for certain result-set.
* @param rSet
*/
private void deleteResultSet(QTIResultSet rSet) {
Long rSetKey = rSet.getKey();
DB db = DBFactory.getInstance();
db.delete("from res in class org.olat.ims.qti.QTIResult where res.resultSet.key = ?", rSetKey, StandardBasicTypes.LONG);
db.delete("from rset in class org.olat.ims.qti.QTIResultSet where rset.key = ?", rSetKey, StandardBasicTypes.LONG);
public void deleteResultSet(QTIResultSet rSet) {
EntityManager em = dbInstance.getCurrentEntityManager();
StringBuilder delResultsSb = new StringBuilder();
delResultsSb.append("delete from ").append(QTIResult.class.getName()).append(" as res where res.resultSet.key=:setKey");
em.createQuery(delResultsSb.toString()).setParameter("setKey", rSet.getKey()).executeUpdate();
StringBuilder delSetSb = new StringBuilder();
delSetSb.append("delete from ").append(QTIResultSet.class.getName()).append(" as rset where rset.key=:setKey");
em.createQuery(delSetSb.toString()).setParameter("setKey", rSet.getKey()).executeUpdate();
}
}
\ No newline at end of file
......@@ -35,6 +35,8 @@
</property>
</bean>
<bean id="qtiResultManager" class="org.olat.ims.qti.QTIResultManager"/>
<bean id="qtiResultManager" class="org.olat.ims.qti.QTIResultManager">
<property name="dbInstance" ref="database"/>
</bean>
</beans>
\ No newline at end of file
......@@ -94,7 +94,6 @@ import org.olat.course.tree.TreePosition;
import org.olat.fileresource.types.FileResource;
import org.olat.ims.qti.QTIChangeLogMessage;
import org.olat.ims.qti.QTIConstants;
import org.olat.ims.qti.QTIResult;
import org.olat.ims.qti.QTIResultManager;
import org.olat.ims.qti.editor.beecom.objects.Assessment;
import org.olat.ims.qti.editor.beecom.objects.ChoiceQuestion;
......@@ -257,9 +256,8 @@ public class QTIEditorMainController extends MainLayoutBasicController implement
CourseNode courseNode = course.getEditorTreeModel().getCourseNode(ref.getUserdata());
String repositorySoftKey = (String) courseNode.getModuleConfiguration().get(IQEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
Long repKey = RepositoryManager.getInstance().lookupRepositoryEntryBySoftkey(repositorySoftKey, true).getKey();
List<QTIResult> results = QTIResultManager.getInstance().selectResults(course.getResourceableId(), courseNode.getIdent(), repKey, 1);
restrictedEdit = ((CoordinatorManager.getInstance().getCoordinator().getLocker().isLocked(course, null))
|| (results != null && results.size() > 0)) ? true : false;
|| QTIResultManager.getInstance().countResults(course.getResourceableId(), courseNode.getIdent(), repKey) > 0) ? true : false;
}
if(restrictedEdit) {
break;
......
......@@ -123,7 +123,7 @@ public class QTIArchiveWizardController extends BasicController {
private File exportDir;
private String targetFileName;
private int type;
private Map qtiItemConfigs;
private Map<Class<?>, QTIExportItemFormatConfig> qtiItemConfigs;
private List<QTIResult> results;
private List<QTIItemObject> qtiItemObjectList;
private Link showFileButton;
......@@ -258,7 +258,7 @@ public class QTIArchiveWizardController extends BasicController {
// </OLATBPS-498>
}
} else {
success = hasResultSets(ureq);
success = hasResultSets();
}
if (success) {
......@@ -273,12 +273,12 @@ public class QTIArchiveWizardController extends BasicController {
} else {
QTIResultManager qrm = QTIResultManager.getInstance();
results = qrm.selectResults(olatResource, currentCourseNode.getIdent(), repKey, type);
results = qrm.selectResults(olatResource, currentCourseNode.getIdent(), repKey, null, type);
QTIResult res0 = results.get(0);
qtiItemObjectList = new QTIObjectTreeBuilder().getQTIItemObjectList(new Long(res0.getResultSet().getRepositoryRef()));
qtiItemConfigs = getQTIItemConfigs();
qtiItemConfigs = getQTIItemConfigs(qtiItemObjectList);
if(dummyMode){
finishedVC = createVelocityContainer("finished");
......@@ -431,7 +431,7 @@ public class QTIArchiveWizardController extends BasicController {
return filename;
}
private boolean hasResultSets(UserRequest ureq) {
private boolean hasResultSets() {
if (currentCourseNode instanceof IQTESTCourseNode) {
type = 1;
} else if (currentCourseNode instanceof IQSELFCourseNode) {
......@@ -454,7 +454,7 @@ public class QTIArchiveWizardController extends BasicController {
}
}
private String convert2CtrlChars(String source) {
public static String convert2CtrlChars(String source) {
if (source == null) return null;
StringBuilder sb = new StringBuilder(300);
int len = source.length();
......@@ -481,59 +481,51 @@ public class QTIArchiveWizardController extends BasicController {
return sb.toString();
}
private Map getQTIItemConfigs(){
Map itConfigs = new HashMap();
public static Map<Class<?>, QTIExportItemFormatConfig> getQTIItemConfigs(List<QTIItemObject> itemList){
Map<Class<?>, QTIExportItemFormatConfig> itConfigs = new HashMap<>();
for (Iterator iter = qtiItemObjectList.iterator(); iter.hasNext();) {
QTIItemObject item = (QTIItemObject) iter.next();
for (Iterator<QTIItemObject> iter = itemList.iterator(); iter.hasNext();) {
QTIItemObject item = iter.next();
if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_SCQ)){
if (itConfigs.get(QTIExportSCQItemFormatConfig.class) == null){
QTIExportSCQItemFormatConfig confSCQ = new QTIExportSCQItemFormatConfig(true, false, false, false);
itConfigs.put(QTIExportSCQItemFormatConfig.class, confSCQ);
itConfigs.put(QTIExportSCQItemFormatConfig.class, confSCQ);
}
}
else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_MCQ)){
} else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_MCQ)){
if (itConfigs.get(QTIExportMCQItemFormatConfig.class) == null){
QTIExportMCQItemFormatConfig confMCQ = new QTIExportMCQItemFormatConfig(true, false, false, false);
itConfigs.put(QTIExportMCQItemFormatConfig.class, confMCQ );
itConfigs.put(QTIExportMCQItemFormatConfig.class, confMCQ );
}
}
else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_KPRIM)){
} else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_KPRIM)){
if (itConfigs.get(QTIExportKPRIMItemFormatConfig.class) == null){
QTIExportKPRIMItemFormatConfig confKPRIM = new QTIExportKPRIMItemFormatConfig(true, false, false, false);
itConfigs.put(QTIExportKPRIMItemFormatConfig.class, confKPRIM);
itConfigs.put(QTIExportKPRIMItemFormatConfig.class, confKPRIM);
}
}
else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_ESSAY)){
} else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_ESSAY)){
if (itConfigs.get(QTIExportEssayItemFormatConfig.class) == null){
QTIExportEssayItemFormatConfig confEssay = new QTIExportEssayItemFormatConfig(true, false);
itConfigs.put(QTIExportEssayItemFormatConfig.class, confEssay);
itConfigs.put(QTIExportEssayItemFormatConfig.class, confEssay);
}
}
else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_FIB)){
} else if (item.getItemIdent().startsWith(ItemParser.ITEM_PREFIX_FIB)){
if (itConfigs.get(QTIExportFIBItemFormatConfig.class) == null){
QTIExportFIBItemFormatConfig confFIB = new QTIExportFIBItemFormatConfig(true, false, false);
itConfigs.put(QTIExportFIBItemFormatConfig.class, confFIB);
itConfigs.put(QTIExportFIBItemFormatConfig.class, confFIB);
}
}
//if cannot find the type via the ItemParser, look for the QTIItemObject type
else if (item.getItemType().equals(QTIItemObject.TYPE.A)){
QTIExportEssayItemFormatConfig confEssay = new QTIExportEssayItemFormatConfig(true, false);
itConfigs.put(QTIExportEssayItemFormatConfig.class, confEssay);
}
else if (item.getItemType().equals(QTIItemObject.TYPE.R)){
itConfigs.put(QTIExportEssayItemFormatConfig.class, confEssay);
} else if (item.getItemType().equals(QTIItemObject.TYPE.R)){
QTIExportSCQItemFormatConfig confSCQ = new QTIExportSCQItemFormatConfig(true, false, false, false);
itConfigs.put(QTIExportSCQItemFormatConfig.class, confSCQ);
}
else if (item.getItemType().equals(QTIItemObject.TYPE.C)){
itConfigs.put(QTIExportSCQItemFormatConfig.class, confSCQ);
} else if (item.getItemType().equals(QTIItemObject.TYPE.C)){
QTIExportMCQItemFormatConfig confMCQ = new QTIExportMCQItemFormatConfig(true, false, false, false);
itConfigs.put(QTIExportMCQItemFormatConfig.class, confMCQ );
}
else if (item.getItemType().equals(QTIItemObject.TYPE.B)){
itConfigs.put(QTIExportMCQItemFormatConfig.class, confMCQ );
} else if (item.getItemType().equals(QTIItemObject.TYPE.B)){
QTIExportFIBItemFormatConfig confFIB = new QTIExportFIBItemFormatConfig(true, false, false);
itConfigs.put(QTIExportFIBItemFormatConfig.class, confFIB);
}
else{
itConfigs.put(QTIExportFIBItemFormatConfig.class, confFIB);
} else {
throw new OLATRuntimeException(null,"Can not resolve QTIItem type", null);
}
}
......
......@@ -27,11 +27,11 @@ package org.olat.ims.qti.export;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
......@@ -91,7 +91,7 @@ public class QTIExportManager extends BasicManager{
Long testReKey, File exportDirectory, String charset, String fileNameSuffix) {
boolean resultsFoundAndExported = false;
QTIResultManager qrm = QTIResultManager.getInstance();
List<QTIResult> results = qrm.selectResults(courseResId, olatResourceDetail, testReKey, qef.getType());
List<QTIResult> results = qrm.selectResults(courseResId, olatResourceDetail, testReKey, null, qef.getType());
if(results.size() > 0){
QTIResult res0 = results.get(0);
List<QTIItemObject> qtiItemObjectList = new QTIObjectTreeBuilder().getQTIItemObjectList(new Long(res0.getResultSet().getRepositoryRef()));
......@@ -106,11 +106,11 @@ public class QTIExportManager extends BasicManager{
}
public boolean selectAndExportResults(QTIExportFormatter qef, Long courseResId, String shortTitle,
String olatResourceDetail, RepositoryEntry testRe, ZipOutputStream exportStream, String charset,
String olatResourceDetail, RepositoryEntry testRe, ZipOutputStream exportStream,
String fileNameSuffix) throws IOException {
boolean resultsFoundAndExported = false;
QTIResultManager qrm = QTIResultManager.getInstance();
List<QTIResult> results = qrm.selectResults(courseResId, olatResourceDetail, testRe.getKey(), qef.getType());
List<QTIResult> results = qrm.selectResults(courseResId, olatResourceDetail, testRe.getKey(), null, qef.getType());
if(results.size() > 0){
List<QTIItemObject> qtiItemObjectList = new QTIObjectTreeBuilder().getQTIItemObjectList(testRe);
qef.setQTIItemObjectList(qtiItemObjectList);
......@@ -138,17 +138,27 @@ public class QTIExportManager extends BasicManager{
* @param fileNameSuffix
* @return
*/
public String exportResults(QTIExportFormatter qef, List<QTIResult> results, List<QTIItemObject> qtiItemObjectList, String shortTitle, File exportDirectory, String charset, String fileNameSuffix) {
String targetFileName = null;
qef.setQTIItemObjectList(qtiItemObjectList);
if (results.size() > 0) {
createContentOfExportFile(results,qtiItemObjectList,qef);
targetFileName = writeContentToFile(shortTitle, exportDirectory, charset, qef, fileNameSuffix);
}
return targetFileName;
public String exportResults(QTIExportFormatter qef, List<QTIResult> results, List<QTIItemObject> qtiItemObjectList, String shortTitle, File exportDirectory, String charset, String fileNameSuffix) {
String targetFileName = null;
qef.setQTIItemObjectList(qtiItemObjectList);
if (results.size() > 0) {
createContentOfExportFile(results,qtiItemObjectList,qef);
targetFileName = writeContentToFile(shortTitle, exportDirectory, charset, qef, fileNameSuffix);
}
return targetFileName;
}
public void exportResults(QTIExportFormatter qef, List<QTIResult> results, List<QTIItemObject> qtiItemObjectList,
OutputStream exportStream)
throws IOException {
qef.setQTIItemObjectList(qtiItemObjectList);
if (results.size() > 0) {
createContentOfExportFile(results,qtiItemObjectList,qef);
IOUtils.write(qef.getReport(), exportStream);
}
}
/**
* @param locale Locale used for export file headers / default values
......@@ -158,7 +168,6 @@ public class QTIExportManager extends BasicManager{
* @return String
*/
private void createContentOfExportFile(List<QTIResult> qtiResults, List<QTIItemObject> qtiItemObjectList, QTIExportFormatter qef) {
qef.openReport();
//formatter has information about how to format the different qti objects
......@@ -167,12 +176,8 @@ public class QTIExportManager extends BasicManager{
while (qtiResults.size() > 0){
List<QTIResult> assessIDresults = stripNextAssessID(qtiResults);
qef.openResultSet(new QTIExportSet(assessIDresults.get(0)));
for (Iterator<QTIItemObject> iter = qtiItemObjectList.iterator(); iter.hasNext();) {
QTIItemObject element = iter.next();
for(QTIItemObject element:qtiItemObjectList) {
QTIResult qtir = element.extractQTIResult(assessIDresults);
qef.visit(qeif.getExportItem(qtir,element));
}
......
......@@ -95,7 +95,7 @@ public class QTIObjectTreeBuilder {
return getQTIItemObjectList(resolver);
}
private final List<QTIItemObject> getQTIItemObjectList(Resolver resolver) {
public final List<QTIItemObject> getQTIItemObjectList(Resolver resolver) {
Document doc = resolver.getQTIDocument();
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
......
......@@ -28,6 +28,8 @@ import org.olat.core.gui.components.tree.TreeModel;
import org.olat.core.gui.components.tree.TreeNode;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.id.OLATResourceable;
import org.olat.core.util.resource.OresHelper;
import org.olat.course.nodes.CourseNodeConfiguration;
import org.olat.course.nodes.CourseNodeFactory;
import org.olat.course.nodes.IQSELFCourseNode;
......@@ -60,6 +62,7 @@ import de.bps.onyx.plugin.OnyxModule;
public class QTIStatisticResourceResult implements StatisticResourceResult {
private final QTICourseNode courseNode;
private final OLATResourceable courseOres;
private final QTIStatisticsManager qtiStatisticsManager;
private StatisticAssessment statisticAssessment;
......@@ -70,9 +73,10 @@ public class QTIStatisticResourceResult implements StatisticResourceResult {
private QTIType type;
public QTIStatisticResourceResult(QTICourseNode courseNode, QTIStatisticSearchParams searchParams) {
public QTIStatisticResourceResult(OLATResourceable courseOres, QTICourseNode courseNode, QTIStatisticSearchParams searchParams) {
this.courseNode = courseNode;
this.searchParams = searchParams;
this.courseOres = OresHelper.clone(courseOres);
qtiStatisticsManager = CoreSpringFactory.getImpl(QTIStatisticsManager.class);
qtiRepositoryEntry = courseNode.getReferencedRepositoryEntry();
......@@ -97,6 +101,10 @@ public class QTIStatisticResourceResult implements StatisticResourceResult {
return type;
}
public OLATResourceable getCourseOres() {
return courseOres;
}
public QTICourseNode getTestCourseNode() {
return courseNode;
}
......
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.ims.qti.statistics;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletResponse;
import org.olat.basesecurity.SecurityGroup;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.Formatter;
import org.olat.core.util.StringHelper;
import org.olat.course.nodes.CourseNode;
import org.olat.ims.qti.QTIResult;
import org.olat.ims.qti.QTIResultManager;
import org.olat.ims.qti.export.QTIArchiveWizardController;
import org.olat.ims.qti.export.QTIExportFormatter;
import org.olat.ims.qti.export.QTIExportFormatterCSVType1;
import org.olat.ims.qti.export.QTIExportFormatterCSVType2;
import org.olat.ims.qti.export.QTIExportManager;
import org.olat.ims.qti.export.helper.QTIItemObject;
import org.olat.ims.qti.export.helper.QTIObjectTreeBuilder;
/**
*
* Initial date: 17.03.2014<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class QTIStatisticsResource implements MediaResource {
private static final OLog log = Tracing.createLoggerFor(QTIStatisticsResource.class);
private final Locale locale;
private final String encoding = "UTF-8";
private final QTIStatisticResourceResult resourceResult;
public QTIStatisticsResource(QTIStatisticResourceResult resourceResult, Locale locale) {
this.resourceResult = resourceResult;
this.locale = locale;
}
@Override
public String getContentType() {
return "application/zip";
}
@Override
public Long getSize() {
return null;
}
@Override
public InputStream getInputStream() {
return null;
}
@Override
public Long getLastModified() {
return null;
}
@Override
public void prepare(HttpServletResponse hres) {
try {
hres.setCharacterEncoding(encoding);
} catch (Exception e) {
log.error("", e);
}
CourseNode courseNode = resourceResult.getTestCourseNode();
String label = courseNode.getType() + "_"
+ StringHelper.transformDisplayNameToFileSystemName(courseNode.getShortName())
+ "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis()))
+ ".csv";
String urlEncodedLabel = StringHelper.urlEncodeUTF8(label);
hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + urlEncodedLabel);
hres.setHeader("Content-Description", urlEncodedLabel);
try {
String sep = "\\t"; // fields separated by
String emb = "\""; // fields embedded by
String esc = "\\"; // fields escaped by
String car = "\\r\\n"; // carriage return
sep = QTIArchiveWizardController.convert2CtrlChars(sep);
car = QTIArchiveWizardController.convert2CtrlChars(car);
int exportType = 1;
QTIExportFormatter formatter;
if (QTIType.test.equals(resourceResult.getType())){
exportType = 1;
formatter = new QTIExportFormatterCSVType1(locale, sep, emb, esc, car, true);
} else if (QTIType.survey.equals(resourceResult.getType())) {
exportType = 2;
formatter = new QTIExportFormatterCSVType2(locale, null, sep, emb, esc, car, true);
} else {
return;
}
Long qtiRepoEntryKey = resourceResult.getQTIRepositoryEntry().getKey();
List<QTIItemObject> itemList = new QTIObjectTreeBuilder().getQTIItemObjectList(resourceResult.getResolver());
formatter.setMapWithExportItemConfigs(QTIArchiveWizardController.getQTIItemConfigs(itemList));
QTIResultManager qrm = QTIResultManager.getInstance();
QTIStatisticSearchParams params = resourceResult.getSearchParams();
List<SecurityGroup> limitToSecGroups = params.isMayViewAllUsersAssessments()
? null : params.getLimitToSecGroups();
List<QTIResult> results = qrm.selectResults(resourceResult.getCourseOres().getResourceableId(),
courseNode.getIdent(), qtiRepoEntryKey, limitToSecGroups, exportType);
QTIExportManager.getInstance().exportResults(formatter, results, itemList, hres.getOutputStream());
} catch (Exception e) {
log.error("", e);
}
}
@Override
public void release() {
//
}
}
......@@ -34,12 +34,15 @@ import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.chart.BarSeries;
import org.olat.core.gui.components.chart.BarSeries.Stringuified;
import org.olat.core.gui.components.chart.StatisticsComponent;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.creator.ControllerCreator;
import org.olat.core.gui.media.MediaResource;
import org.olat.course.nodes.QTICourseNode;
import org.olat.course.nodes.iq.IQEditController;
import org.olat.ims.qti.editor.beecom.objects.Item;
......@@ -47,6 +50,7 @@ import org.olat.ims.qti.editor.beecom.objects.QTIDocument;
import org.olat.ims.qti.editor.beecom.objects.Section;
import org.olat.ims.qti.statistics.QTIStatisticResourceResult;
import org.olat.ims.qti.statistics.QTIStatisticsManager;
import org.olat.ims.qti.statistics.QTIStatisticsResource;
import org.olat.ims.qti.statistics.QTIType;
import org.olat.ims.qti.statistics.model.StatisticAssessment;
import org.olat.ims.qti.statistics.model.StatisticItem;
......@@ -64,6 +68,7 @@ public class QTI12AssessmentStatisticsController extends BasicController {
private final Float cutValue;
private final String mediaBaseURL;
private final Link downloadRawLink;
private final VelocityContainer mainVC;
private final SeriesFactory seriesfactory;
......@@ -83,6 +88,9 @@ public class QTI12AssessmentStatisticsController extends BasicController {
mainVC = createVelocityContainer("statistics_assessment");
mainVC.put("loadd3js", new StatisticsComponent("d3loader"));
mainVC.contextPut("printMode", new Boolean(printMode));
downloadRawLink = LinkFactory.createLink("download.raw.data", mainVC, this);
downloadRawLink.setCustomEnabledLinkCSS("b_content_download");
mainVC.put("download", downloadRawLink);
//cut value
QTICourseNode testNode = resourceResult.getTestCourseNode();
......@@ -263,8 +271,15 @@ public class QTI12AssessmentStatisticsController extends BasicController {
protected void event(UserRequest ureq, Component source, Event event) {
if("print".equals(event.getCommand())){
printPages(ureq);
} else if(downloadRawLink == source) {
doDownloadRawData(ureq);
}
}
private void doDownloadRawData(UserRequest ureq) {
MediaResource resource = new QTIStatisticsResource(resourceResult, getLocale());
ureq.getDispatchResult().setResultingMediaResource(resource);
}
private void printPages(UserRequest ureq) {
ControllerCreator printControllerCreator = new ControllerCreator() {
......
......@@ -157,7 +157,7 @@ public class QTI12StatisticsToolController extends BasicController implements St
private void doLaunchStatistics(UserRequest ureq, WindowControl wControl) {
if(result == null) {
result = new QTIStatisticResourceResult(courseNode, searchParams);
result = new QTIStatisticResourceResult(courseRes, courseNode, searchParams);
}
GenericTreeModel treeModel = new GenericTreeModel();
......
......@@ -11,9 +11,10 @@
}
}
</script>
<div id='$r.getId("print")'>
<a class="b_small_icon o_print_icon" href='javascript:$r.getId("print")()' title='$r.translateInAttribute("print")'><span>Print</span></a>
</div>
<a class="b_with_small_icon_left o_print_icon" href='javascript:$r.getId("print")()' title='$r.translateInAttribute("print")'>
<span>$r.translate("print")</span>
</a>
$r.render("download")
</div>
#end
......
......@@ -57,7 +57,7 @@ answer.yes=Ja
answer.no=Nein
wrong.answer=Liste of falsche Antworten:
answer.points=({0} Punkte)
download.raw.data=Raw Daten herunterladen
fig.title=Kennzahlen
fig.participants=Teilnehmer
fig.passed=Bestanden
......@@ -74,3 +74,4 @@ fig.stddev=Standardabweichung
fig.avg=Mittelwert
fig.span=Spannweite
fig.median=Median
print=Drcken
......@@ -27,6 +27,14 @@ div.o_qti_statistics {
&.qti-qtype5 {padding-left:20px; background: url(../img/kprimItem.png) no-repeat;}
}
a.b_content_download {
display: inline;
}
a.o_print_icon span {
display: inline;
}
}
/* QTI legacy styles */
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment