diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java index 6a7d93d4b4950608531e22e8a9907144fd460da3..f9c11de8f0838ae1ac6a7a21cc73133dacd7078a 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java @@ -358,8 +358,12 @@ public class IdentityListCourseNodeController extends FormBasicController implem AssessmentToolOptions options = new AssessmentToolOptions(); options.setAdmin(assessmentCallback.isAdmin()); if(group == null) { - options.setIdentities(assessedIdentities); - fillAlternativeToAssessableIdentityList(options); + if(assessmentCallback.isAdmin()) { + options.setNonMembers(params.isNonMembers()); + } else { + options.setIdentities(assessedIdentities); + fillAlternativeToAssessableIdentityList(options, params); + } } else { options.setGroup(group); } @@ -383,29 +387,7 @@ public class IdentityListCourseNodeController extends FormBasicController implem flc.contextPut("toolCmpNames", toolCmpNames); } - /* - private boolean accept(AssessmentEntry entry, SearchAssessedIdentityParams params) { - boolean ok = true; - - if(params.isPassed() && (entry == null || entry.getPassed() == null || !entry.getPassed().booleanValue())) { - ok &= false; - } - - if(params.isFailed() && (entry == null || entry.getPassed() == null || entry.getPassed().booleanValue())) { - ok &= false; - } - - if(params.getAssessmentStatus() != null && params.getAssessmentStatus().size() > 0) { - if(entry == null || entry.getAssessmentStatus() == null) { - ok &= false; - } else { - ok &= !params.getAssessmentStatus().contains(entry.getAssessmentStatus()); - } - } - return ok; - }*/ - - private void fillAlternativeToAssessableIdentityList(AssessmentToolOptions options) { + private void fillAlternativeToAssessableIdentityList(AssessmentToolOptions options, SearchAssessedIdentityParams params) { List<Group> baseGroups = new ArrayList<>(); if((assessmentCallback.canAssessRepositoryEntryMembers() && (assessmentCallback.getCoachedGroups() == null || assessmentCallback.getCoachedGroups().isEmpty())) @@ -417,7 +399,8 @@ public class IdentityListCourseNodeController extends FormBasicController implem baseGroups.add(coachedGroup.getBaseGroup()); } } - options.setAlternativeToIdentities(baseGroups, assessmentCallback.canAssessNonMembers()); + options.setGroups(baseGroups); + options.setNonMembers(params.isNonMembers()); } @Override diff --git a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java index 220633aebe0d27c5db7641743a7cd42583347d60..f9f1c6515494e5485e428350c99f9fec92d9b4c4 100644 --- a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java +++ b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java @@ -162,7 +162,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe Roles roles = ureq.getUserSession().getRoles(); Translator trans = Util.createPackageTranslator(IQTESTCourseNode.class, ureq.getLocale()); if (roles.isGuestOnly()) { - if(isGuestAllowedForQTI21()) { + if(isGuestAllowedForQTI21(getReferencedRepositoryEntry())) { controller = new QTI21AssessmentRunController(ureq, wControl, userCourseEnv, this); } else { String title = trans.translate("guestnoaccess.title"); @@ -200,8 +200,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe return new NodeRunConstructionResult(ctrl); } - private boolean isGuestAllowedForQTI21() { - RepositoryEntry testEntry = getReferencedRepositoryEntry(); + private boolean isGuestAllowedForQTI21(RepositoryEntry testEntry) { OLATResource ores = testEntry.getOlatResource(); if(ImsQTI21Resource.TYPE_NAME.equals(ores.getResourceableTypeName())) { QTI21DeliveryOptions options = CoreSpringFactory.getImpl(QTI21Service.class).getDeliveryOptions(testEntry); @@ -291,10 +290,11 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe if(ImsQTI21Resource.TYPE_NAME.equals(qtiTestEntry.getOlatResource().getResourceableTypeName())) { RepositoryEntry courseEntry = userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); QTI21StatisticSearchParams searchParams = new QTI21StatisticSearchParams(qtiTestEntry, courseEntry, getIdent()); - QTI21DeliveryOptions deliveryOptions = CoreSpringFactory.getImpl(QTI21Service.class) - .getDeliveryOptions(qtiTestEntry); boolean admin = userCourseEnv.isAdmin(); - QTI21StatisticsSecurityCallback secCallback = new QTI21StatisticsSecurityCallback(admin, admin && deliveryOptions.isAllowAnonym()); + if(options.getParticipantsGroups() != null) { + searchParams.setLimitToGroups(options.getParticipantsGroups()); + } + QTI21StatisticsSecurityCallback secCallback = new QTI21StatisticsSecurityCallback(admin, admin && isGuestAllowedForQTI21(qtiTestEntry)); return new QTI21StatisticResourceResult(qtiTestEntry, courseEntry, this, searchParams, secCallback); } @@ -637,7 +637,6 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe // 1) prepare result export CourseEnvironment courseEnv = course.getCourseEnvironment(); - List<Identity> identities = ScoreAccountingHelper.loadUsers(courseEnv, options); //create SyntheticUserRequest with UserSession to avoid Nullpointer in AssessmentResultController UserRequest ureq = new SyntheticUserRequest(new TransientIdentity(), locale, new UserSession()); Roles roles = new Roles(false, false, false, false, false, false, false); @@ -656,14 +655,18 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe } else if(ImsQTI21Resource.TYPE_NAME.equals(re.getOlatResource().getResourceableTypeName())) { // 2a) create export resource QTI21Service qtiService = CoreSpringFactory.getImpl(QTI21Service.class); + + List<Identity> identities = ScoreAccountingHelper.loadUsers(courseEnv, options); new QTI21ResultsExportMediaResource(courseEnv, identities, this, qtiService, ureq, locale).exportTestResults(exportStream); - // excel results - QTI21ArchiveFormat qaf = new QTI21ArchiveFormat(locale, true, true, true); + // excel results RepositoryEntry courseEntry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); - qaf.export(courseEntry, getIdent(), re, exportStream); + QTI21StatisticSearchParams searchParams = new QTI21StatisticSearchParams(options, re, courseEntry, getIdent()); + QTI21ArchiveFormat qaf = new QTI21ArchiveFormat(locale, searchParams); + qaf.exportCourseElement(exportStream); return true; } else { // 2b) create export resource + List<Identity> identities = ScoreAccountingHelper.loadUsers(courseEnv, options); new QTI12ResultsExportMediaResource(courseEnv, locale, identities, this).exportTestResults(exportStream); // excel results String shortTitle = getShortTitle(); diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java index 01a5aabfe9f7457c9b352f0650459876b515b186..501c0288b123bdc0cc6162b173d7af5679b6d292 100644 --- a/src/main/java/org/olat/course/run/CourseRuntimeController.java +++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java @@ -1432,7 +1432,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im if (reSecurity.isEntryAdmin() || reSecurity.isCourseCoach() || reSecurity.isGroupCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) { removeCustomCSS(); UserCourseEnvironmentImpl uce = getUserCourseEnvironment(); - StatisticCourseNodesController ctrl = new StatisticCourseNodesController(ureq, swControl, toolbarPanel, uce, types); + StatisticCourseNodesController ctrl = new StatisticCourseNodesController(ureq, swControl, toolbarPanel, reSecurity, uce, types); listenTo(ctrl); statsToolCtr = pushController(ureq, translate(i18nCrumbKey), ctrl); currentToolCtr = statsToolCtr; diff --git a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java index e88fbaddeb15fee0304c21b0bdec72b5979166b3..71d93674f523e1973c1e9db7a9ffec7e05bcbdf4 100644 --- a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java +++ b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java @@ -25,11 +25,9 @@ package org.olat.course.run.userview; -import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.olat.basesecurity.Group; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.gui.control.WindowControl; @@ -233,26 +231,6 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment { return courseRepoEntry; } - public List<Group> getCoachedBaseGroups(boolean withRepo, boolean withBusinessGroups) { - List<Group> groups; - if(isCoach()) { - boolean repoCoach = false; - groups = new ArrayList<Group>(); - if(withBusinessGroups && sizeCoachedGroups() > 0) { - for(BusinessGroup businessGroup: getCoachedGroups()) { - groups.add(businessGroup.getBaseGroup()); - } - } - - if(withRepo && repoCoach) { - //TODO groups - } - } else { - groups = Collections.emptyList(); - } - return groups; - } - public int sizeCoachedGroups() { return coachedGroups == null ? 0 : coachedGroups.size(); } diff --git a/src/main/java/org/olat/course/statistic/StatisticCourseNodesController.java b/src/main/java/org/olat/course/statistic/StatisticCourseNodesController.java index 7c92ed6a4721f5e2d440b1a361bf80b572845b4e..e580f83eec84a622978638fc5f9aeedeedd548f2 100644 --- a/src/main/java/org/olat/course/statistic/StatisticCourseNodesController.java +++ b/src/main/java/org/olat/course/statistic/StatisticCourseNodesController.java @@ -51,7 +51,11 @@ import org.olat.course.ICourse; import org.olat.course.nodes.CourseNode; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; +import org.olat.group.BusinessGroup; import org.olat.ims.qti.statistics.QTIType; +import org.olat.repository.RepositoryService; +import org.olat.repository.model.RepositoryEntrySecurity; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -67,22 +71,31 @@ public class StatisticCourseNodesController extends BasicController implements A private final QTIType[] types; private final StatisticResourceOption options; + @Autowired + private RepositoryService repositoryService; + public StatisticCourseNodesController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, - UserCourseEnvironment userCourseEnv, QTIType ... types) { + RepositoryEntrySecurity reSecurity, UserCourseEnvironment userCourseEnv, QTIType ... types) { super(ureq, wControl); this.types = types; this.stackPanel = stackPanel; options = new StatisticResourceOption(); - - boolean admin = userCourseEnv.isAdmin(); - boolean coach = userCourseEnv.isCoach(); - if(coach && !admin) { + + if(!reSecurity.isEntryAdmin() && !reSecurity.isOwner()) { + List<Group> groups = new ArrayList<>(); UserCourseEnvironmentImpl userCourseEnvImpl = (UserCourseEnvironmentImpl)userCourseEnv; - List<Group> coachedGroups = userCourseEnvImpl.getCoachedBaseGroups(true, true); - if(coachedGroups == null || coachedGroups.isEmpty()) { - options.setParticipantsGroups(coachedGroups); + if(reSecurity.isCourseCoach()) { + Group bGroup = repositoryService.getDefaultGroup(userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry()); + groups.add(bGroup); + } + if(reSecurity.isGroupCoach()) { + List<BusinessGroup> businessGroups = userCourseEnvImpl.getCoachedGroups(); + for(BusinessGroup businessGroup:businessGroups) { + groups.add(businessGroup.getBaseGroup()); + } } + options.setParticipantsGroups(groups); } courseTree = new MenuTree("assessmentStatisticsTree"); diff --git a/src/main/java/org/olat/ims/qti/export/QTIArchiver.java b/src/main/java/org/olat/ims/qti/export/QTIArchiver.java index 5ada2fa7b8ba663fd20b03c04f09e9df2d8533a0..0d3c20272eabe46eee74e62fa3c2e740f16d35ba 100644 --- a/src/main/java/org/olat/ims/qti/export/QTIArchiver.java +++ b/src/main/java/org/olat/ims/qti/export/QTIArchiver.java @@ -64,6 +64,7 @@ import org.olat.ims.qti.editor.beecom.parser.ItemParser; import org.olat.ims.qti.export.helper.QTIItemObject; import org.olat.ims.qti.export.helper.QTIObjectTreeBuilder; import org.olat.ims.qti21.manager.archive.QTI21ArchiveFormat; +import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.repository.RepositoryEntry; import org.olat.repository.handlers.RepositoryHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; @@ -223,7 +224,8 @@ public class QTIArchiver { } else if(ImsQTI21Resource.TYPE_NAME.equals(testRe.getOlatResource().getResourceableTypeName())) { type = Type.qti21; RepositoryEntry courseEntry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); - success = new QTI21ArchiveFormat(locale, participants, allUsers, anonymUsers).hasResults(courseEntry, courseNode.getIdent(), testRe); + QTI21StatisticSearchParams searchParams = new QTI21StatisticSearchParams(testRe, courseEntry, courseNode.getIdent(), allUsers, anonymUsers); + success = new QTI21ArchiveFormat(locale, searchParams).hasResults(); } else { type = Type.qti12; success = qrm.hasResultSets(courseOres.getResourceableId(), courseNode.getIdent(), testRe.getKey()); @@ -268,7 +270,8 @@ public class QTIArchiver { ICourse course = CourseFactory.loadCourse(courseOres); RepositoryEntry testRe = courseNode.getReferencedRepositoryEntry(); RepositoryEntry courseEntry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); - return (new QTI21ArchiveFormat(locale, participants, allUsers, anonymUsers)).export(courseEntry, courseNode.getIdent(), testRe); + QTI21StatisticSearchParams searchParams = new QTI21StatisticSearchParams(testRe, courseEntry, courseNode.getIdent(), allUsers, anonymUsers); + return new QTI21ArchiveFormat(locale, searchParams).exportCourseElement(); } public MediaResource exportQTI12() throws IOException { diff --git a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12StatisticsToolController.java b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12StatisticsToolController.java index bd6d42ec216ce551ef915114fa09ce6277d56e39..b4a8ab9cfe8cf299423bf8bf04634aad724bf08e 100644 --- a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12StatisticsToolController.java +++ b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12StatisticsToolController.java @@ -51,7 +51,6 @@ import org.olat.course.statistic.StatisticResourceNode; import org.olat.ims.qti.statistics.QTIStatisticResourceResult; import org.olat.ims.qti.statistics.QTIStatisticSearchParams; import org.olat.modules.assessment.AssessmentToolOptions; -import org.olat.modules.assessment.AssessmentToolOptions.AlternativeToIdentities; import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; @@ -90,10 +89,9 @@ public class QTI12StatisticsToolController extends BasicController implements Ac if(asOptions.getGroup() != null) { List<Group> bGroups = Collections.singletonList(asOptions.getGroup().getBaseGroup()); searchParams.setLimitToGroups(bGroups); - } else if(asOptions.getAlternativeToIdentities() != null) { - AlternativeToIdentities alt = asOptions.getAlternativeToIdentities(); - searchParams.setMayViewAllUsersAssessments(alt.isMayViewAllUsersAssessments()); - searchParams.setLimitToGroups(alt.getGroups()); + } else if(asOptions.getGroups() != null) { + searchParams.setMayViewAllUsersAssessments(asOptions.isNonMembers()); + searchParams.setLimitToGroups(asOptions.getGroups()); } statsButton = LinkFactory.createButton("menu.title", null, this); diff --git a/src/main/java/org/olat/ims/qti21/manager/AssessmentResponseDAO.java b/src/main/java/org/olat/ims/qti21/manager/AssessmentResponseDAO.java index 63fd36db8c7e972807222e52a12f295bc933fadc..5a1248fa6f1f32b4cec592a26c4ccf5d717d671d 100644 --- a/src/main/java/org/olat/ims/qti21/manager/AssessmentResponseDAO.java +++ b/src/main/java/org/olat/ims/qti21/manager/AssessmentResponseDAO.java @@ -22,6 +22,7 @@ package org.olat.ims.qti21.manager; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.stream.Collectors; import javax.persistence.TypedQuery; @@ -31,9 +32,9 @@ import org.olat.core.util.StringHelper; import org.olat.ims.qti21.AssessmentItemSession; import org.olat.ims.qti21.AssessmentResponse; import org.olat.ims.qti21.AssessmentTestSession; +import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.ims.qti21.model.ResponseLegality; import org.olat.ims.qti21.model.jpa.AssessmentResponseImpl; -import org.olat.repository.RepositoryEntryRef; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -95,8 +96,7 @@ public class AssessmentResponseDAO { * @param testEntry * @return */ - public boolean hasResponses(RepositoryEntryRef courseEntry, String subIdent, RepositoryEntryRef testEntry, - boolean participant, boolean users, boolean anonymUsers) { + public boolean hasResponses(QTI21StatisticSearchParams searchParams) { StringBuilder sb = new StringBuilder(); sb.append("select response.key from qtiassessmentresponse response ") .append(" inner join response.assessmentItemSession itemSession") @@ -104,35 +104,44 @@ public class AssessmentResponseDAO { .append(" where testSession.repositoryEntry.key=:repoEntryKey") .append(" and testSession.testEntry.key=:testEntryKey") .append(" and testSession.subIdent=:subIdent") - .append(" and testSession.finishTime is not null") + .append(" and testSession.finishTime is not null and testSession.authorMode=false") .append(" and ("); - if(users) { + + if(searchParams.isViewAllUsers()) { sb.append(" testSession.identity.key is not null"); - } else if(participant) { + } else if(searchParams.getLimitToGroups() != null) { + sb.append(" testSession.identity.key in (select membership.identity.key from bgroupmember as membership, repoentrytogroup as rel") + .append(" where rel.entry.key=:repoEntryKey and rel.group.key=membership.group.key and rel.group.key in (:limitGroupKeys)") + .append(" and membership.role='").append(GroupRoles.participant.name()).append("'") + .append(" )"); + } else if(searchParams.getLimitToIdentities() != null) { + sb.append(" testSession.identity.key in (select membership.identity.key from bgroupmember as membership, repoentrytogroup as rel") + .append(" where rel.entry.key=:repoEntryKey and rel.group.key=membership.group.key and membership.identity.key in (:limitIdentityKeys)") + .append(" and membership.role='").append(GroupRoles.participant.name()).append("'") + .append(" )"); + } else { sb.append(" testSession.identity.key in (select membership.identity.key from bgroupmember as membership, repoentrytogroup as rel") .append(" where rel.entry.key=:repoEntryKey and rel.group.key=membership.group.key ") .append(" and membership.role='").append(GroupRoles.participant.name()).append("'") .append(" )"); } - if(anonymUsers) { - if(participant || users) sb.append(" or "); - sb.append(" testSession.anonymousIdentifier is not null"); + if(searchParams.isViewAnonymUsers()) { + sb.append(" or testSession.anonymousIdentifier is not null"); } - sb.append("))"); + sb.append(")"); List<Long> responses = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Long.class) - .setParameter("repoEntryKey", courseEntry.getKey()) - .setParameter("testEntryKey", testEntry.getKey()) - .setParameter("subIdent", subIdent) + .setParameter("repoEntryKey", searchParams.getCourseEntry().getKey()) + .setParameter("testEntryKey", searchParams.getTestEntry().getKey()) + .setParameter("subIdent", searchParams.getNodeIdent()) .setFirstResult(0) .setMaxResults(1) .getResultList(); return responses.size() > 0 && responses.get(0) != null; } - public List<AssessmentResponse> getResponse(RepositoryEntryRef courseEntry, String subIdent, RepositoryEntryRef testEntry, - boolean participant, boolean users, boolean anonymUsers) { + public List<AssessmentResponse> getResponse(QTI21StatisticSearchParams searchParams) { StringBuilder sb = new StringBuilder(); sb.append("select response from qtiassessmentresponse response ") .append(" inner join fetch response.assessmentItemSession itemSession") @@ -141,26 +150,37 @@ public class AssessmentResponseDAO { .append(" left join assessmentEntry.identity as ident") .append(" left join ident.user as usr") .append(" where testSession.testEntry.key=:testEntryKey") - .append(" and testSession.finishTime is not null"); - if(courseEntry != null) { + .append(" and testSession.finishTime is not null and testSession.authorMode=false"); + if(searchParams.getCourseEntry() != null) { sb.append(" and testSession.repositoryEntry.key=:repoEntryKey"); } - if(StringHelper.containsNonWhitespace(subIdent)) { + if(StringHelper.containsNonWhitespace(searchParams.getNodeIdent())) { sb.append(" and testSession.subIdent=:subIdent"); } - sb.append(" and ("); - if(users) { + + if(searchParams.getLimitToGroups() != null) { + sb.append(" testSession.identity.key in (select membership.identity.key from bgroupmember as membership, repoentrytogroup as rel") + .append(" where rel.entry.key=:repoEntryKey and rel.group.key=membership.group.key and rel.group.key in (:limitGroupKeys)"); + if(!searchParams.isViewAllUsers()) { + sb.append(" and membership.role='").append(GroupRoles.participant.name()).append("'"); + } + sb.append(" )"); + } else if(searchParams.getLimitToIdentities() != null) { + sb.append(" testSession.identity.key in (select membership.identity.key from bgroupmember as membership, repoentrytogroup as rel") + .append(" where rel.entry.key=:repoEntryKey and rel.group.key=membership.group.key and membership.identity.key in (:limitIdentityKeys)") + .append(" and membership.role='").append(GroupRoles.participant.name()).append("'") + .append(" )"); + } else if(searchParams.isViewAllUsers()) { sb.append(" testSession.identity.key is not null"); - } else if(participant) { + } else { sb.append(" testSession.identity.key in (select membership.identity.key from bgroupmember as membership, repoentrytogroup as rel") .append(" where rel.entry.key=:repoEntryKey and rel.group.key=membership.group.key ") .append(" and membership.role='").append(GroupRoles.participant.name()).append("'") .append(" )"); } - if(anonymUsers) { - if(participant || users) sb.append(" or "); - sb.append(" testSession.anonymousIdentifier is not null"); + if(searchParams.isViewAnonymUsers()) { + sb.append(" or testSession.anonymousIdentifier is not null"); } sb.append(")"); @@ -169,12 +189,24 @@ public class AssessmentResponseDAO { TypedQuery<AssessmentResponse> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), AssessmentResponse.class) - .setParameter("testEntryKey", testEntry.getKey()); - if(courseEntry != null) { - query.setParameter("repoEntryKey", courseEntry.getKey()); + .setParameter("testEntryKey", searchParams.getTestEntry().getKey()); + if(searchParams.getCourseEntry() != null) { + query.setParameter("repoEntryKey", searchParams.getCourseEntry().getKey()); + } else { + query.setParameter("repoEntryKey", searchParams.getTestEntry().getKey()); + } + if(StringHelper.containsNonWhitespace(searchParams.getNodeIdent())) { + query.setParameter("subIdent", searchParams.getNodeIdent()); + } + if(searchParams.getLimitToGroups() != null && searchParams.getLimitToGroups().size() > 0) { + List<Long> keys = searchParams.getLimitToGroups().stream() + .map(group -> group.getKey()).collect(Collectors.toList()); + query.setParameter("limitGroupKeys", keys); } - if(StringHelper.containsNonWhitespace(subIdent)) { - query.setParameter("subIdent", subIdent); + if(searchParams.getLimitToIdentities() != null && searchParams.getLimitToIdentities().size() > 0) { + List<Long> keys = searchParams.getLimitToIdentities().stream() + .map(group -> group.getKey()).collect(Collectors.toList()); + query.setParameter("limitIdentityKeys", keys); } return query.getResultList(); } diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21StatisticsManagerImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21StatisticsManagerImpl.java index 82ea2eaca943e461288413ed3cc681d30a77e0b2..239b9606b34cebb2048d9cc059eb97882166323c 100644 --- a/src/main/java/org/olat/ims/qti21/manager/QTI21StatisticsManagerImpl.java +++ b/src/main/java/org/olat/ims/qti21/manager/QTI21StatisticsManagerImpl.java @@ -116,13 +116,21 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { .append(" )"); } else if(searchParams.getLimitToGroups() != null && searchParams.getLimitToGroups().size() > 0) { sb.append(" and asession.identity.key in ( select membership.identity.key from bgroupmember membership") - .append(" where membership.group in (:baseGroups)") + .append(" where membership.group in (:baseGroups) and membership.role='").append(GroupRole.participant).append("'") .append(" )"); } else { //limit to participants - sb.append(" and asession.identity.key in ( select membership.identity.key from repoentrytogroup as rel, bgroup as reBaseGroup, bgroupmember membership ") - .append(" where rel.entry.key=:repositoryEntryKey and rel.group.key=reBaseGroup.key and membership.group.key=reBaseGroup.key and membership.role='").append(GroupRole.participant).append("'") - .append(" )"); + sb.append(" and (asession.identity.key in ( select membership.identity.key from repoentrytogroup as rel, bgroupmember membership ") + .append(" where rel.entry.key=:repositoryEntryKey and rel.group.key=membership.group.key and membership.role='").append(GroupRole.participant).append("'") + //.append(" where rel.entry.key=:repositoryEntryKey and rel.group.key=reBaseGroup.key and membership.group.key=reBaseGroup.key and membership.role='").append(GroupRole.participant).append("'") + .append(" )"); + // add non members + if(searchParams.isViewNonMembers()) { + sb.append(" or asession.identity.key not in (select membership.identity.key from repoentrytogroup as rel, bgroupmember as membership") + .append(" where rel.entry.key=:repositoryEntryKey and rel.group.key=membership.group.key") + .append(" )"); + } + sb.append(")"); } return sb; diff --git a/src/main/java/org/olat/ims/qti21/manager/archive/QTI21ArchiveFormat.java b/src/main/java/org/olat/ims/qti21/manager/archive/QTI21ArchiveFormat.java index 33b668a1ee3aa14f66e7b2a5135b881f839a51ce..4c279200707c92b31dc9ac4986730c3d7f5c9a8d 100644 --- a/src/main/java/org/olat/ims/qti21/manager/archive/QTI21ArchiveFormat.java +++ b/src/main/java/org/olat/ims/qti21/manager/archive/QTI21ArchiveFormat.java @@ -32,7 +32,6 @@ import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.apache.commons.io.IOUtils; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.translator.Translator; @@ -83,6 +82,7 @@ import org.olat.ims.qti21.manager.archive.interactions.PositionObjectInteraction import org.olat.ims.qti21.manager.archive.interactions.SelectPointInteractionArchive; import org.olat.ims.qti21.manager.archive.interactions.SliderInteractionArchive; import org.olat.ims.qti21.manager.archive.interactions.TextEntryInteractionArchive; +import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.ims.qti21.ui.QTI21RuntimeController; import org.olat.modules.assessment.AssessmentEntry; import org.olat.repository.RepositoryEntry; @@ -133,9 +133,7 @@ public class QTI21ArchiveFormat { private List<UserPropertyHandler> userPropertyHandlers; private IdentityAnonymizerCallback anonymizerCallback; - private boolean participants; - private boolean allUsers; - private boolean anonymUsers; + private final QTI21StatisticSearchParams searchParams; private List<ItemInfos> itemInfos; private final Map<String, InteractionArchive> interactionArchiveMap = new HashMap<>(); @@ -144,10 +142,8 @@ public class QTI21ArchiveFormat { private final UserManager userManager; private final AssessmentResponseDAO responseDao; - public QTI21ArchiveFormat(Locale locale, boolean participants, boolean allUsers, boolean anonymUsers) { - this.participants = participants; - this.allUsers = allUsers; - this.anonymUsers = anonymUsers; + public QTI21ArchiveFormat(Locale locale, QTI21StatisticSearchParams searchParams) { + this.searchParams = searchParams; userManager = CoreSpringFactory.getImpl(UserManager.class); qtiService = CoreSpringFactory.getImpl(QTI21ServiceImpl.class); @@ -187,17 +183,17 @@ public class QTI21ArchiveFormat { interactionArchiveMap.put(TextEntryInteraction.QTI_CLASS_NAME, new TextEntryInteractionArchive()); //ok } - public boolean hasResults(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry) { - return responseDao.hasResponses(courseEntry, subIdent, testEntry, participants, allUsers, anonymUsers); + public boolean hasResults() { + return responseDao.hasResponses(searchParams); } - public void export(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry, ZipOutputStream exportStream) { - FileResourceManager frm = FileResourceManager.getInstance(); - File unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource()); - resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false); - - ICourse course = CourseFactory.loadCourse(courseEntry); - CourseNode courseNode = course.getRunStructure().getNode(subIdent); + /** + * + * @param exportStream + */ + public void exportCourseElement(ZipOutputStream exportStream) { + ICourse course = CourseFactory.loadCourse(searchParams.getCourseEntry()); + CourseNode courseNode = course.getRunStructure().getNode(searchParams.getNodeIdent()); String label = StringHelper.transformDisplayNameToFileSystemName(courseNode.getShortName()) + "_" + Formatter.formatDatetimeSave(new Date()) + ".xlsx"; @@ -206,49 +202,53 @@ public class QTI21ArchiveFormat { anonymizerCallback = course.getCourseEnvironment().getCoursePropertyManager(); } - export(courseEntry, subIdent, testEntry, label, exportStream); + export(label, exportStream); } - public void export(RepositoryEntry testEntry, ZipOutputStream exportStream) { - FileResourceManager frm = FileResourceManager.getInstance(); - File unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource()); - resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false); - + public void exportResource(ZipOutputStream exportStream) { String archiveName = "qti21test_" - + StringHelper.transformDisplayNameToFileSystemName(testEntry.getDisplayname()) + + StringHelper.transformDisplayNameToFileSystemName(searchParams.getTestEntry().getDisplayname()) + "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + ".xlsx"; - export(null, null, testEntry, archiveName, exportStream); + export(archiveName, exportStream); } - private void export(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry, String filename, ZipOutputStream exportStream) { - //content - final List<AssessmentResponse> responses = responseDao.getResponse(courseEntry, subIdent, testEntry, participants, allUsers, anonymUsers); + private void export(String filename, ZipOutputStream exportStream) { try { exportStream.putNextEntry(new ZipEntry(filename)); - OpenXMLWorkbook workbook = new OpenXMLWorkbook(new ShieldOutputStream(exportStream), 1); - + exportWorkbook(new ShieldOutputStream(exportStream)); + exportStream.closeEntry(); + } catch (IOException e) { + log.error("", e); + } + } + + public void exportWorkbook(OutputStream exportStream) { + RepositoryEntry testEntry = searchParams.getTestEntry(); + FileResourceManager frm = FileResourceManager.getInstance(); + File unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource()); + resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false); + + //content + List<AssessmentResponse> responses = responseDao.getResponse(searchParams); + try(OpenXMLWorkbook workbook = new OpenXMLWorkbook(exportStream, 1)) { //headers OpenXMLWorksheet exportSheet = workbook.nextWorksheet(); exportSheet.setHeaderRows(2); writeHeaders_1(exportSheet, workbook); writeHeaders_2(exportSheet, workbook); writeData(responses, exportSheet, workbook); - - IOUtils.closeQuietly(workbook); - - exportStream.closeEntry(); - } catch (IOException e) { + } catch(Exception e) { log.error("", e); } } - public MediaResource export(RepositoryEntry courseEntry, String subIdent, RepositoryEntry testEntry) { + public MediaResource exportCourseElement() { FileResourceManager frm = FileResourceManager.getInstance(); - File unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource()); + File unzippedDirRoot = frm.unzipFileResource(searchParams.getTestEntry().getOlatResource()); resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false); - ICourse course = CourseFactory.loadCourse(courseEntry); - CourseNode courseNode = course.getRunStructure().getNode(subIdent); + ICourse course = CourseFactory.loadCourse(searchParams.getCourseEntry()); + CourseNode courseNode = course.getRunStructure().getNode(searchParams.getNodeIdent()); String label = courseNode.getType() + "_" + StringHelper.transformDisplayNameToFileSystemName(courseNode.getShortName()) + "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) @@ -259,8 +259,7 @@ public class QTI21ArchiveFormat { } //content - final List<AssessmentResponse> responses = responseDao.getResponse(courseEntry, subIdent, testEntry, participants, allUsers, anonymUsers); - + final List<AssessmentResponse> responses = responseDao.getResponse(searchParams); return new OpenXMLWorkbookResource(label) { @Override protected void generate(OutputStream out) { diff --git a/src/main/java/org/olat/ims/qti21/model/QTI21StatisticSearchParams.java b/src/main/java/org/olat/ims/qti21/model/QTI21StatisticSearchParams.java index 67f1b7e0756569f500bce5e52f713571399443eb..248832aef4fd512dd3e85371112c3443862c7685 100644 --- a/src/main/java/org/olat/ims/qti21/model/QTI21StatisticSearchParams.java +++ b/src/main/java/org/olat/ims/qti21/model/QTI21StatisticSearchParams.java @@ -19,9 +19,12 @@ */ package org.olat.ims.qti21.model; +import java.util.ArrayList; import java.util.List; import org.olat.basesecurity.Group; +import org.olat.core.id.Identity; +import org.olat.course.nodes.ArchiveOptions; import org.olat.repository.RepositoryEntry; /** @@ -37,9 +40,30 @@ public class QTI21StatisticSearchParams { private final RepositoryEntry testEntry; private List<Group> limitToGroups; + private List<Identity> limitToIdentities; private boolean viewAnonymUsers; private boolean viewAllUsers; + private boolean viewNonMembers; + + public QTI21StatisticSearchParams(ArchiveOptions options, RepositoryEntry testEntry, RepositoryEntry courseEntry, String nodeIdent) { + this.testEntry = testEntry; + this.courseEntry = courseEntry; + this.nodeIdent = nodeIdent; + + if(options == null) { + viewAnonymUsers = true; + viewAllUsers = true; + } else if(options.getGroup() != null) { + limitToGroups = new ArrayList<>(2); + limitToGroups.add(options.getGroup().getBaseGroup()); + } else if(options.getIdentities() != null) { + limitToIdentities = new ArrayList<>(options.getIdentities()); + } else { + viewAnonymUsers = true; + viewAllUsers = true; + } + } public QTI21StatisticSearchParams(RepositoryEntry testEntry, RepositoryEntry courseEntry, String nodeIdent) { this.nodeIdent = nodeIdent; @@ -47,6 +71,15 @@ public class QTI21StatisticSearchParams { this.testEntry = testEntry; } + public QTI21StatisticSearchParams(RepositoryEntry testEntry, RepositoryEntry courseEntry, String nodeIdent, + boolean viewAllUsers, boolean viewAnonymUsers) { + this.nodeIdent = nodeIdent; + this.courseEntry = courseEntry; + this.testEntry = testEntry; + this.viewAllUsers = viewAllUsers; + this.viewAnonymUsers = viewAnonymUsers; + } + public RepositoryEntry getTestEntry() { return testEntry; } @@ -67,6 +100,14 @@ public class QTI21StatisticSearchParams { this.limitToGroups = limitToGroups; } + public List<Identity> getLimitToIdentities() { + return limitToIdentities; + } + + public void setLimitToIdentities(List<Identity> limitToIdentities) { + this.limitToIdentities = limitToIdentities; + } + public boolean isViewAllUsers() { return viewAllUsers; } @@ -75,6 +116,14 @@ public class QTI21StatisticSearchParams { this.viewAllUsers = view; } + public boolean isViewNonMembers() { + return viewNonMembers; + } + + public void setViewNonMembers(boolean viewNonMembers) { + this.viewNonMembers = viewNonMembers; + } + public boolean isViewAnonymUsers() { return viewAnonymUsers; } diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java index bfd68fe6336cee511b83c8444055b75da2aa10d3..be1439bb4c5f3b80916213d765610224c38ef44b 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21ResetToolController.java @@ -59,6 +59,7 @@ import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.group.BusinessGroupService; import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.manager.archive.QTI21ArchiveFormat; +import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.modules.assessment.AssessmentToolOptions; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; @@ -218,7 +219,9 @@ public class QTI21ResetToolController extends BasicController { try(FileOutputStream fileStream = new FileOutputStream(exportFile); ZipOutputStream exportStream = new ZipOutputStream(fileStream)) { - new QTI21ArchiveFormat(getLocale(), true, true, true).export(testEntry, exportStream); + //author can do this, also they can archive all users and anonyme users + QTI21StatisticSearchParams searchParams = new QTI21StatisticSearchParams(testEntry, null, null, true, true); + new QTI21ArchiveFormat(getLocale(), searchParams).exportResource(exportStream); } catch (IOException e) { logError("", e); } diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeController.java index 3464607d7fdd30aa309f693e7384663f440d6a50..b62a69bc088725fabc9d9a3c8f4f02e6df4d2f88 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeController.java @@ -190,7 +190,7 @@ public class QTI21RuntimeController extends RepositoryEntryRuntimeController { if (reSecurity.isEntryAdmin() || reSecurity.isCourseCoach() || reSecurity.isGroupCoach()) { AssessmentToolOptions asOptions = new AssessmentToolOptions(); asOptions.setAdmin(reSecurity.isEntryAdmin()); - QTI21RuntimeStatisticsController ctrl = new QTI21RuntimeStatisticsController(ureq, swControl, + QTI21RuntimeStatisticsController ctrl = new QTI21RuntimeStatisticsController(ureq, swControl, toolbarPanel, getRepositoryEntry(), asOptions); listenTo(ctrl); diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java index 6151fecb71f37eab4c3eadba809fa0b711900503..5bd3236f7ff1f9b3dd7b4c68efbdcd286c5083b4 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java @@ -27,6 +27,8 @@ import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.panel.Panel; +import org.olat.core.gui.components.stack.TooledController; +import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.components.tree.MenuTree; import org.olat.core.gui.components.tree.TreeEvent; import org.olat.core.gui.components.tree.TreeModel; @@ -46,7 +48,6 @@ import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.ims.qti21.ui.statistics.QTI21StatisticResourceResult; import org.olat.ims.qti21.ui.statistics.QTI21StatisticsSecurityCallback; import org.olat.modules.assessment.AssessmentToolOptions; -import org.olat.modules.assessment.AssessmentToolOptions.AlternativeToIdentities; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; @@ -56,9 +57,11 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class QTI21RuntimeStatisticsController extends BasicController implements Activateable2 { +public class QTI21RuntimeStatisticsController extends BasicController implements Activateable2, TooledController { private MenuTree courseTree; + private TooledStackedPanel stackPanel; + private Controller currentCtrl; private LayoutMain3ColsController layoutCtr; @@ -70,9 +73,10 @@ public class QTI21RuntimeStatisticsController extends BasicController implements @Autowired private QTI21Service qtiService; - public QTI21RuntimeStatisticsController(UserRequest ureq, WindowControl wControl, + public QTI21RuntimeStatisticsController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, RepositoryEntry testEntry, AssessmentToolOptions asOptions) { super(ureq, wControl); + this.stackPanel = stackPanel; options = new ArchiveOptions(); options.setGroup(asOptions.getGroup()); options.setIdentities(asOptions.getIdentities()); @@ -81,9 +85,8 @@ public class QTI21RuntimeStatisticsController extends BasicController implements if(asOptions.getGroup() != null) { List<Group> bGroups = Collections.singletonList(asOptions.getGroup().getBaseGroup()); searchParams.setLimitToGroups(bGroups); - } else if(asOptions.getAlternativeToIdentities() != null) { - AlternativeToIdentities alt = asOptions.getAlternativeToIdentities(); - searchParams.setLimitToGroups(alt.getGroups()); + } else if(asOptions.getGroups() != null) { + searchParams.setLimitToGroups(asOptions.getGroups()); } QTI21DeliveryOptions deliveryOptions = qtiService.getDeliveryOptions(testEntry); @@ -102,6 +105,13 @@ public class QTI21RuntimeStatisticsController extends BasicController implements TreeNode rootNode = courseTree.getTreeModel().getRootNode(); doSelectNode(ureq, rootNode); } + + @Override + public void initTools() { + if(currentCtrl instanceof TooledController) { + ((TooledController)currentCtrl).initTools(); + } + } @Override protected void doDispose() { @@ -141,7 +151,7 @@ public class QTI21RuntimeStatisticsController extends BasicController implements private void doSelectNode(UserRequest ureq, TreeNode selectedNode) { removeAsListenerAndDispose(currentCtrl); WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableInstance(selectedNode.getIdent(), 0l), null); - currentCtrl = resourceResult.getController(ureq, swControl, selectedNode, false); + currentCtrl = resourceResult.getController(ureq, swControl, stackPanel, selectedNode, false); if(currentCtrl != null) { listenTo(currentCtrl); layoutCtr.setCol3(currentCtrl.getInitialComponent()); diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java index 1e346ff971ef85179bf07635e6420cc98439d720..b5a0f06564bd26790b1d9a321aa2e4663d9752ff 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java @@ -80,7 +80,8 @@ public class QTI21AssessmentItemStatisticsController extends BasicController { private QTI21StatisticsManager qtiStatisticsManager; public QTI21AssessmentItemStatisticsController(UserRequest ureq, WindowControl wControl, - AssessmentItemRef itemRef, AssessmentItem item, String sectionTitle, QTI21StatisticResourceResult resourceResult, boolean printMode) { + AssessmentItemRef itemRef, AssessmentItem item, String sectionTitle, QTI21StatisticResourceResult resourceResult, + boolean withFilter, boolean printMode) { super(ureq, wControl); this.item = item; @@ -103,7 +104,7 @@ public class QTI21AssessmentItemStatisticsController extends BasicController { mainVC.contextPut("itemCss", "o_mi_qtiunkown"); } - if(resourceResult.canViewAnonymousUsers() || resourceResult.canViewNonParticipantUsers()) { + if(withFilter && (resourceResult.canViewAnonymousUsers() || resourceResult.canViewNonParticipantUsers())) { filterCtrl = new UserFilterController(ureq, getWindowControl(), resourceResult.canViewNonParticipantUsers(), resourceResult.canViewAnonymousUsers(), resourceResult.isViewNonParticipantUsers(), resourceResult.isViewAnonymousUsers()); diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentTestStatisticsController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentTestStatisticsController.java index 1d7c7190e28b78b13716022e747b4be3a6341225..3f61d84f964d86793ce8c6024329abcecbae9704 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentTestStatisticsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentTestStatisticsController.java @@ -23,20 +23,33 @@ import static org.olat.ims.qti.statistics.ui.StatisticFormatter.duration; import static org.olat.ims.qti.statistics.ui.StatisticFormatter.format; import static org.olat.ims.qti.statistics.ui.StatisticFormatter.getModeString; +import java.util.Date; import java.util.List; +import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.chart.BarSeries; 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.link.LinkPopupSettings; +import org.olat.core.gui.components.stack.TooledController; +import org.olat.core.gui.components.stack.TooledStackedPanel; +import org.olat.core.gui.components.stack.TooledStackedPanel.Align; 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.control.generic.dtabs.Activateable2; +import org.olat.core.gui.media.MediaResource; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; +import org.olat.core.util.CodeHelper; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; import org.olat.course.nodes.QTICourseNode; import org.olat.course.nodes.iq.IQEditController; import org.olat.ims.qti.statistics.QTIType; @@ -49,9 +62,11 @@ import org.olat.modules.assessment.ui.event.UserFilterEvent; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class QTI21AssessmentTestStatisticsController extends BasicController implements Activateable2 { - +public class QTI21AssessmentTestStatisticsController extends BasicController implements Activateable2, TooledController { + private final VelocityContainer mainVC; + private final TooledStackedPanel stackPanel; + private final Link printLink, downloadRawLink; private UserFilterController filterCtrl; @@ -59,9 +74,10 @@ public class QTI21AssessmentTestStatisticsController extends BasicController imp private QTICourseNode courseNode; private final QTI21StatisticResourceResult resourceResult; - public QTI21AssessmentTestStatisticsController(UserRequest ureq, WindowControl wControl, - QTI21StatisticResourceResult resourceResult, boolean printMode) { + public QTI21AssessmentTestStatisticsController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, + QTI21StatisticResourceResult resourceResult, boolean withFilter, boolean printMode) { super(ureq, wControl); + this.stackPanel = stackPanel; this.resourceResult = resourceResult; courseNode = resourceResult.getTestCourseNode(); type = resourceResult.getType(); @@ -73,8 +89,24 @@ public class QTI21AssessmentTestStatisticsController extends BasicController imp mainVC.contextPut("courseId", resourceResult.getCourseEntry().getKey()); } mainVC.contextPut("testId", resourceResult.getTestEntry().getKey()); + if(stackPanel != null) { + printLink = LinkFactory.createToolLink("print" + CodeHelper.getRAMUniqueID(), translate("print"), this); + printLink.setIconLeftCSS("o_icon o_icon_print o_icon-lg"); + printLink.setPopup(new LinkPopupSettings(680, 500, "qti-stats")); + stackPanel.addTool(printLink, Align.right); + + downloadRawLink = LinkFactory.createToolLink("download" + CodeHelper.getRAMUniqueID(), translate("download.raw.data"), this); + stackPanel.addTool(downloadRawLink, Align.right); + } else { + printLink = null; + downloadRawLink = LinkFactory.createLink("download.raw.data", mainVC, this); + downloadRawLink.setCustomEnabledLinkCSS("o_content_download"); + mainVC.put("download", downloadRawLink); + } + downloadRawLink.setIconLeftCSS("o_icon o_icon_download o_icon-lg"); + - if(resourceResult.canViewAnonymousUsers() || resourceResult.canViewNonParticipantUsers()) { + if(withFilter && (resourceResult.canViewAnonymousUsers() || resourceResult.canViewNonParticipantUsers())) { filterCtrl = new UserFilterController(ureq, getWindowControl(), resourceResult.canViewNonParticipantUsers(), resourceResult.canViewAnonymousUsers(), resourceResult.isViewNonParticipantUsers(), resourceResult.isViewAnonymousUsers()); @@ -88,9 +120,20 @@ public class QTI21AssessmentTestStatisticsController extends BasicController imp @Override protected void doDispose() { - // + if(stackPanel != null) { + stackPanel.removeTool(downloadRawLink); + stackPanel.removeTool(printLink); + } } + @Override + public void initTools() { + if(stackPanel != null) { + stackPanel.addTool(printLink, Align.right); + stackPanel.addTool(downloadRawLink, Align.right); + } + } + private void updateData() { StatisticAssessment stats = resourceResult.getQTIStatisticAssessment(); initScoreHistogram(stats); @@ -189,6 +232,34 @@ public class QTI21AssessmentTestStatisticsController extends BasicController imp @Override protected void event(UserRequest ureq, Component source, Event event) { - // + if(printLink == source) { + printPages(ureq); + } else if(downloadRawLink == source) { + doDownloadRawData(ureq); + } + } + + private void printPages(UserRequest ureq) { + ControllerCreator printControllerCreator = new ControllerCreator() { + @Override + public Controller createController(UserRequest lureq, WindowControl lwControl) { + return new QTI21PrintController(lureq, lwControl, resourceResult); + } + }; + ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createPrintPopupLayout(printControllerCreator); + openInNewBrowserWindow(ureq, layoutCtrlr); + } + + private void doDownloadRawData(UserRequest ureq) { + String label; + if(courseNode == null) { + label = StringHelper.transformDisplayNameToFileSystemName(resourceResult.getTestEntry().getDisplayname()); + } else { + label = courseNode.getType() + "_" + + StringHelper.transformDisplayNameToFileSystemName(courseNode.getShortName()); + } + label += "_" + Formatter.formatDatetimeFilesystemSave(new Date()) + ".xlsx"; + MediaResource resource = new QTI21StatisticsResource(resourceResult, label, getLocale()); + ureq.getDispatchResult().setResultingMediaResource(resource); } } \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21PrintController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21PrintController.java new file mode 100644 index 0000000000000000000000000000000000000000..8847e50edc95f3166bca5c221c592b0dad8cd6dd --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21PrintController.java @@ -0,0 +1,104 @@ +/** + * <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.qti21.ui.statistics; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.panel.MainPanel; +import org.olat.core.gui.components.tree.TreeNode; +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.util.nodes.INode; +import org.olat.course.CourseFactory; +import org.olat.course.ICourse; +import org.olat.course.statistic.StatisticResourceNode; + +/** + * + * Initial date: 13 févr. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTI21PrintController extends BasicController { + + private final VelocityContainer mainVC; + + public QTI21PrintController(UserRequest ureq, WindowControl wControl, QTI21StatisticResourceResult resourceResult) { + super(ureq, wControl); + + mainVC = createVelocityContainer("print"); + initView(ureq, resourceResult); + + MainPanel mainPanel = new MainPanel("statsPrintPanel"); + mainPanel.setContent(mainVC); + mainPanel.setCssClass("o_qti_print"); + putInitialPanel(mainPanel); + } + + private void initView(UserRequest ureq, QTI21StatisticResourceResult resourceResult) { + StatisticResourceNode rootNode = (StatisticResourceNode)resourceResult.getSubTreeModel().getRootNode(); + + if(resourceResult.getCourseEntry() != null) { + ICourse course = CourseFactory.loadCourse(resourceResult.getCourseEntry()); + mainVC.contextPut("courseTitle", course.getCourseTitle()); + } + String testTitle = resourceResult.getTestEntry().getDisplayname(); + mainVC.contextPut("testTitle", testTitle); + + int count = 0; + List<String> pageNames = new ArrayList<>(); + + Controller assessmentCtrl = resourceResult.getController(ureq, getWindowControl(), null, rootNode, true); + + String pageName = "page" + count++; + mainVC.put(pageName, assessmentCtrl.getInitialComponent()); + pageNames.add(pageName); + + for(int i=0; i<rootNode.getChildCount(); i++) { + INode sectionNode = rootNode.getChildAt(i); + for(int j=0; j<sectionNode.getChildCount(); j++) { + TreeNode itemNode = (TreeNode)sectionNode.getChildAt(j); + Controller itemCtrl = resourceResult.getController(ureq, getWindowControl(), null, itemNode, true); + + String itemPageName = "page" + count++; + mainVC.put(itemPageName, itemCtrl.getInitialComponent()); + pageNames.add(itemPageName); + } + } + + mainVC.contextPut("pageNames", pageNames); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } +} diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java index 4599cc5293fd62ba9ba58751e4b2c0e68da40623..4842d9cdef1c21aa89ce78e23cef0dd7dd14dc96 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java @@ -77,6 +77,8 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { private final QTI21Service qtiService; private final QTI21StatisticsManager qtiStatisticsManager; + + private boolean withFilter = true; public QTI21StatisticResourceResult(RepositoryEntry testEntry, QTI21StatisticSearchParams searchParams, QTI21StatisticsSecurityCallback secCallback) { @@ -159,6 +161,14 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { searchParams.setViewAllUsers(view); } + public boolean isWithFilter() { + return withFilter; + } + + public void setWithFilter(boolean withFilter) { + this.withFilter = withFilter; + } + /** * Return the tree model for a test learn resource. * @@ -212,7 +222,6 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { firstItem = itemNode; } } - rootTreeNode.setDelegate(firstItem); } else { int counter = 0; for(TestPart part:parts) { @@ -288,13 +297,13 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { @Override public Controller getController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, TreeNode selectedNode) { - return getController(ureq, wControl, selectedNode, false); + return getController(ureq, wControl, stackPanel, selectedNode, false); } - public Controller getController(UserRequest ureq, WindowControl wControl, + public Controller getController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, TreeNode selectedNode, boolean printMode) { if(selectedNode instanceof StatisticResourceNode) { - return createAssessmentController(ureq, wControl, printMode); + return createAssessmentController(ureq, wControl, stackPanel, printMode); } else { Object uobject = selectedNode.getUserObject(); @@ -304,14 +313,14 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { return createAssessmentItemController(ureq, wControl, (AssessmentItemRef)uobject, sectionTitle, printMode); } else if(uobject instanceof AssessmentTest) { - return createAssessmentController(ureq, wControl, printMode); + return createAssessmentController(ureq, wControl, stackPanel, printMode); } } return null; } - private Controller createAssessmentController(UserRequest ureq, WindowControl wControl, boolean printMode) { - Controller ctrl = new QTI21AssessmentTestStatisticsController(ureq, wControl, this, printMode); + private Controller createAssessmentController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, boolean printMode) { + Controller ctrl = new QTI21AssessmentTestStatisticsController(ureq, wControl, stackPanel, this, withFilter, printMode); if(courseNode != null) { CourseNodeConfiguration cnConfig = CourseNodeFactory.getInstance() .getCourseNodeConfigurationEvenForDisabledBB(courseNode.getType()); @@ -325,7 +334,7 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { AssessmentItemRef assessmentItemRef, String sectionTitle, boolean printMode) { ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(assessmentItemRef); AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode(); - Controller ctrl = new QTI21AssessmentItemStatisticsController(ureq, wControl, assessmentItemRef, assessmentItem, sectionTitle, this, printMode); + Controller ctrl = new QTI21AssessmentItemStatisticsController(ureq, wControl, assessmentItemRef, assessmentItem, sectionTitle, this, withFilter, printMode); String iconCssClass = "o_mi_qtisc"; if(courseNode != null) { ctrl = TitledWrapperHelper.getWrapper(ureq, wControl, ctrl, courseNode, iconCssClass); diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsResource.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsResource.java new file mode 100644 index 0000000000000000000000000000000000000000..82278a035fb3a656f9a98c9bc05657290b3a878d --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsResource.java @@ -0,0 +1,58 @@ +/** + * <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.qti21.ui.statistics; + +import java.io.OutputStream; +import java.util.Locale; + +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.openxml.OpenXMLWorkbookResource; +import org.olat.ims.qti21.manager.archive.QTI21ArchiveFormat; + +/** + * + * Initial date: 13 févr. 2017<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class QTI21StatisticsResource extends OpenXMLWorkbookResource { + + private static final OLog log = Tracing.createLoggerFor(QTI21StatisticsResource.class); + + private final Locale locale; + private final QTI21StatisticResourceResult resourceResult; + + public QTI21StatisticsResource(QTI21StatisticResourceResult resourceResult, String label, Locale locale) { + super(label); + this.locale = locale; + this.resourceResult = resourceResult; + } + + @Override + protected void generate(OutputStream out) { + try { + new QTI21ArchiveFormat(locale, resourceResult.getSearchParams()) + .exportWorkbook(out); + } catch (Exception e) { + log.error("", e); + } + } +} diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsToolController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsToolController.java index 29709d026e3027d1718af8104917da17a2f0d67e..e6e8deedc559128af6e2e95a999f3abf393de6f7 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsToolController.java +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsToolController.java @@ -52,7 +52,6 @@ import org.olat.ims.qti21.QTI21DeliveryOptions; import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.modules.assessment.AssessmentToolOptions; -import org.olat.modules.assessment.AssessmentToolOptions.AlternativeToIdentities; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; @@ -82,6 +81,16 @@ public class QTI21StatisticsToolController extends BasicController implements Ac @Autowired private QTI21Service qtiService; + /** + * This is the statistics tool for the assessment tool. + * + * @param ureq + * @param wControl + * @param stackPanel + * @param courseEnv + * @param asOptions + * @param courseNode + */ public QTI21StatisticsToolController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, CourseEnvironment courseEnv, AssessmentToolOptions asOptions, QTICourseNode courseNode) { @@ -98,14 +107,16 @@ public class QTI21StatisticsToolController extends BasicController implements Ac secCallback = new QTI21StatisticsSecurityCallback(asOptions.isAdmin(), asOptions.isAdmin() && deliveryOptions.isAllowAnonym()); searchParams = new QTI21StatisticSearchParams(testEntry, courseEntry, courseNode.getIdent()); - searchParams.setViewAnonymUsers(secCallback.canViewAnonymousUsers()); + searchParams.setViewAnonymUsers(false);//In assessment tool, no user allowed + searchParams.setViewAllUsers(false); - if(asOptions.getGroup() != null) { + if(asOptions.getGroup() != null) {// filter by business group List<Group> bGroups = Collections.singletonList(asOptions.getGroup().getBaseGroup()); searchParams.setLimitToGroups(bGroups); - } else if(asOptions.getAlternativeToIdentities() != null) { - AlternativeToIdentities alt = asOptions.getAlternativeToIdentities(); - searchParams.setLimitToGroups(alt.getGroups()); + } else if(asOptions.getGroups() != null) { + searchParams.setLimitToGroups(asOptions.getGroups()); + } else { + searchParams.setViewNonMembers(asOptions.isNonMembers()); } statsButton = LinkFactory.createButton("menu.title", null, this); @@ -168,6 +179,7 @@ public class QTI21StatisticsToolController extends BasicController implements Ac private void doLaunchStatistics(UserRequest ureq, WindowControl wControl) { if(result == null) { result = new QTI21StatisticResourceResult(testEntry, courseEntry, courseNode, searchParams, secCallback); + result.setWithFilter(false); } GenericTreeModel treeModel = new GenericTreeModel(); diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/print.html b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/print.html new file mode 100644 index 0000000000000000000000000000000000000000..ca3a74b41cf63de9d547d92267343d419bf4e1f8 --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/print.html @@ -0,0 +1,14 @@ +#if($r.isNotNull($courseTitle)) +<h3>$courseTitle</h3> +#end +<h3>$testTitle</h3> +#foreach($pageName in $pageNames) + <div #if ($velocityCount > 1) class="o_print_break_before" #end> + $r.render($pageName) + </div> +#end +<script type='text/javascript'> +/* <![CDATA[ */ + window.print(); +/* ]]> */ +</script> \ No newline at end of file diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_assessment_test.html b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_assessment_test.html index 5262c5fe3ca71a49231a0e629c216ca250dd6407..8fb5fd7bc5da67edb31c36e3f505408f16b5e4c8 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_assessment_test.html +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_assessment_test.html @@ -1,4 +1,4 @@ -#if($r.available("filter")) +#if($r.available("filter") && !$printMode) <div class="o_button_group o_button_group_right"> $r.render("filter") </div> diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_de.properties index 7b7098754bc7cc481ded42df6f6fa20e8b39c5d5..23b9f93b3f213739d3642b7f5e11f7b84afccf60 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_de.properties @@ -13,6 +13,7 @@ chart.percent.participants.num=$org.olat.ims.qti.statistics.ui\:chart.percent.pa chart.points=$org.olat.ims.qti.statistics.ui\:chart.points chart.responses=$org.olat.ims.qti.statistics.ui\:chart.responses chart.score.histogramm=$org.olat.ims.qti.statistics.ui\:chart.score.histogramm +download.raw.data=$org.olat.ims.qti.statistics.ui\:download.raw.data fib.wrong.answer=$org.olat.ims.qti.statistics.ui\:fib.wrong.answer fig.averagedur=$org.olat.ims.qti.statistics.ui\:fig.averagedur fig.averagescore=$org.olat.ims.qti.statistics.ui\:fig.averagescore diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_en.properties index 28713a5eaad3a90080de0c92145913eb1826dd3e..59e86626a8266156a5a318903fc717bfcae5b65f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_en.properties @@ -13,6 +13,7 @@ chart.percent.participants.num=$org.olat.ims.qti.statistics.ui\:chart.percent.pa chart.points=$org.olat.ims.qti.statistics.ui\:chart.points chart.responses=$org.olat.ims.qti.statistics.ui\:chart.responses chart.score.histogramm=$org.olat.ims.qti.statistics.ui\:chart.score.histogramm +download.raw.data=$org.olat.ims.qti.statistics.ui\:download.raw.data fib.wrong.answer=$org.olat.ims.qti.statistics.ui\:fib.wrong.answer fig.averagedur=$org.olat.ims.qti.statistics.ui\:fig.averagedur fig.averagescore=$org.olat.ims.qti.statistics.ui\:fig.averagescore diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_fr.properties index 274894623d041d3a82f1d20466ddeeedf5e6c0d4..b257fa0cc4895afed5f506b97cfa17274010b548 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_fr.properties @@ -13,6 +13,7 @@ chart.percent.participants.num=$org.olat.ims.qti.statistics.ui\:chart.percent.pa chart.points=$org.olat.ims.qti.statistics.ui\:chart.points chart.responses=$org.olat.ims.qti.statistics.ui\:chart.responses chart.score.histogramm=$org.olat.ims.qti.statistics.ui\:chart.score.histogramm +download.raw.data=$org.olat.ims.qti.statistics.ui\:download.raw.data fib.wrong.answer=$org.olat.ims.qti.statistics.ui\:fib.wrong.answer fig.averagedur=$org.olat.ims.qti.statistics.ui\:fig.averagedur fig.averagescore=$org.olat.ims.qti.statistics.ui\:fig.averagescore diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_it.properties index b2c70ee9a1751f72d721f414daab0023c6b49a9d..063bf57848697e296a8864bb703305c32f6e5306 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_it.properties @@ -13,6 +13,7 @@ chart.percent.participants.num=$org.olat.ims.qti.statistics.ui\:chart.percent.pa chart.points=$org.olat.ims.qti.statistics.ui\:chart.points chart.responses=$org.olat.ims.qti.statistics.ui\:chart.responses chart.score.histogramm=$org.olat.ims.qti.statistics.ui\:chart.score.histogramm +download.raw.data=$org.olat.ims.qti.statistics.ui\:download.raw.data fib.wrong.answer=$org.olat.ims.qti.statistics.ui\:fib.wrong.answer fig.averagedur=$org.olat.ims.qti.statistics.ui\:fig.averagedur fig.averagescore=$org.olat.ims.qti.statistics.ui\:fig.averagescore diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_pt_BR.properties index eaa4b5d5e2f493b5056d186be6e04ac9e897c7da..79adf0d28a839391b62d55646581e7c40478be24 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_i18n/LocalStrings_pt_BR.properties @@ -13,6 +13,7 @@ chart.percent.participants.num=$org.olat.ims.qti.statistics.ui\:chart.percent.pa chart.points=$org.olat.ims.qti.statistics.ui\:chart.points chart.responses=$org.olat.ims.qti.statistics.ui\:chart.responses chart.score.histogramm=$org.olat.ims.qti.statistics.ui\:chart.score.histogramm +download.raw.data=$org.olat.ims.qti.statistics.ui\:download.raw.data fib.wrong.answer=$org.olat.ims.qti.statistics.ui\:fib.wrong.answer fig.averagedur=$org.olat.ims.qti.statistics.ui\:fig.averagedur fig.averagescore=$org.olat.ims.qti.statistics.ui\:fig.averagescore diff --git a/src/main/java/org/olat/modules/assessment/AssessmentToolOptions.java b/src/main/java/org/olat/modules/assessment/AssessmentToolOptions.java index 3a455f0419eb643bd258961c12517063183fbdff..9b11a2ef87bdc49e0922cdaafab8dccb076ea91d 100644 --- a/src/main/java/org/olat/modules/assessment/AssessmentToolOptions.java +++ b/src/main/java/org/olat/modules/assessment/AssessmentToolOptions.java @@ -35,8 +35,10 @@ public class AssessmentToolOptions { private boolean admin; private BusinessGroup group; + private List<Group> groups; private List<Identity> identities; - private AlternativeToIdentities alternativeToIdentities; + + private boolean nonMembers; public AssessmentToolOptions() { // @@ -50,6 +52,14 @@ public class AssessmentToolOptions { this.admin = admin; } + public boolean isNonMembers() { + return nonMembers; + } + + public void setNonMembers(boolean nonMembers) { + this.nonMembers = nonMembers; + } + public BusinessGroup getGroup() { return group; } @@ -65,35 +75,15 @@ public class AssessmentToolOptions { public void setIdentities(List<Identity> identities) { this.identities = identities; } - - public AlternativeToIdentities getAlternativeToIdentities() { - return alternativeToIdentities; - } - - public void setAlternativeToIdentities(List<Group> groups, boolean mayViewAllUsersAssessments) { - alternativeToIdentities = new AlternativeToIdentities(); - alternativeToIdentities.setGroups(groups); - alternativeToIdentities.setMayViewAllUsersAssessments(mayViewAllUsersAssessments); + + public List<Group> getGroups() { + return groups; } - - public static class AlternativeToIdentities { - private List<Group> groups; - private boolean mayViewAllUsersAssessments; - public List<Group> getGroups() { - return groups; - } - - public void setGroups(List<Group> groups) { - this.groups = groups; - } - - public boolean isMayViewAllUsersAssessments() { - return mayViewAllUsersAssessments; - } - - public void setMayViewAllUsersAssessments(boolean mayViewAllUsersAssessments) { - this.mayViewAllUsersAssessments = mayViewAllUsersAssessments; - } + public void setGroups(List<Group> groups) { + this.groups = groups; } + + + } diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java b/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java index 6d7bebaca35260ca20361fcd776c6c9fddf58973..81def30930e5286b2c0273cc5277744f9e42ca03 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java +++ b/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java @@ -198,7 +198,6 @@ public class RepositoryEntryRelationDAO { return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Group.class) .setParameter("repoKey", re.getKey()) - .setHint("org.hibernate.cacheable", Boolean.TRUE) .getSingleResult(); } diff --git a/src/main/java/org/olat/search/service/document/file/FileTypeDetector.java b/src/main/java/org/olat/search/service/document/file/FileTypeDetector.java index d30d2686cb199d23c0f137fe9390dab595a85800..65b58ccb2c2d7dd8e5dcdb81f07aa8ca68d61654 100644 --- a/src/main/java/org/olat/search/service/document/file/FileTypeDetector.java +++ b/src/main/java/org/olat/search/service/document/file/FileTypeDetector.java @@ -55,7 +55,7 @@ public class FileTypeDetector { if("doc".equals(suffix)) { if(checkMagicBytes(leaf, ZIP)) return "docx"; } else if("xls".equals(suffix)) { - if(checkMagicBytes(leaf, ZIP)) return "xslx"; + if(checkMagicBytes(leaf, ZIP)) return "xlsx"; } else if("ppt".equals(suffix)) { if(checkMagicBytes(leaf, ZIP)) return "pptx"; }