Skip to content
Snippets Groups Projects
Commit 4ee39eb0 authored by srosse's avatar srosse
Browse files
parents e30329a2 169e42e6
No related branches found
No related tags found
No related merge requests found
...@@ -20,10 +20,8 @@ ...@@ -20,10 +20,8 @@
package org.olat.course.nodes.st.assessment; package org.olat.course.nodes.st.assessment;
import org.olat.core.CoreSpringFactory; import org.olat.core.CoreSpringFactory;
import org.olat.core.util.tree.TreeVisitor;
import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.CourseAssessmentService;
import org.olat.course.assessment.handler.AssessmentConfig; import org.olat.course.assessment.handler.AssessmentConfig;
import org.olat.course.nodes.CollectingVisitor;
import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNode;
import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.scoring.AssessmentEvaluation;
import org.olat.course.run.scoring.CompletionEvaluator; import org.olat.course.run.scoring.CompletionEvaluator;
...@@ -52,37 +50,17 @@ public class ConventionalSTCompletionEvaluator implements CompletionEvaluator { ...@@ -52,37 +50,17 @@ public class ConventionalSTCompletionEvaluator implements CompletionEvaluator {
ScoreAccounting scoreAccounting) { ScoreAccounting scoreAccounting) {
Double completion = null; Double completion = null;
if (isPassed(currentEvaluation)) {
completion = Double.valueOf(1.0); if (courseNode.getParent() == null) {
} else { AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode);
// get all children if (isPassedConfigurated(assessmentConfig)) {
CollectingVisitor visitor = CollectingVisitor.testing(cn -> !cn.getIdent().equals(courseNode.getIdent())); completion = isNodePassed(currentEvaluation)? Double.valueOf(1.0): Double.valueOf(0.0);
TreeVisitor tv = new TreeVisitor(visitor, courseNode, true);
tv.visitAll();
int countIsPassedConfig = 0;
int countIsPassed = 0;
for (CourseNode child: visitor.getCourseNodes()) {
AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(child);
if (isPassedConfigurated(assessmentConfig)) {
countIsPassedConfig++;
AssessmentEvaluation assessmentEvaluation = scoreAccounting.evalCourseNode(child);
if (isNodePassed(assessmentEvaluation)) {
countIsPassed++;
}
}
}
if (countIsPassedConfig > 0) {
completion = Double.valueOf((double)countIsPassed / countIsPassedConfig);
} }
} }
return completion; return completion;
} }
private boolean isPassed(AssessmentEvaluation currentEvaluation) {
return Boolean.TRUE.equals(currentEvaluation.getPassed());
}
private boolean isNodePassed(AssessmentEvaluation assessmentEvaluation) { private boolean isNodePassed(AssessmentEvaluation assessmentEvaluation) {
return Boolean.TRUE.equals(assessmentEvaluation.getPassed()) return Boolean.TRUE.equals(assessmentEvaluation.getPassed())
&& Boolean.TRUE.equals(assessmentEvaluation.getUserVisible()); && Boolean.TRUE.equals(assessmentEvaluation.getUserVisible());
......
...@@ -79,6 +79,9 @@ import org.olat.core.util.StringHelper; ...@@ -79,6 +79,9 @@ import org.olat.core.util.StringHelper;
import org.olat.core.util.Util; import org.olat.core.util.Util;
import org.olat.core.util.resource.OresHelper; import org.olat.core.util.resource.OresHelper;
import org.olat.course.CorruptedCourseException; import org.olat.course.CorruptedCourseException;
import org.olat.course.CourseFactory;
import org.olat.course.ICourse;
import org.olat.course.condition.ConditionNodeAccessProvider;
import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryEntryStatusEnum; import org.olat.repository.RepositoryEntryStatusEnum;
import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryManager;
...@@ -635,6 +638,9 @@ public class RepositoryEntryListController extends FormBasicController ...@@ -635,6 +638,9 @@ public class RepositoryEntryListController extends FormBasicController
@Override @Override
public void forgeCompletion(RepositoryEntryRow row) { public void forgeCompletion(RepositoryEntryRow row) {
if(!guestOnly && row.getCompletion() != null) { if(!guestOnly && row.getCompletion() != null) {
if (isConventionalUnpassedCourse(row)) {
return;
}
ProgressBarItem completionItem = new ProgressBarItem("completion_" + row.getKey(), 100, ProgressBarItem completionItem = new ProgressBarItem("completion_" + row.getKey(), 100,
row.getCompletion().floatValue(), Float.valueOf(1), null); row.getCompletion().floatValue(), Float.valueOf(1), null);
completionItem.setWidthInPercent(true); completionItem.setWidthInPercent(true);
...@@ -656,6 +662,15 @@ public class RepositoryEntryListController extends FormBasicController ...@@ -656,6 +662,15 @@ public class RepositoryEntryListController extends FormBasicController
row.setCompletionItem(completionItem); row.setCompletionItem(completionItem);
} }
} }
private boolean isConventionalUnpassedCourse(RepositoryEntryRow row) {
if ("CourseModule".equals(row.getOLATResourceable().getResourceableTypeName())) {
ICourse course = CourseFactory.loadCourse(row.getOLATResourceable());
return ConditionNodeAccessProvider.TYPE.equals(course.getCourseConfig().getNodeAccessType().getType())
&& row.getCompletion().doubleValue() < 1.0;
}
return false;
}
@Override @Override
public void forgeSelectLink(RepositoryEntryRow row) { public void forgeSelectLink(RepositoryEntryRow row) {
......
...@@ -77,6 +77,11 @@ public class OLATUpgrade_15_pre_0 extends OLATUpgrade { ...@@ -77,6 +77,11 @@ public class OLATUpgrade_15_pre_0 extends OLATUpgrade {
uhd.setInstallationComplete(allOk); uhd.setInstallationComplete(allOk);
upgradeManager.setUpgradesHistory(uhd, VERSION); upgradeManager.setUpgradesHistory(uhd, VERSION);
// OLATUpgrade_15_pre_6_ae has only to run if this upgrade (OLATUpgrade_15_pre_0)
// is run before the fix for the completion of assessment entries of conventional courses.
upgradeManager.setUpgradesHistory(uhd, OLATUpgrade_15_pre_6_ae.VERSION);
if(allOk) { if(allOk) {
log.info(Tracing.M_AUDIT, "Finished OLATUpgrade_15_pre_0 successfully!"); log.info(Tracing.M_AUDIT, "Finished OLATUpgrade_15_pre_0 successfully!");
} else { } else {
......
/**
* <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.upgrade;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.logging.log4j.Logger;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.persistence.QueryBuilder;
import org.olat.core.logging.Tracing;
import org.olat.course.CorruptedCourseException;
import org.olat.course.CourseFactory;
import org.olat.course.ICourse;
import org.olat.course.Structure;
import org.olat.course.assessment.CourseAssessmentService;
import org.olat.course.condition.ConditionNodeAccessProvider;
import org.olat.course.nodeaccess.NodeAccessType;
import org.olat.repository.RepositoryEntry;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
* Initial date: 17.03.2020<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
public class OLATUpgrade_15_pre_6_ae extends OLATUpgrade {
private static final Logger log = Tracing.createLoggerFor(OLATUpgrade_15_pre_6_ae.class);
static final String VERSION = "OLAT_15.pre.6.ae";
private static final String CONDITION_COURSE_COMPLETION = "CONDITION COURSES COMPLETION";
@Autowired
private DB dbInstance;
@Autowired
private CourseAssessmentService courseAssessmentService;
public OLATUpgrade_15_pre_6_ae() {
super();
}
@Override
public String getVersion() {
return VERSION;
}
@Override
public boolean doPostSystemInitUpgrade(UpgradeManager upgradeManager) {
UpgradeHistoryData uhd = upgradeManager.getUpgradesHistory(VERSION);
if (uhd == null) {
// has never been called, initialize
uhd = new UpgradeHistoryData();
} else if (uhd.isInstallationComplete()) {
return false;
}
boolean allOk = true;
allOk &= migrateAssessmentEntrCompletion(upgradeManager, uhd);
uhd.setInstallationComplete(allOk);
upgradeManager.setUpgradesHistory(uhd, VERSION);
if(allOk) {
log.info(Tracing.M_AUDIT, "Finished OLATUpgrade_15_pre_6_ae successfully!");
} else {
log.info(Tracing.M_AUDIT, "OLATUpgrade_15_pre_6_ae not finished, try to restart OpenOlat!");
}
return allOk;
}
private boolean migrateAssessmentEntrCompletion(UpgradeManager upgradeManager, UpgradeHistoryData uhd) {
boolean allOk = true;
if (!uhd.getBooleanDataValue(CONDITION_COURSE_COMPLETION)) {
try {
migrateCourseAssessmentEntries();
dbInstance.commitAndCloseSession();
log.info("All assessment entry completions migrated.");
} catch (Exception e) {
log.error("", e);
allOk = false;
}
uhd.setBooleanDataValue(CONDITION_COURSE_COMPLETION, allOk);
upgradeManager.setUpgradesHistory(uhd, VERSION);
}
return allOk;
}
private void migrateCourseAssessmentEntries() {
List<RepositoryEntry> courseEntries = getCourseEntries();
AtomicInteger migrationCounter = new AtomicInteger(0);
for (RepositoryEntry repositoryEntry : courseEntries) {
calculateCourseAssessmentEntries(repositoryEntry);
migrationCounter.incrementAndGet();
if(migrationCounter.get() % 25 == 0) {
dbInstance.commitAndCloseSession();
} else {
dbInstance.commit();
}
if(migrationCounter.get() % 100 == 0) {
log.info("Assessment entries: num. of courses migrated: {}", migrationCounter);
}
}
}
private List<RepositoryEntry> getCourseEntries() {
QueryBuilder sb = new QueryBuilder();
sb.append("select re");
sb.append(" from repositoryentry re");
sb.append(" inner join re.olatResource as ores");
sb.and().append(" ores.resName = 'CourseModule'");
sb.append(" order by re.statistics.lastUsage desc");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), RepositoryEntry.class)
.getResultList();
}
private void calculateCourseAssessmentEntries(RepositoryEntry repositoryEntry) {
try {
ICourse course = CourseFactory.loadCourse(repositoryEntry);
if (course != null) {
NodeAccessType nodeAccessType = NodeAccessType.of(course);
if (ConditionNodeAccessProvider.TYPE.equals(nodeAccessType.getType())) {
Structure runStructure = course.getCourseEnvironment().getRunStructure();
if (runStructure != null) {
courseAssessmentService.evaluateAll(course);
log.info("Assessment entry completions calculated: course {} ({}).",
repositoryEntry.getKey(), repositoryEntry.getDisplayname());
}
}
}
} catch (CorruptedCourseException cce) {
log.warn("CorruptedCourseException in migration of assessment entry completion of course {} ({})",
repositoryEntry.getKey(), repositoryEntry.getDisplayname());
} catch (Exception e) {
log.error("Error in migration of assessment entry completion of course {} ({}).", repositoryEntry.getKey(),
repositoryEntry.getDisplayname());
log.error("", e);
}
}
}
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
<bean id="upgrade_14_2_0" class="org.olat.upgrade.OLATUpgrade_14_2_0"/> <bean id="upgrade_14_2_0" class="org.olat.upgrade.OLATUpgrade_14_2_0"/>
<bean id="upgrade_15_pre_6" class="org.olat.upgrade.OLATUpgrade_15_pre_6"/><!-- because really quicker as pre.0 --> <bean id="upgrade_15_pre_6" class="org.olat.upgrade.OLATUpgrade_15_pre_6"/><!-- because really quicker as pre.0 -->
<bean id="upgrade_15_pre_0" class="org.olat.upgrade.OLATUpgrade_15_pre_0"/> <bean id="upgrade_15_pre_0" class="org.olat.upgrade.OLATUpgrade_15_pre_0"/>
<bean id="upgrade_15_pre_6_ae" class="org.olat.upgrade.OLATUpgrade_15_pre_6_ae"/>
</list> </list>
</property> </property>
</bean> </bean>
......
...@@ -29,7 +29,6 @@ import org.mockito.MockitoAnnotations; ...@@ -29,7 +29,6 @@ import org.mockito.MockitoAnnotations;
import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.CourseAssessmentService;
import org.olat.course.assessment.MappedScoreAccounting; import org.olat.course.assessment.MappedScoreAccounting;
import org.olat.course.assessment.handler.AssessmentConfig; import org.olat.course.assessment.handler.AssessmentConfig;
import org.olat.course.nodes.Card2BrainCourseNode;
import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNode;
import org.olat.course.nodes.STCourseNode; import org.olat.course.nodes.STCourseNode;
import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.scoring.AssessmentEvaluation;
...@@ -63,53 +62,89 @@ public class ConventionalSTCompletionEvaluatorTest { ...@@ -63,53 +62,89 @@ public class ConventionalSTCompletionEvaluatorTest {
} }
@Test @Test
public void shouldReturn1IfCondittionIsPassed() { public void shouldReturnNullIfItIsNotRoot() {
MappedScoreAccounting scoreAccounting = new MappedScoreAccounting(); MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
CourseNode parent = new STCourseNode(); CourseNode root = new STCourseNode();
CourseNode child = new STCourseNode();
root.addChild(child);
AssessmentEvaluation parrentEvaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE);
scoreAccounting.put(child, parrentEvaluation);
when(courseAssessmentService.getAssessmentConfig(child)).thenReturn(configWithPassed);
Double completion = sut.getCompletion(parrentEvaluation, child, scoreAccounting);
assertThat(completion).isNull();
}
@Test
public void shouldReturnNullIfHasNoPassConfig() {
MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
CourseNode root = new STCourseNode();
AssessmentEvaluation parrentEvaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE);
scoreAccounting.put(root, parrentEvaluation);
when(courseAssessmentService.getAssessmentConfig(root)).thenReturn(configWithoutPassed);
Double completion = sut.getCompletion(parrentEvaluation, root, scoreAccounting);
assertThat(completion).isNull();
}
@Test
public void shouldReturn0IfIsFailed() {
MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
CourseNode root = new STCourseNode();
AssessmentEvaluation parrentEvaluation = createAssessmentEvaluation(Boolean.FALSE, Boolean.TRUE);
scoreAccounting.put(root, parrentEvaluation);
when(courseAssessmentService.getAssessmentConfig(root)).thenReturn(configWithPassed);
Double completion = sut.getCompletion(parrentEvaluation, root, scoreAccounting);
assertThat(completion).isEqualTo(0.0);
}
@Test
public void shouldReturn0IfNOtPassedYet() {
MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
CourseNode root = new STCourseNode();
AssessmentEvaluation parrentEvaluation = createAssessmentEvaluation(null, Boolean.TRUE);
scoreAccounting.put(root, parrentEvaluation);
when(courseAssessmentService.getAssessmentConfig(root)).thenReturn(configWithPassed);
Double completion = sut.getCompletion(parrentEvaluation, root, scoreAccounting);
assertThat(completion).isEqualTo(0.0);
}
@Test
public void shouldReturn0IfIsPassedButNotUserVisible() {
MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
CourseNode root = new STCourseNode();
AssessmentEvaluation parrentEvaluation = createAssessmentEvaluation(Boolean.TRUE, null); AssessmentEvaluation parrentEvaluation = createAssessmentEvaluation(Boolean.TRUE, null);
scoreAccounting.put(parent, parrentEvaluation); scoreAccounting.put(root, parrentEvaluation);
when(courseAssessmentService.getAssessmentConfig(root)).thenReturn(configWithPassed);
Double completion = sut.getCompletion(parrentEvaluation, parent, scoreAccounting); Double completion = sut.getCompletion(parrentEvaluation, root, scoreAccounting);
assertThat(completion).isEqualByComparingTo(1.0); assertThat(completion).isEqualTo(0.0);
} }
@Test @Test
public void shouldReturnNumberOfPassedNodes() { public void shouldReturn1IfIsPassedAndUserVisible() {
MappedScoreAccounting scoreAccounting = new MappedScoreAccounting(); MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
CourseNode parent = new STCourseNode(); CourseNode root = new STCourseNode();
AssessmentEvaluation parrentEvaluation = createAssessmentEvaluation(Boolean.FALSE, null); AssessmentEvaluation parrentEvaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE);
scoreAccounting.put(parent, parrentEvaluation); scoreAccounting.put(root, parrentEvaluation);
// Child with passed configured: passed when(courseAssessmentService.getAssessmentConfig(root)).thenReturn(configWithPassed);
CourseNode child1 = new Card2BrainCourseNode();
parent.addChild(child1); Double completion = sut.getCompletion(parrentEvaluation, root, scoreAccounting);
AssessmentEvaluation assessedEvaluation1 = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE);
scoreAccounting.put(child1, assessedEvaluation1); assertThat(completion).isEqualTo(1.0);
when(courseAssessmentService.getAssessmentConfig(child1)).thenReturn(configWithPassed);
// Child with passed configured: passed but not user visible
CourseNode child2= new Card2BrainCourseNode();
parent.addChild(child2);
AssessmentEvaluation assessedEvaluation2 = createAssessmentEvaluation(Boolean.TRUE, Boolean.FALSE);
scoreAccounting.put(child2, assessedEvaluation2);
when(courseAssessmentService.getAssessmentConfig(child2)).thenReturn(configWithPassed);
// Child with passed configured: not passed
CourseNode child3 = new Card2BrainCourseNode();
parent.addChild(child3);
AssessmentEvaluation assessedEvaluation3 = createAssessmentEvaluation(Boolean.FALSE, Boolean.TRUE);
scoreAccounting.put(child3, assessedEvaluation3);
when(courseAssessmentService.getAssessmentConfig(child3)).thenReturn(configWithPassed);
// Child without passed configured:
CourseNode child4 = new Card2BrainCourseNode();
parent.addChild(child4);
AssessmentEvaluation assessedEvaluation4 = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE);
scoreAccounting.put(child4, assessedEvaluation4);
when(courseAssessmentService.getAssessmentConfig(child4)).thenReturn(configWithPassed);
Double completion = sut.getCompletion(parrentEvaluation, parent, scoreAccounting);
assertThat(completion).isEqualByComparingTo(0.5);
} }
private AssessmentEvaluation createAssessmentEvaluation(Boolean passed, Boolean userVisibility) { private AssessmentEvaluation createAssessmentEvaluation(Boolean passed, Boolean userVisibility) {
......
...@@ -776,6 +776,10 @@ public class AssessmentEntryDAOTest extends OlatTestCase { ...@@ -776,6 +776,10 @@ public class AssessmentEntryDAOTest extends OlatTestCase {
random(), Boolean.TRUE, null); random(), Boolean.TRUE, null);
nodeAssessment2_2Root.setCompletion(0.2); nodeAssessment2_2Root.setCompletion(0.2);
assessmentEntryDao.updateAssessmentEntry(nodeAssessment2_2Root); assessmentEntryDao.updateAssessmentEntry(nodeAssessment2_2Root);
AssessmentEntry nodeAssessment2_3Root = assessmentEntryDao.createAssessmentEntry(assessedIdentity2, null, entry3,
random(), Boolean.TRUE, null);
nodeAssessment2_3Root.setCompletion(null);
assessmentEntryDao.updateAssessmentEntry(nodeAssessment2_3Root);
// other identity // other identity
AssessmentEntry nodeAssessment1OtherIdent = assessmentEntryDao.createAssessmentEntry(assessedIdentityOther, null, AssessmentEntry nodeAssessment1OtherIdent = assessmentEntryDao.createAssessmentEntry(assessedIdentityOther, null,
......
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