diff --git a/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java b/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java index f7a5ac1eaac4fd50b9b2995c7da3623a85c08a6c..8b7c26978ed63954e9c54b30c04894513d573b64 100644 --- a/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java +++ b/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java @@ -63,6 +63,7 @@ import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.assessment.manager.UserCourseInformationsManager; import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.ArchiveOptions; @@ -177,8 +178,8 @@ public class ScoreAccountingHelper { header1ColCnt += acNode.getType().equals("ita") ? 1 : 0; AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(acNode); - boolean scoreOk = assessmentConfig.hasScore(); - boolean passedOk = assessmentConfig.hasPassed(); + boolean scoreOk = Mode.none != assessmentConfig.getScoreMode(); + boolean passedOk = Mode.none != assessmentConfig.getPassedMode(); boolean attemptsOk = assessmentConfig.hasAttempts(); boolean commentOk = assessmentConfig.hasComment(); if (scoreOk || passedOk || commentOk || attemptsOk) { @@ -200,8 +201,8 @@ public class ScoreAccountingHelper { } AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(acNode); - boolean scoreOk = assessmentConfig.hasScore(); - boolean passedOk = assessmentConfig.hasPassed(); + boolean scoreOk = Mode.none != assessmentConfig.getScoreMode(); + boolean passedOk = Mode.none != assessmentConfig.getPassedMode(); boolean attemptsOk = assessmentConfig.hasAttempts(); boolean commentOk = assessmentConfig.hasComment(); if (scoreOk || passedOk || commentOk || attemptsOk) { @@ -263,8 +264,8 @@ public class ScoreAccountingHelper { for (CourseNode acnode:myNodes) { AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(acnode); - boolean scoreOk = assessmentConfig.hasScore(); - boolean passedOk = assessmentConfig.hasPassed(); + boolean scoreOk = Mode.none != assessmentConfig.getScoreMode(); + boolean passedOk = Mode.none != assessmentConfig.getPassedMode(); boolean attemptsOk = assessmentConfig.hasAttempts(); boolean commentOk = assessmentConfig.hasComment(); @@ -353,7 +354,7 @@ public class ScoreAccountingHelper { boolean first = true; for (CourseNode acnode:myNodes) { AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(acnode); - if (!assessmentConfig.hasScore()) { + if (Mode.none == assessmentConfig.getScoreMode()) { // only show min/max/cut legend when score configured continue; } @@ -369,14 +370,14 @@ public class ScoreAccountingHelper { String minVal; String maxVal; String cutVal; - if(assessmentConfig.isEvaluationCalculated() || !assessmentConfig.hasScore()) { + if(assessmentConfig.isEvaluationCalculated() || Mode.none == assessmentConfig.getScoreMode()) { minVal = maxVal = cutVal = "-"; } else { Float minScoreConfig = assessmentConfig.getMinScore(); Float maxScoreConfig = assessmentConfig.getMaxScore(); minVal = minScoreConfig == null ? "-" : AssessmentHelper.getRoundedScore(minScoreConfig); maxVal = maxScoreConfig == null ? "-" : AssessmentHelper.getRoundedScore(maxScoreConfig); - if (assessmentConfig.hasPassed()) { + if (Mode.none != assessmentConfig.getPassedMode()) { Float cutValueConfig = assessmentConfig.getCutValue(); cutVal = cutValueConfig == null ? "-" : AssessmentHelper.getRoundedScore(cutValueConfig); } else { diff --git a/src/main/java/org/olat/course/assessment/AssessmentHelper.java b/src/main/java/org/olat/course/assessment/AssessmentHelper.java index cc12bb8ec5963307794505cacc6d704d046f4dd2..b98d7ad25bf24d4f5ee5f72cec03098c347f8e44 100644 --- a/src/main/java/org/olat/course/assessment/AssessmentHelper.java +++ b/src/main/java/org/olat/course/assessment/AssessmentHelper.java @@ -49,6 +49,7 @@ import org.olat.core.util.tree.TreeVisitor; import org.olat.core.util.tree.Visitor; import org.olat.course.ICourse; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.assessment.model.AssessmentNodeData; import org.olat.course.assessment.model.AssessmentNodesLastModified; import org.olat.course.nodes.CourseNode; @@ -160,11 +161,11 @@ public class AssessmentHelper { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(node); if (node instanceof STCourseNode) { - if (assessmentConfig.hasPassed() || assessmentConfig.hasScore()) { + if (Mode.none != assessmentConfig.getPassedMode() || Mode.none != assessmentConfig.getScoreMode()) { return true; } } else if (node instanceof ScormCourseNode) { - if (assessmentConfig.hasPassed() || assessmentConfig.hasScore()) { + if (Mode.none != assessmentConfig.getPassedMode() || Mode.none != assessmentConfig.getScoreMode()) { return true; } } else if (assessmentConfig.isAssessable()) { @@ -330,8 +331,8 @@ public class AssessmentHelper { return assessmentConfig.isAssessable() && ( assessmentConfig.hasEditableDetails() || assessmentConfig.hasAttempts() - || assessmentConfig.hasScore() - || assessmentConfig.hasPassed() + || Mode.none != assessmentConfig.getScoreMode() + || Mode.none != assessmentConfig.getPassedMode() || assessmentConfig.hasComment()); } @@ -442,7 +443,7 @@ public class AssessmentHelper { } } // score - if (assessmentConfig.hasScore()) { + if (Mode.none != assessmentConfig.getScoreMode()) { hasDisplayableValuesConfigured = true; Float score = scoreEvaluation.getScore(); if (score != null) { @@ -456,7 +457,7 @@ public class AssessmentHelper { } } // passed - if (assessmentConfig.hasPassed()) { + if (Mode.none != assessmentConfig.getPassedMode()) { hasDisplayableValuesConfigured = true; Boolean passed = scoreEvaluation.getPassed(); if (passed != null) { diff --git a/src/main/java/org/olat/course/assessment/CourseAssessmentService.java b/src/main/java/org/olat/course/assessment/CourseAssessmentService.java index 17729efc7f595bebf95bcb87709fc961ac62eab5..8bbf0002c9d3ce3ed6ab776714e0c614a828b073 100644 --- a/src/main/java/org/olat/course/assessment/CourseAssessmentService.java +++ b/src/main/java/org/olat/course/assessment/CourseAssessmentService.java @@ -36,7 +36,6 @@ import org.olat.course.config.CourseConfig; import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; @@ -72,18 +71,6 @@ public interface CourseAssessmentService { */ public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment); - /** - * Returns the current, persisted AssessmentEvaluation of the user for a course - * node. The loaded values are modified according to the AssessmentConfig of the - * course node, e.g. if a user has a saved score but the the score is disabled - * in the config, the AssessmentEvaluation has a score of null. - * - * @param courseNode - * @param userCourseEnvironment - * @return - */ - public AssessmentEvaluation getPersistedAssessmentEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment); - /** * Converts the assessmentEntry to an AssessmentEvaluation in respect of the * AssessmentConfig. If the assessmentEntry is null, the method returns @@ -126,15 +113,6 @@ public interface CourseAssessmentService { public void updateScoreEvaluation(CourseNode courseNode, ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, boolean incrementAttempts, Role by); - /** - * Returns the ScoreCalculator if the course nod can calculate its score. Check - * AssessmentConfig.isEvaluationCalculated() before invoking this method. - * - * @param courseNode - * @return - */ - public ScoreCalculator getScoreCalculator(CourseNode courseNode); - /** * * @param courseNode diff --git a/src/main/java/org/olat/course/assessment/handler/AssessmentConfig.java b/src/main/java/org/olat/course/assessment/handler/AssessmentConfig.java index 4827c2be1272c5e66a1db7ca53b60386c91ea64f..b6c5a09bd18516ed6e5beb655ec35f0fcaf33e6b 100644 --- a/src/main/java/org/olat/course/assessment/handler/AssessmentConfig.java +++ b/src/main/java/org/olat/course/assessment/handler/AssessmentConfig.java @@ -41,19 +41,23 @@ public interface AssessmentConfig { public boolean isAssessable(); /** - * @return true if the assessment evaluation is persisted + * @return if this course node should be ignored in the cumulative assessment of + * the course root node. */ - public boolean isEvaluationPersisted(); + public boolean ignoreInCourseAssessment(); + + public void setIgnoreInCourseAssessment(boolean ignoreInCourseAssessment); /** * @return true if the score evaluation is calculated e.g as sum of other assessments. */ + //TODO uh delete after implementiation of passedMode public boolean isEvaluationCalculated(); /** - * @return True if this course node produces a score variable for the learner + * @return if this course node produces a score variable for the learner */ - public boolean hasScore(); + public Mode getScoreMode(); /** * @return Returns the maximal score that can be achieved on this node. Throws @@ -68,9 +72,9 @@ public interface AssessmentConfig { public Float getMinScore(); /** - * @return True if this course node produces a passed variable for the learner + * @return if this course node produces a passed variable for the learner */ - public boolean hasPassed(); + public Mode getPassedMode(); /** * @return Returns the passed cut value or null if no such value is defined. A null diff --git a/src/main/java/org/olat/course/assessment/handler/AssessmentHandler.java b/src/main/java/org/olat/course/assessment/handler/AssessmentHandler.java index 381e2e36266585cde6c16f7e3f3fb60592840599..a75cc6fcedcb72f46228d4dc3fd73ec22e8e2638 100644 --- a/src/main/java/org/olat/course/assessment/handler/AssessmentHandler.java +++ b/src/main/java/org/olat/course/assessment/handler/AssessmentHandler.java @@ -29,8 +29,6 @@ import org.olat.course.config.CourseConfig; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNodeProvider; import org.olat.course.run.scoring.AccountingEvaluators; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -68,24 +66,6 @@ public interface AssessmentHandler extends CourseNodeProvider { * @return */ public AccountingEvaluators getEvaluators(CourseNode courseNode, CourseConfig courseConfig); - - /** - * This method has to be implemented if the AssessmentConfig.isEvaluationCalculated() return true. - * - * @param courseNode - * @param userCourseEnvironment - * @return - */ - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment); - - /** - * This method has to be implemented if the AssessmentConfig.isEvaluationCalculated() return true. - * - * @param courseNode - * @param userCourseEnvironment - * @return - */ - public ScoreCalculator getScoreCalculator(CourseNode courseNode); public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, CourseNode courseNode, UserCourseEnvironment coachCourseEnv, UserCourseEnvironment assessedUserCourseEnvironment); diff --git a/src/main/java/org/olat/course/assessment/handler/ModuleAssessmentConfig.java b/src/main/java/org/olat/course/assessment/handler/ModuleAssessmentConfig.java index 59fcac089158672b8ec951613d562d07c6af5bdb..c1d141951f31a3bf788161e08ab663afc52ffc6b 100644 --- a/src/main/java/org/olat/course/assessment/handler/ModuleAssessmentConfig.java +++ b/src/main/java/org/olat/course/assessment/handler/ModuleAssessmentConfig.java @@ -43,8 +43,13 @@ public abstract class ModuleAssessmentConfig implements AssessmentConfig { } @Override - public boolean isEvaluationPersisted() { - return true; + public boolean ignoreInCourseAssessment() { + return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + } + + @Override + public void setIgnoreInCourseAssessment(boolean ignoreInCourseAssessment) { + config.setBooleanEntry(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); } @Override @@ -53,13 +58,13 @@ public abstract class ModuleAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasScore() { - return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD); + public Mode getScoreMode() { + return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD)? Mode.setByNode: Mode.none; } @Override public Float getMaxScore() { - if (!hasScore()) { + if (Mode.none == getScoreMode()) { throw new OLATRuntimeException(ModuleAssessmentConfig.class, "getMaxScore not defined when hasScoreConfigured set to false", null); } return config.getFloatEntry(MSCourseNode.CONFIG_KEY_SCORE_MAX); @@ -67,20 +72,20 @@ public abstract class ModuleAssessmentConfig implements AssessmentConfig { @Override public Float getMinScore() { - if (!hasScore()) { + if (Mode.none == getScoreMode()) { throw new OLATRuntimeException(ModuleAssessmentConfig.class, "getMinScore not defined when hasScore set to false", null); } return config.getFloatEntry(MSCourseNode.CONFIG_KEY_SCORE_MIN); } @Override - public boolean hasPassed() { - return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD); + public Mode getPassedMode() { + return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD)? Mode.setByNode: Mode.none; } @Override public Float getCutValue() { - if (!hasPassed()) { + if (Mode.none == getPassedMode()) { throw new OLATRuntimeException(ModuleAssessmentConfig.class, "getCutValue not defined when hasPassed set to false", null); } return config.getFloatEntry(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE); diff --git a/src/main/java/org/olat/course/assessment/handler/NonAssessmentConfig.java b/src/main/java/org/olat/course/assessment/handler/NonAssessmentConfig.java index fab2185b63f6e2d85daeeb63a5118abe453a9513..f1fb7d10daf3980fb3e2cf7f4a5d7af84ae3280d 100644 --- a/src/main/java/org/olat/course/assessment/handler/NonAssessmentConfig.java +++ b/src/main/java/org/olat/course/assessment/handler/NonAssessmentConfig.java @@ -37,10 +37,15 @@ public class NonAssessmentConfig implements AssessmentConfig { public boolean isAssessable() { return false; } + + @Override + public boolean ignoreInCourseAssessment() { + return true; + } @Override - public boolean isEvaluationPersisted() { - return false; + public void setIgnoreInCourseAssessment(boolean ignoreInCourseAssessment) { + // } @Override @@ -53,8 +58,8 @@ public class NonAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasScore() { - return false; + public Mode getScoreMode() { + return Mode.none; } @Override @@ -68,8 +73,8 @@ public class NonAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasPassed() { - return false; + public Mode getPassedMode() { + return Mode.none; } @Override @@ -132,4 +137,5 @@ public class NonAssessmentConfig implements AssessmentConfig { return false; } + } diff --git a/src/main/java/org/olat/course/assessment/handler/NonAssessmentHandler.java b/src/main/java/org/olat/course/assessment/handler/NonAssessmentHandler.java index 7cd4ec638fe3cdf82e2e023f681390283318a3b7..896cab0d93a6f0b0c05d6eaa6dbe4aeeaab607d9 100644 --- a/src/main/java/org/olat/course/assessment/handler/NonAssessmentHandler.java +++ b/src/main/java/org/olat/course/assessment/handler/NonAssessmentHandler.java @@ -29,8 +29,6 @@ import org.olat.course.config.CourseConfig; import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -70,17 +68,6 @@ public class NonAssessmentHandler implements AssessmentHandler { return AccountingEvaluatorsBuilder.defaultConventional(); } - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } - @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, CourseNode courseNode, UserCourseEnvironment coachCourseEnv, diff --git a/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java b/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java index bbb74215d1b1e5d2fc37914e4e37156a0aead372..e78a6986512f61a6c2bf8deff260b79353595b54 100644 --- a/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java +++ b/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java @@ -75,6 +75,7 @@ import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.bulk.BulkAssessmentOverviewController; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.assessment.model.BulkAssessmentDatas; import org.olat.course.assessment.model.BulkAssessmentFeedback; import org.olat.course.assessment.model.BulkAssessmentRow; @@ -310,8 +311,8 @@ public class BulkAssessmentTask implements LongRunnable, TaskAwareRunnable, Sequ final AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); final boolean hasUserComment = assessmentConfig.hasComment(); - final boolean hasScore = assessmentConfig.hasScore(); - final boolean hasPassed = assessmentConfig.hasPassed(); + final boolean hasScore = Mode.none != assessmentConfig.getScoreMode(); + final boolean hasPassed = Mode.none != assessmentConfig.getPassedMode(); final boolean hasReturnFiles = (StringHelper.containsNonWhitespace(datas.getReturnFiles()) && (courseNode instanceof TACourseNode || courseNode instanceof GTACourseNode)); diff --git a/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java index dc86656a66b3b7a9b27587811041d416c29e1532..33f29afec20f5b3b0af37532c28f33407439cd80 100644 --- a/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java +++ b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java @@ -56,7 +56,6 @@ import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.navigation.NodeVisitedListener; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; @@ -135,12 +134,6 @@ public class CourseAssessmentServiceImpl implements CourseAssessmentService, Nod public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) { return getAssessmentHandler(courseNode).getAssessmentEntry(courseNode, userCourseEnvironment); } - - @Override - public AssessmentEvaluation getPersistedAssessmentEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) { - AssessmentEntry assessmentEntry = getAssessmentHandler(courseNode).getAssessmentEntry(courseNode, userCourseEnvironment); - return toAssessmentEvaluation(assessmentEntry, courseNode); - } @Override public AssessmentEvaluation toAssessmentEvaluation(AssessmentEntry assessmentEntry, AssessmentConfig assessmentConfig) { @@ -155,17 +148,8 @@ public class CourseAssessmentServiceImpl implements CourseAssessmentService, Nod @Override public AssessmentEvaluation getAssessmentEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) { - AssessmentConfig assessmentConfig = getAssessmentConfig(courseNode); - AssessmentHandler assessmentHandler = getAssessmentHandler(courseNode); - - AssessmentEvaluation assessmentEvaluation = AssessmentEvaluation.EMPTY_EVAL; - if (assessmentConfig.isEvaluationCalculated()) { - assessmentEvaluation = assessmentHandler.getCalculatedScoreEvaluation(courseNode, userCourseEnvironment); - } else if (assessmentConfig.isEvaluationPersisted()) { - assessmentEvaluation = getPersistedAssessmentEvaluation(courseNode, userCourseEnvironment); - } - // Other handlers should be able to have other implementations - return assessmentEvaluation; + AssessmentEntry assessmentEntry = getAssessmentHandler(courseNode).getAssessmentEntry(courseNode, userCourseEnvironment); + return toAssessmentEvaluation(assessmentEntry, courseNode); } @Override @@ -179,12 +163,6 @@ public class CourseAssessmentServiceImpl implements CourseAssessmentService, Nod userCourseEnvironment, incrementAttempts, by); } - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - ScoreCalculator scoreCalculator = getAssessmentHandler(courseNode).getScoreCalculator(courseNode); - return scoreCalculator != null? scoreCalculator: new ScoreCalculator(); - } - @Override public Double getCurrentRunCompletion(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) { AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager(); diff --git a/src/main/java/org/olat/course/assessment/model/BulkAssessmentSettings.java b/src/main/java/org/olat/course/assessment/model/BulkAssessmentSettings.java index d772a3305f6357aff0ce04ab994f8c8ffa74e427..9c394fd0608926ca2595429bf391288b54d3fe14 100644 --- a/src/main/java/org/olat/course/assessment/model/BulkAssessmentSettings.java +++ b/src/main/java/org/olat/course/assessment/model/BulkAssessmentSettings.java @@ -25,6 +25,7 @@ import java.io.Serializable; import org.olat.core.CoreSpringFactory; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.ProjectBrokerCourseNode; @@ -53,8 +54,8 @@ public class BulkAssessmentSettings implements Serializable { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); hasUserComment = assessmentConfig.hasComment(); - hasScore = assessmentConfig.hasScore(); - hasPassed = assessmentConfig.hasPassed(); + hasScore = Mode.none != assessmentConfig.getScoreMode(); + hasPassed = Mode.none != assessmentConfig.getPassedMode(); ModuleConfiguration config = courseNode.getModuleConfiguration(); if (courseNode instanceof TACourseNode) { diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessedBusinessGroupCourseNodeListController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessedBusinessGroupCourseNodeListController.java index ce70afb86ce925fa8ed461b0e915190e8da925cb..ca8e49af4844beee02d40322586fc97fa413d6f7 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/AssessedBusinessGroupCourseNodeListController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessedBusinessGroupCourseNodeListController.java @@ -53,6 +53,7 @@ import org.olat.course.assessment.AssessmentModule; import org.olat.course.assessment.AssessmentToolManager; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.assessment.model.AssessedBusinessGroup; import org.olat.course.assessment.model.SearchAssessedIdentityParams; import org.olat.course.assessment.ui.tool.AssessedBusinessGroupTableModel.ABGCols; @@ -119,11 +120,11 @@ public class AssessedBusinessGroupCourseNodeListController extends FormBasicCont columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ABGCols.name, "select")); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if(assessmentConfig.hasPassed()) { + if(Mode.none != assessmentConfig.getPassedMode()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ABGCols.countPassed, new ProgressRenderer(false, getTranslator()))); } - if(assessmentConfig.hasScore()) { + if(Mode.none != assessmentConfig.getScoreMode()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ABGCols.averageScore, new ScoreCellRenderer())); } diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java index 47aeb9ba4f31dba1bc23d326e1052c61a310f071..d238c38d42216162cf5d43cfa6d29a14ccfb9467 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java @@ -61,6 +61,7 @@ import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.AssessmentModule; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.ScoreAccounting; import org.olat.course.run.scoring.ScoreEvaluation; @@ -129,8 +130,8 @@ public class AssessmentForm extends FormBasicController { AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); hasAttempts = assessmentConfig.hasAttempts(); - hasScore = assessmentConfig.hasScore(); - hasPassed = assessmentConfig.hasPassed(); + hasScore = Mode.none != assessmentConfig.getScoreMode(); + hasPassed = Mode.none != assessmentConfig.getPassedMode(); hasComment = assessmentConfig.hasComment(); hasIndividualAssessmentDocs = assessmentConfig.hasIndividualAsssessmentDocuments(); 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 5e3db3ee1b0faa5a2ea7f1c5c42660c9d55af521..107d266ea49aa60b5702ad4bfb50c65a19db09f2 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 @@ -79,6 +79,7 @@ import org.olat.course.assessment.AssessmentToolManager; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.bulk.PassedCellRenderer; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.assessment.model.SearchAssessedIdentityParams; import org.olat.course.assessment.ui.tool.IdentityListCourseNodeTableModel.IdentityCourseElementCols; import org.olat.course.assessment.ui.tool.event.ShowDetailsEvent; @@ -375,7 +376,7 @@ public class IdentityListCourseNodeController extends FormBasicController columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.userVisibility, new UserVisibilityCellRenderer(getTranslator()))); } - if(assessmentConfig.hasScore()) { + if(Mode.none != assessmentConfig.getScoreMode()) { if(!assessmentConfig.isEvaluationCalculated()) { if(assessmentConfig.getMinScore() != null) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.min, new ScoreCellRenderer())); @@ -383,13 +384,13 @@ public class IdentityListCourseNodeController extends FormBasicController if(assessmentConfig.getMaxScore() != null) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.max, new ScoreCellRenderer())); } - if(assessmentConfig.hasPassed() && assessmentConfig.getCutValue() != null) { + if(Mode.none != assessmentConfig.getPassedMode() && assessmentConfig.getCutValue() != null) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, IdentityCourseElementCols.cut, new ScoreCellRenderer())); } } initScoreColumns(columnsModel); } - if(assessmentConfig.hasPassed()) { + if(Mode.none != assessmentConfig.getPassedMode()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.passed, new PassedCellRenderer())); } if(assessmentConfig.hasIndividualAsssessmentDocuments()) { diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeTableModel.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeTableModel.java index 888d916eedf73407952832517ee57f474d6eef2e..e9314560d946271cef6b8fa9a690e0f5e6f91304 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeTableModel.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeTableModel.java @@ -37,6 +37,7 @@ import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.certificate.CertificateLight; import org.olat.course.nodes.CourseNode; import org.olat.modules.assessment.model.AssessmentEntryStatus; @@ -70,10 +71,10 @@ public class IdentityListCourseNodeTableModel extends DefaultFlexiTableDataModel if (courseNode != null) { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if(!assessmentConfig.isEvaluationCalculated() && assessmentConfig.hasScore()) { + if(Mode.setByNode == assessmentConfig.getScoreMode()) { maxScore = assessmentConfig.getMaxScore(); minScore = assessmentConfig.getMinScore(); - if (assessmentConfig.hasPassed()) { + if (Mode.setByNode == assessmentConfig.getPassedMode()) { cutValue = assessmentConfig.getCutValue(); } } diff --git a/src/main/java/org/olat/course/certificate/ui/CertificatesOptionsController.java b/src/main/java/org/olat/course/certificate/ui/CertificatesOptionsController.java index ee5005fe8124c8aa3907912d43b35b23c62a01bc..160a550320106c2f8496eae9a75c8b41393363d7 100644 --- a/src/main/java/org/olat/course/certificate/ui/CertificatesOptionsController.java +++ b/src/main/java/org/olat/course/certificate/ui/CertificatesOptionsController.java @@ -24,7 +24,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Collection; -import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -49,42 +48,27 @@ 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.generic.closablewrapper.CloseableModalController; -import org.olat.core.gui.control.generic.modal.DialogBoxController; -import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.media.StreamedMediaResource; import org.olat.core.gui.media.ZippedDirectoryMediaResource; -import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.Tracing; -import org.olat.core.logging.activity.ILoggingAction; -import org.olat.core.logging.activity.LearningResourceLoggingAction; -import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.FileUtils; import org.olat.core.util.Util; -import org.olat.core.util.coordinate.CoordinatorManager; -import org.olat.core.util.coordinate.LockResult; -import org.olat.core.util.event.EventBus; import org.olat.core.util.vfs.JavaIOItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSMediaResource; import org.olat.course.CourseFactory; import org.olat.course.ICourse; -import org.olat.course.assessment.manager.EfficiencyStatementManager; import org.olat.course.certificate.CertificateTemplate; import org.olat.course.certificate.CertificatesManager; import org.olat.course.certificate.PDFCertificatesOptions; import org.olat.course.certificate.RecertificationTimeUnit; import org.olat.course.certificate.model.PreviewCertificate; import org.olat.course.config.CourseConfig; -import org.olat.course.config.CourseConfigEvent; -import org.olat.course.config.CourseConfigEvent.CourseConfigType; -import org.olat.course.config.ui.CourseOptionsController; import org.olat.course.run.RunMainController; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryManagedFlag; -import org.olat.repository.RepositoryManager; -import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; /** @@ -94,9 +78,8 @@ import org.springframework.beans.factory.annotation.Autowired; * */ public class CertificatesOptionsController extends FormBasicController { - + private MultipleSelectionElement pdfCertificatesEl; - private MultipleSelectionElement efficencyEl; private TextElement certificationCustom1El; private TextElement certificationCustom2El; private TextElement certificationCustom3El; @@ -114,8 +97,7 @@ public class CertificatesOptionsController extends FormBasicController { private CloseableModalController cmc; private CertificateChooserController certificateChooserCtrl; - private DialogBoxController enableEfficiencyDC, disableEfficiencyDC; - + private static final String[] pdfCertificatesOptionsKeys = new String[] { PDFCertificatesOptions.auto.name(), PDFCertificatesOptions.manual.name() @@ -129,67 +111,34 @@ public class CertificatesOptionsController extends FormBasicController { }; private final String mapperUrl; - private LockResult lockEntry; - @Autowired - private UserManager userManager; + @Autowired private CertificatesManager certificatesManager; - @Autowired - private EfficiencyStatementManager efficiencyStatementManager; - /** - * @param name - * @param chatEnabled - */ public CertificatesOptionsController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, CourseConfig courseConfig, boolean editable) { super(ureq, wControl); - setTranslator(Util.createPackageTranslator(CourseOptionsController.class, getLocale(), getTranslator())); setTranslator(Util.createPackageTranslator(RunMainController.class, getLocale(), getTranslator())); this.courseConfig = courseConfig; this.entry = entry; + this.editable = editable; mapperUrl = registerMapper(ureq, new TemplateMapper()); - lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker() - .acquireLock(entry.getOlatResource(), getIdentity(), CourseFactory.COURSE_EDITOR_LOCK); - this.editable = (lockEntry != null && lockEntry.isSuccess()) && editable; - - initForm (ureq); - if(lockEntry != null && !lockEntry.isSuccess()) { - String lockerName = "???"; - if(lockEntry.getOwner() != null) { - lockerName = userManager.getUserDisplayName(lockEntry.getOwner()); - } - showWarning("error.editoralreadylocked", new String[] { lockerName }); - } + initForm(ureq); } @Override protected void doDispose() { - if (lockEntry != null && lockEntry.isSuccess()) { - CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lockEntry); - lockEntry = null; - } + // } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - setFormTitle("options.certificates.title"); - setFormTitleIconCss("o_icon o_icon_certificate"); - setFormDescription("options.certificates.descr"); - setFormContextHelp("Course Settings#_leistungsnachweis"); - formLayout.setElementCssClass("o_sel_course_certificates"); + setFormTitle("options.certificate.title"); - boolean effEnabled = courseConfig.isEfficencyStatementEnabled(); boolean managedEff = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.efficencystatement); - efficencyEl = uifactory.addCheckboxesHorizontal("effIsOn", "chkbx.efficency.onoff", formLayout, new String[] {"xx"}, new String[] {""}); - efficencyEl.addActionListener(FormEvent.ONCHANGE); - efficencyEl.select("xx", effEnabled); - efficencyEl.setEnabled(editable && !managedEff); - - String[] pdfCertificatesOptionsValues = new String[] { translate("pdf.certificates.auto"), translate("pdf.certificates.manual") @@ -303,15 +252,7 @@ public class CertificatesOptionsController extends FormBasicController { @Override protected void event(UserRequest ureq, Controller source, Event event) { - if (source == disableEfficiencyDC) { - if (DialogBoxUIFactory.isOkEvent(event)) { - doChangeConfig(ureq); - } - } else if (source == enableEfficiencyDC) { - if (DialogBoxUIFactory.isOkEvent(event)) { - doChangeConfig(ureq); - } - } else if(source == certificateChooserCtrl) { + if(source == certificateChooserCtrl) { if(event == Event.DONE_EVENT) { doSetTemplate(certificateChooserCtrl.getSelectedTemplate()); } @@ -340,7 +281,7 @@ public class CertificatesOptionsController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { - doSave(ureq); + doChangeConfig(ureq); } private void doPreviewTemplate(UserRequest ureq) { @@ -377,21 +318,6 @@ public class CertificatesOptionsController extends FormBasicController { cmc.activate(); } - private void doSave(UserRequest ureq) { - boolean confirmUpdateStatement = courseConfig.isEfficencyStatementEnabled() != efficencyEl.isSelected(0); - if(confirmUpdateStatement) { - if (courseConfig.isEfficencyStatementEnabled()) { - // a change from enabled Efficiency to disabled - disableEfficiencyDC = activateYesNoDialog(ureq, null, translate("warning.change.todisabled"), disableEfficiencyDC); - } else { - // a change from disabled Efficiency - enableEfficiencyDC = activateYesNoDialog(ureq, null, translate("warning.change.toenable"), enableEfficiencyDC); - } - } else { - doChangeConfig(ureq); - } - } - private void doChangeConfig(UserRequest ureq) { OLATResourceable courseOres = entry.getOlatResource(); if(CourseFactory.isCourseEditSessionOpen(courseOres.getResourceableId())) { @@ -402,10 +328,6 @@ public class CertificatesOptionsController extends FormBasicController { ICourse course = CourseFactory.openCourseEditSession(courseOres.getResourceableId()); courseConfig = course.getCourseEnvironment().getCourseConfig(); - boolean enableEfficiencyStatment = efficencyEl.isSelected(0); - boolean updateStatement = courseConfig.isEfficencyStatementEnabled() != enableEfficiencyStatment; - courseConfig.setEfficencyStatementIsEnabled(enableEfficiencyStatment); - Collection<String> certificationOptions = pdfCertificatesEl.getSelectedKeys(); courseConfig.setAutomaticCertificationEnabled(certificationOptions.contains(PDFCertificatesOptions.auto.name())); courseConfig.setManualCertificationEnabled(certificationOptions.contains(PDFCertificatesOptions.manual.name())); @@ -442,29 +364,6 @@ public class CertificatesOptionsController extends FormBasicController { CourseFactory.setCourseConfig(course.getResourceableId(), courseConfig); CourseFactory.closeCourseEditSession(course.getResourceableId(), true); - if(updateStatement) { - if(enableEfficiencyStatment) { - // first create the efficiencies, send event to agency (all courses add link) - RepositoryEntry courseRe = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); - List<Identity> identitiesWithData = course.getCourseEnvironment().getCoursePropertyManager().getAllIdentitiesWithCourseAssessmentData(null); - efficiencyStatementManager.updateEfficiencyStatements(courseRe, identitiesWithData); - } else { - // delete really the efficiencies of the users. - RepositoryEntry courseRepoEntry = RepositoryManager.getInstance().lookupRepositoryEntry(course, true); - efficiencyStatementManager.deleteEfficiencyStatementsFromCourse(courseRepoEntry.getKey()); - } - - //inform everybody else - EventBus eventBus = CoordinatorManager.getInstance().getCoordinator().getEventBus(); - CourseConfigEvent courseConfigEvent = new CourseConfigEvent(CourseConfigType.efficiencyStatement, course.getResourceableId()); - eventBus.fireEventToListenersOf(courseConfigEvent, course); - - ILoggingAction loggingAction = enableEfficiencyStatment ? - LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_EFFICIENCY_STATEMENT_ENABLED : - LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_EFFICIENCY_STATEMENT_DISABLED; - ThreadLocalUserActivityLogger.log(loggingAction, getClass()); - } - fireEvent(ureq, Event.CHANGED_EVENT); } diff --git a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties index ef2f5e31d5dc52fbf8fcfb06b19e87c92e09dbf7..91a75beb0aaaf041b2e65f6315e945ef21c926e4 100644 --- a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties @@ -25,8 +25,7 @@ details.certificate=Zertifikat details.course.infos=Bewertungen download.button=Zertifikat herunterladen error.mail.invalid=Bitte geben Sie eine g\u00FCltige E-Mailadresse an. -options.certificates.title=Konfiguration Leistungnachweis -options.certificates.descr=Damit Kurse als bestanden angezeigt werden k\u00F6nnen, muss im Kurshauptknoten zwingend im "Punkte"-Tab die Option <strong>Bestanden berechnen?</strong> aktiviert werden. +options.certificate.title=Zertifikat generate.certificate=Zertifikat erzeugen no.certificate=Kein Zertifikat vorhanden pdf.certificates=PDF Zertifikat erzeugen diff --git a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_en.properties index 22a0dfdb6c5c5af9867d7a8168e780a9f7b5b266..3421c35650ece806ed2e406d04fef5d53e784350 100644 --- a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_en.properties @@ -47,8 +47,7 @@ no.certificate=No certificate available notifications.desc={0} received a new certificate. notifications.header=New certificates for the course "{0}". notifications.title=New Certificates in course "{0}". -options.certificates.title=Evidence of achievement configuration -options.certificates.descr=Courses will only be listed as passed if the checkbox <strong>Calculate passing score?</strong> is selected in the "Score" tab in the course root node. +options.certificate.title=Certificate orientation=Orientation pdf.certificates=Generate PDF certificate pdf.certificates.auto=Automatically after passing the course diff --git a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_fr.properties index 601e0498f981b5be29b1005ef2d15c553a7f8d51..277bc9fe9db739857613a81c0b6bd400cf3a2d34 100644 --- a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_fr.properties @@ -46,8 +46,6 @@ no.certificate=Aucun certificat disponible notifications.desc={0} a re\u00E7u un nouveau certificat. notifications.header=Nouveaux certificats pour le cours "{0}" notifications.title=Nouveaux certificats pour le cours "{0}" -options.certificates.descr=Un cours ne sera affich\u00E9 comme r\u00E9ussi que si la case \u00E0 cocher <strong>Calculer r\u00E9ussite?</strong> est s\u00E9lectionn\u00E9e dans le tab "Points" de l'\u00E9l\u00E9ment racine du cours. -options.certificates.title=Configuration des attestions de performance orientation=Orientation pdf.certificates=G\u00E9n\u00E9rer un certificat PDF pdf.certificates.auto=Automatiquement quand le cours est r\u00E9ussi diff --git a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_it.properties index 498ba6ad94ffc444c3d1c0e6030b636e37faaa2e..948fcddba24076bd8351022e8459076515930bf4 100644 --- a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_it.properties @@ -38,8 +38,6 @@ no.certificate=Nessun certificato disponibile notifications.desc={0} ha ricevuto un nuovo certificato. notifications.header=Nuovo certificato per il corso "{0}". notifications.title=Nuovo certificato nel corso "{0}". -options.certificates.descr=I corsi saranno elencati come superati se il checkbox <strong>Calcolare punteggio di superamento?</strong> \u00E8 selezionato nel tab "Punteggio" nel nodo radice del corso. -options.certificates.title=Configurazione degli attestati di efficienza orientation=Orientamento pdf.certificates=Generare un certificato PDF pdf.certificates.auto=Automaticamente al superamento del corso diff --git a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_pt_BR.properties index 5bab1c425526e317de1dfa879516c2cd30338f24..8bc5a1d6bf7068b747a4c7710c134c30b97f9dfe 100644 --- a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_pt_BR.properties @@ -44,8 +44,6 @@ no.certificate=Nenhum certificado dispon\u00EDvel notifications.desc={0} recebeu um novo certificado notifications.header=Novos certificados para o curso "{0}". notifications.title=Novos Certificados no curso "{0}". -options.certificates.descr=Cursos s\u00F3 ser\u00E3o listados como "passou" se a caixa de sele\u00E7\u00E3o <strong>Calcular pontua\u00E7\u00E3o de aprova\u00E7\u00E3o?</strong> estiver selecionado na aba "Pontua\u00E7\u00E3o" na raiz do menu do curso. -options.certificates.title=Configura\u00E7\u00E3o dos comprovantes de conclus\u00E3o orientation=Orienta\u00E7\u00E3o pdf.certificates=Gerar certificado PDF pdf.certificates.auto=Automaticamente depois de passar no Curso diff --git a/src/main/java/org/olat/course/condition/ConditionNodeAccessProvider.java b/src/main/java/org/olat/course/condition/ConditionNodeAccessProvider.java index 1e8d0360baf2ad4575f010d1605cd93092017d89..4386f9296fc71cff5d8d11571810b11ec041ca31 100644 --- a/src/main/java/org/olat/course/condition/ConditionNodeAccessProvider.java +++ b/src/main/java/org/olat/course/condition/ConditionNodeAccessProvider.java @@ -71,6 +71,11 @@ public class ConditionNodeAccessProvider implements NodeAccessProvider { return true; } + @Override + public boolean isScoreCalculatorSupported() { + return true; + } + @Override public TabbableController createEditController(UserRequest ureq, WindowControl wControl, CourseNode courseNode, UserCourseEnvironment userCourseEnv, CourseEditorTreeModel editorModel) { diff --git a/src/main/java/org/olat/course/config/ui/CourseResultController.java b/src/main/java/org/olat/course/config/ui/CourseResultController.java new file mode 100644 index 0000000000000000000000000000000000000000..b78585484948b4c104006083da30714d0a836632 --- /dev/null +++ b/src/main/java/org/olat/course/config/ui/CourseResultController.java @@ -0,0 +1,120 @@ +/** + * <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.course.config.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +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.Util; +import org.olat.core.util.coordinate.CoordinatorManager; +import org.olat.core.util.coordinate.LockResult; +import org.olat.course.CourseFactory; +import org.olat.course.certificate.ui.CertificatesOptionsController; +import org.olat.course.config.CourseConfig; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.run.RunMainController; +import org.olat.repository.RepositoryEntry; +import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 9 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class CourseResultController extends BasicController { + + private Controller scoreCtrl; + private Controller efficiencyStatementCtrl; + private Controller certificatesCtrl; + + private LockResult lockEntry; + + @Autowired + private UserManager userManager; + @Autowired + private NodeAccessService nodeAccessService; + + protected CourseResultController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, CourseConfig courseConfig, boolean editable) { + super(ureq, wControl); + setTranslator(Util.createPackageTranslator(RunMainController.class, getLocale(), getTranslator())); + + lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker() + .acquireLock(entry.getOlatResource(), getIdentity(), CourseFactory.COURSE_EDITOR_LOCK); + boolean editableAndLocked = (lockEntry != null && lockEntry.isSuccess()) && editable; + + if (lockEntry != null && !lockEntry.isSuccess()) { + String lockerName = "???"; + if(lockEntry.getOwner() != null) { + lockerName = userManager.getUserDisplayName(lockEntry.getOwner()); + } + showWarning("error.editoralreadylocked", new String[] { lockerName }); + } + + VelocityContainer mainVC = createVelocityContainer("course_result"); + + if (!nodeAccessService.isScoreCalculatorSupported(courseConfig.getNodeAccessType())) { + scoreCtrl = new CourseScoreController(ureq, wControl, entry, editableAndLocked); + listenTo(scoreCtrl); + mainVC.put("score", scoreCtrl.getInitialComponent()); + } + + efficiencyStatementCtrl = new EfficiencyStatementController(ureq, wControl, entry, courseConfig, editableAndLocked); + listenTo(efficiencyStatementCtrl); + mainVC.put("efficiencyStatement", efficiencyStatementCtrl.getInitialComponent()); + + certificatesCtrl = new CertificatesOptionsController(ureq, wControl, entry, courseConfig, editableAndLocked); + listenTo(certificatesCtrl); + mainVC.put("certificate", certificatesCtrl.getInitialComponent()); + + putInitialPanel(mainVC); + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if (source == scoreCtrl) { + fireEvent(ureq, event); + } else if (source == efficiencyStatementCtrl) { + fireEvent(ureq, event); + } if (source == certificatesCtrl) { + fireEvent(ureq, event); + } + super.event(ureq, source, event); + } + + @Override + protected void doDispose() { + if (lockEntry != null && lockEntry.isSuccess()) { + CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lockEntry); + lockEntry = null; + } + } + +} diff --git a/src/main/java/org/olat/course/config/ui/CourseScoreController.java b/src/main/java/org/olat/course/config/ui/CourseScoreController.java new file mode 100644 index 0000000000000000000000000000000000000000..9b22e6767cd5681b17380b53243dd3cd237cd38b --- /dev/null +++ b/src/main/java/org/olat/course/config/ui/CourseScoreController.java @@ -0,0 +1,291 @@ +/** + * <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.course.config.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.util.KeyValues; +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.id.OLATResourceable; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.course.CourseFactory; +import org.olat.course.ICourse; +import org.olat.course.assessment.CourseAssessmentService; +import org.olat.course.nodes.STCourseNode; +import org.olat.course.run.RunMainController; +import org.olat.course.tree.CourseEditorTreeNode; +import org.olat.modules.ModuleConfiguration; +import org.olat.repository.RepositoryEntry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 9 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class CourseScoreController extends FormBasicController { + + private static final String SCORE_VALUE_NONE = "options.score.points.none"; + private static final String[] ONE_OPTION = { "xx" }; + private static final String[] UNTRANSLATED = { "" }; + + private SingleSelection scoreEl; + private MultipleSelectionElement passedProgressEl; + private MultipleSelectionElement passedAllEl; + private MultipleSelectionElement passedPointsEl; + private TextElement passedPointsCutEl; + + private final RepositoryEntry courseEntry; + private final boolean editable; + + @Autowired + private CourseAssessmentService courseAssessmentService; + + public CourseScoreController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, boolean editable) { + super(ureq, wControl); + setTranslator(Util.createPackageTranslator(RunMainController.class, getLocale(), getTranslator())); + this.courseEntry = entry; + this.editable = editable; + + initScoreCalculatorSupport(ureq); + + initForm(ureq); + } + + /** + * This is a security procedure to ensure the right value in CONFIG_SCORE_CALCULATOR_SUPPORTED. + * In releases between OO 15.pre.0 and 15.pre.7 this value was not set. + * If a user has access to this controller we have to set the value. + * + * @param ureq + */ + private void initScoreCalculatorSupport(UserRequest ureq) { + OLATResourceable courseOres = courseEntry.getOlatResource(); + if(CourseFactory.isCourseEditSessionOpen(courseOres.getResourceableId())) { + showWarning("error.editoralreadylocked", new String[] { "???" }); + return; + } + + ICourse course = CourseFactory.openCourseEditSession(courseOres.getResourceableId()); + ModuleConfiguration runConfig = course.getCourseEnvironment().getRunStructure().getRootNode().getModuleConfiguration(); + + boolean scoreCalculatorSupported = runConfig.getBooleanSafe(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED, true); + if (scoreCalculatorSupported) { + CourseEditorTreeNode courseEditorTreeNode = (CourseEditorTreeNode)course.getEditorTreeModel().getRootNode(); + ModuleConfiguration editorConfig = courseEditorTreeNode.getCourseNode().getModuleConfiguration(); + + runConfig.setBooleanEntry(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED, false); + editorConfig.setBooleanEntry(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED, false); + + CourseFactory.saveCourse(courseEntry.getOlatResource().getResourceableId()); + } + + CourseFactory.closeCourseEditSession(course.getResourceableId(), true); + + if (scoreCalculatorSupported) { + courseAssessmentService.evaluateAll(course); + fireEvent(ureq, Event.CHANGED_EVENT); + } + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + setFormTitle("options.score.title"); + + KeyValues scoreKV = new KeyValues(); + scoreKV.add(KeyValues.entry(SCORE_VALUE_NONE, translate( "options.score.points.none"))); + scoreKV.add(KeyValues.entry(STCourseNode.CONFIG_SCORE_VALUE_SUM, translate("options.score.points.sum"))); + scoreKV.add(KeyValues.entry(STCourseNode.CONFIG_SCORE_VALUE_AVG, translate("options.score.points.average"))); + scoreEl = uifactory.addDropdownSingleselect("options.score.points", formLayout, scoreKV.keys(), scoreKV.values()); + scoreEl.setEnabled(editable); + ICourse course = CourseFactory.loadCourse(courseEntry); + ModuleConfiguration moduleConfig = course.getCourseEnvironment().getRunStructure().getRootNode().getModuleConfiguration(); + String scoreKey = moduleConfig.has(STCourseNode.CONFIG_SCORE_KEY)? moduleConfig.getStringValue(STCourseNode.CONFIG_SCORE_KEY): SCORE_VALUE_NONE; + scoreEl.select(scoreKey, true); + + // Passed + StaticTextElement passedIfEl = uifactory.addStaticTextElement("options.passed.if", null, formLayout); + passedIfEl.setHelpTextKey("options.passed.if.help", null); + + passedProgressEl = uifactory.addCheckboxesHorizontal("options.passed.progress", formLayout, ONE_OPTION, UNTRANSLATED); + boolean passedProgress = moduleConfig.getBooleanSafe(STCourseNode.CONFIG_PASSED_PROGRESS); + passedProgressEl.select(passedProgressEl.getKey(0), passedProgress); + passedProgressEl.setEnabled(editable); + + passedAllEl = uifactory.addCheckboxesHorizontal("options.passed.all", formLayout, ONE_OPTION, UNTRANSLATED); + boolean passedAll = moduleConfig.getBooleanSafe(STCourseNode.CONFIG_PASSED_ALL); + passedAllEl.select(passedAllEl.getKey(0), passedAll); + passedAllEl.setEnabled(editable); + + passedPointsEl = uifactory.addCheckboxesHorizontal("options.passed.points", formLayout, ONE_OPTION, UNTRANSLATED); + passedPointsEl.addActionListener(FormEvent.ONCHANGE); + boolean passedPoints = moduleConfig.getBooleanSafe(STCourseNode.CONFIG_PASSED_POINTS); + passedPointsEl.select(passedPointsEl.getKey(0), passedPoints); + passedPointsEl.setEnabled(editable); + + String passedPointsCut = moduleConfig.has(STCourseNode.CONFIG_PASSED_POINTS_CUT) + ? String.valueOf(moduleConfig.getIntegerSafe(STCourseNode.CONFIG_PASSED_POINTS_CUT, 1)) + : null; + passedPointsCutEl = uifactory.addTextElement("options.passed.points.cut", 10, passedPointsCut, formLayout); + passedPointsCutEl.setCheckVisibleLength(true); + passedPointsCutEl.setDisplaySize(10); + passedPointsEl.setEnabled(editable); + + if (editable) { + FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonCont.setRootForm(mainForm); + formLayout.add(buttonCont); + uifactory.addFormSubmitButton("save", buttonCont); + } + + updateUI(); + } + + private void updateUI() { + boolean passedPoints = passedPointsEl.isAtLeastSelected(1); + passedPointsCutEl.setVisible(passedPoints); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if (source == passedPointsEl) { + updateUI(); + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + allOk &= validateInteger(passedPointsCutEl, 1, Integer.MAX_VALUE, true, "error.positiv.int"); + + return allOk & super.validateFormLogic(ureq); + } + + private boolean validateInteger(TextElement el, int min, int max, boolean mandatory, String i18nKey) { + boolean allOk = true; + el.clearError(); + if(el.isEnabled() && el.isVisible()) { + String val = el.getValue(); + if(StringHelper.containsNonWhitespace(val)) { + try { + int value = Integer.parseInt(val); + if(min > value) { + allOk = false; + } else if(max < value) { + allOk = false; + } + } catch (NumberFormatException e) { + allOk = false; + } + } else if (mandatory) { + allOk = false; + } + } + if (!allOk) { + el.setErrorKey(i18nKey, null); + } + return allOk; + } + + @Override + protected void formOK(UserRequest ureq) { + OLATResourceable courseOres = courseEntry.getOlatResource(); + if(CourseFactory.isCourseEditSessionOpen(courseOres.getResourceableId())) { + showWarning("error.editoralreadylocked", new String[] { "???" }); + return; + } + + ICourse course = CourseFactory.openCourseEditSession(courseOres.getResourceableId()); + ModuleConfiguration runConfig = course.getCourseEnvironment().getRunStructure().getRootNode().getModuleConfiguration(); + CourseEditorTreeNode courseEditorTreeNode = (CourseEditorTreeNode)course.getEditorTreeModel().getRootNode(); + ModuleConfiguration editorConfig = courseEditorTreeNode.getCourseNode().getModuleConfiguration(); + + runConfig.setBooleanEntry(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED, false); + editorConfig.setBooleanEntry(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED, false); + + String selectedScoreKey = scoreEl.getSelectedKey(); + if (SCORE_VALUE_NONE.equals(selectedScoreKey)) { + runConfig.remove(STCourseNode.CONFIG_SCORE_KEY); + editorConfig.remove(STCourseNode.CONFIG_SCORE_KEY); + } else { + runConfig.setStringValue(STCourseNode.CONFIG_SCORE_KEY, selectedScoreKey); + editorConfig.setStringValue(STCourseNode.CONFIG_SCORE_KEY, selectedScoreKey); + } + + boolean passedProgress = passedProgressEl.isAtLeastSelected(1); + if (passedProgress) { + runConfig.setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + editorConfig.setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + } else { + runConfig.remove(STCourseNode.CONFIG_PASSED_PROGRESS); + editorConfig.remove(STCourseNode.CONFIG_PASSED_PROGRESS); + } + + boolean passedAll = passedAllEl.isAtLeastSelected(1); + if (passedAll) { + runConfig.setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + editorConfig.setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + } else { + runConfig.remove(STCourseNode.CONFIG_PASSED_ALL); + editorConfig.remove(STCourseNode.CONFIG_PASSED_ALL); + } + + boolean passedPoints = passedPointsEl.isAtLeastSelected(1); + if (passedPoints) { + int pointsCut = Integer.parseInt(passedPointsCutEl.getValue()); + runConfig.setBooleanEntry(STCourseNode.CONFIG_PASSED_POINTS, true); + runConfig.setIntValue(STCourseNode.CONFIG_PASSED_POINTS_CUT, pointsCut); + editorConfig.setBooleanEntry(STCourseNode.CONFIG_PASSED_POINTS, true); + editorConfig.setIntValue(STCourseNode.CONFIG_PASSED_POINTS_CUT, pointsCut); + } else { + runConfig.remove(STCourseNode.CONFIG_PASSED_POINTS); + runConfig.remove(STCourseNode.CONFIG_PASSED_POINTS_CUT); + editorConfig.remove(STCourseNode.CONFIG_PASSED_POINTS); + editorConfig.remove(STCourseNode.CONFIG_PASSED_POINTS_CUT); + } + + CourseFactory.saveCourse(courseEntry.getOlatResource().getResourceableId()); + CourseFactory.closeCourseEditSession(course.getResourceableId(), true); + + courseAssessmentService.evaluateAll(course); + + fireEvent(ureq, Event.CHANGED_EVENT); + } + + @Override + protected void doDispose() { + // + } + +} diff --git a/src/main/java/org/olat/course/config/ui/CourseSettingsController.java b/src/main/java/org/olat/course/config/ui/CourseSettingsController.java index 03af5e96ff67ce6950893f0b2dae3b36cc514d53..45deefe6ab2f21076ba881f2a0e715e0ecfda5a5 100644 --- a/src/main/java/org/olat/course/config/ui/CourseSettingsController.java +++ b/src/main/java/org/olat/course/config/ui/CourseSettingsController.java @@ -34,7 +34,6 @@ import org.olat.core.id.context.StateEntry; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; import org.olat.course.ICourse; -import org.olat.course.certificate.ui.CertificatesOptionsController; import org.olat.course.config.CourseConfig; import org.olat.course.config.ui.courselayout.CourseLayoutGeneratorController; import org.olat.repository.RepositoryEntry; @@ -52,13 +51,13 @@ public class CourseSettingsController extends RepositoryEntrySettingsController private Link layoutLink; private Link toolbarLink; private Link optionsLink; - private Link certificatesLink; + private Link resultsLink; private Link executionSettingsLink; private CourseOptionsController optionsCtrl; private CourseToolbarController toolbarCtrl; private CourseLayoutGeneratorController layoutCtrl; - private CertificatesOptionsController certificatesCtrl; + private CourseResultController resultsCtrl; private CourseExecutionSettingsController executionSettingsCtrl; public CourseSettingsController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, RepositoryEntry entry) { @@ -84,9 +83,9 @@ public class CourseSettingsController extends RepositoryEntrySettingsController toolbarLink.setElementCssClass("o_sel_toolbar"); buttonsGroup.addButton(toolbarLink, false); - certificatesLink = LinkFactory.createLink("details.certificates", getTranslator(), this); - certificatesLink.setElementCssClass("o_sel_certificates"); - buttonsGroup.addButton(certificatesLink, false); + resultsLink = LinkFactory.createLink("details.results", getTranslator(), this); + resultsLink.setElementCssClass("o_sel_results"); + buttonsGroup.addButton(resultsLink, false); optionsLink = LinkFactory.createLink("details.options", getTranslator(), this); optionsLink.setElementCssClass("o_sel_options"); @@ -107,8 +106,8 @@ public class CourseSettingsController extends RepositoryEntrySettingsController doOpenLayout(ureq); } else if("Toolbar".equalsIgnoreCase(type)) { doOpenToolbarSettings(ureq); - } else if("Certificates".equalsIgnoreCase(type)) { - doOpenCertificatesSettings(ureq); + } else if("Results".equalsIgnoreCase(type)) { + doOpenResultSettings(ureq); } else if("Options".equalsIgnoreCase(type)) { doOpenOptions(ureq); } @@ -129,9 +128,9 @@ public class CourseSettingsController extends RepositoryEntrySettingsController if(event == Event.CANCELLED_EVENT) { doOpenLayout(ureq); } - } else if(certificatesCtrl == source) { + } else if(resultsCtrl == source) { if(event == Event.CANCELLED_EVENT) { - doOpenCertificatesSettings(ureq); + doOpenResultSettings(ureq); } } else if(executionSettingsCtrl == source) { if(event == Event.CANCELLED_EVENT) { @@ -149,8 +148,8 @@ public class CourseSettingsController extends RepositoryEntrySettingsController doOpenLayout(ureq); } else if(toolbarLink == source) { doOpenToolbarSettings(ureq); - } else if(certificatesLink == source) { - doOpenCertificatesSettings(ureq); + } else if(resultsLink == source) { + doOpenResultSettings(ureq); } else if(optionsLink == source) { doOpenOptions(ureq); } @@ -162,12 +161,12 @@ public class CourseSettingsController extends RepositoryEntrySettingsController super.cleanUp(); removeAsListenerAndDispose(executionSettingsCtrl); - removeAsListenerAndDispose(certificatesCtrl); + removeAsListenerAndDispose(resultsCtrl); removeAsListenerAndDispose(optionsCtrl); removeAsListenerAndDispose(toolbarCtrl); removeAsListenerAndDispose(layoutCtrl); executionSettingsCtrl = null; - certificatesCtrl = null; + resultsCtrl = null; optionsCtrl = null; toolbarCtrl = null; layoutCtrl = null; @@ -205,14 +204,14 @@ public class CourseSettingsController extends RepositoryEntrySettingsController buttonsGroup.setSelectedButton(toolbarLink); } - private void doOpenCertificatesSettings(UserRequest ureq) { + private void doOpenResultSettings(UserRequest ureq) { ICourse course = CourseFactory.loadCourse(entry); CourseConfig courseConfig = course.getCourseEnvironment().getCourseConfig().clone(); - WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("Certificates"), null); - certificatesCtrl = new CertificatesOptionsController(ureq, swControl, entry, courseConfig, true); - listenTo(certificatesCtrl); - mainPanel.setContent(certificatesCtrl.getInitialComponent()); - buttonsGroup.setSelectedButton(certificatesLink); + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("Results"), null); + resultsCtrl = new CourseResultController(ureq, swControl, entry, courseConfig, true); + listenTo(resultsCtrl); + mainPanel.setContent(resultsCtrl.getInitialComponent()); + buttonsGroup.setSelectedButton(resultsLink); } private void doOpenOptions(UserRequest ureq) { diff --git a/src/main/java/org/olat/course/config/ui/EfficiencyStatementController.java b/src/main/java/org/olat/course/config/ui/EfficiencyStatementController.java new file mode 100644 index 0000000000000000000000000000000000000000..7ea27d8da7a03272fcc244ce1fc2f7d51a80ff87 --- /dev/null +++ b/src/main/java/org/olat/course/config/ui/EfficiencyStatementController.java @@ -0,0 +1,192 @@ +/** + * <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.course.config.ui; + +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +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.generic.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; +import org.olat.core.logging.activity.ILoggingAction; +import org.olat.core.logging.activity.LearningResourceLoggingAction; +import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; +import org.olat.core.util.Util; +import org.olat.core.util.coordinate.CoordinatorManager; +import org.olat.core.util.event.EventBus; +import org.olat.course.CourseFactory; +import org.olat.course.ICourse; +import org.olat.course.assessment.manager.EfficiencyStatementManager; +import org.olat.course.config.CourseConfig; +import org.olat.course.config.CourseConfigEvent; +import org.olat.course.config.CourseConfigEvent.CourseConfigType; +import org.olat.course.run.RunMainController; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryManagedFlag; +import org.olat.repository.RepositoryManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 9 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class EfficiencyStatementController extends FormBasicController { + + private MultipleSelectionElement efficencyEl; + + private DialogBoxController enableEfficiencyDC, disableEfficiencyDC; + + private final RepositoryEntry entry; + private CourseConfig courseConfig; + private final boolean editable; + + @Autowired + private EfficiencyStatementManager efficiencyStatementManager; + + public EfficiencyStatementController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, + CourseConfig courseConfig, boolean editable) { + super(ureq, wControl); + setTranslator(Util.createPackageTranslator(RunMainController.class, getLocale(), getTranslator())); + this.entry = entry; + this.courseConfig = courseConfig; + this.editable = editable; + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + setFormTitle("options.efficency.title"); + setFormContextHelp("Course Settings#_leistungsnachweis"); + formLayout.setElementCssClass("o_sel_course_certificates"); + + boolean effEnabled = courseConfig.isEfficencyStatementEnabled(); + boolean managedEff = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.efficencystatement); + efficencyEl = uifactory.addCheckboxesHorizontal("effIsOn", "chkbx.efficency.onoff", formLayout, new String[] {"xx"}, new String[] {""}); + efficencyEl.addActionListener(FormEvent.ONCHANGE); + efficencyEl.select("xx", effEnabled); + efficencyEl.setEnabled(editable && !managedEff); + + if (editable) { + FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonCont.setRootForm(mainForm); + formLayout.add(buttonCont); + uifactory.addFormSubmitButton("save", buttonCont); + } + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if (source == disableEfficiencyDC) { + if (DialogBoxUIFactory.isOkEvent(event)) { + doChangeConfig(ureq); + } else { + efficencyEl.select("xx", true); + } + } else if (source == enableEfficiencyDC) { + if (DialogBoxUIFactory.isOkEvent(event)) { + doChangeConfig(ureq); + } else { + efficencyEl.select("xx", false); + } + } + super.event(ureq, source, event); + } + + @Override + protected void formOK(UserRequest ureq) { + doSave(ureq); + } + + private void doSave(UserRequest ureq) { + boolean confirmUpdateStatement = courseConfig.isEfficencyStatementEnabled() != efficencyEl.isSelected(0); + if (confirmUpdateStatement) { + if (courseConfig.isEfficencyStatementEnabled()) { + // a change from enabled Efficiency to disabled + disableEfficiencyDC = activateYesNoDialog(ureq, null, translate("warning.change.todisabled"), disableEfficiencyDC); + } else { + // a change from disabled Efficiency + enableEfficiencyDC = activateYesNoDialog(ureq, null, translate("warning.change.toenable"), enableEfficiencyDC); + } + } else { + doChangeConfig(ureq); + } + } + + private void doChangeConfig(UserRequest ureq) { + OLATResourceable courseOres = entry.getOlatResource(); + if(CourseFactory.isCourseEditSessionOpen(courseOres.getResourceableId())) { + showWarning("error.editoralreadylocked", new String[] { "???" }); + return; + } + + ICourse course = CourseFactory.openCourseEditSession(courseOres.getResourceableId()); + courseConfig = course.getCourseEnvironment().getCourseConfig(); + + boolean enableEfficiencyStatment = efficencyEl.isSelected(0); + boolean updateStatement = courseConfig.isEfficencyStatementEnabled() != enableEfficiencyStatment; + courseConfig.setEfficencyStatementIsEnabled(enableEfficiencyStatment); + + CourseFactory.setCourseConfig(course.getResourceableId(), courseConfig); + CourseFactory.closeCourseEditSession(course.getResourceableId(), true); + + if(updateStatement) { + if(enableEfficiencyStatment) { + // first create the efficiencies, send event to agency (all courses add link) + RepositoryEntry courseRe = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + List<Identity> identitiesWithData = course.getCourseEnvironment().getCoursePropertyManager().getAllIdentitiesWithCourseAssessmentData(null); + efficiencyStatementManager.updateEfficiencyStatements(courseRe, identitiesWithData); + } else { + // delete really the efficiencies of the users. + RepositoryEntry courseRepoEntry = RepositoryManager.getInstance().lookupRepositoryEntry(course, true); + efficiencyStatementManager.deleteEfficiencyStatementsFromCourse(courseRepoEntry.getKey()); + } + + //inform everybody else + EventBus eventBus = CoordinatorManager.getInstance().getCoordinator().getEventBus(); + CourseConfigEvent courseConfigEvent = new CourseConfigEvent(CourseConfigType.efficiencyStatement, course.getResourceableId()); + eventBus.fireEventToListenersOf(courseConfigEvent, course); + + ILoggingAction loggingAction = enableEfficiencyStatment ? + LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_EFFICIENCY_STATEMENT_ENABLED : + LearningResourceLoggingAction.REPOSITORY_ENTRY_PROPERTIES_EFFICIENCY_STATEMENT_DISABLED; + ThreadLocalUserActivityLogger.log(loggingAction, getClass()); + } + + fireEvent(ureq, Event.CHANGED_EVENT); + } + + @Override + protected void doDispose() { + // + } + +} diff --git a/src/main/java/org/olat/course/config/ui/_content/course_result.html b/src/main/java/org/olat/course/config/ui/_content/course_result.html new file mode 100644 index 0000000000000000000000000000000000000000..d09c3c4acbf2c6d78a23ef668eb7feb6b770bd3e --- /dev/null +++ b/src/main/java/org/olat/course/config/ui/_content/course_result.html @@ -0,0 +1,9 @@ +#if($r.available("score")) + $r.render("score") +#end +#if($r.available("efficiencyStatement")) + $r.render("efficiencyStatement") +#end +#if($r.available("certificate")) + $r.render("certificate") +#end \ No newline at end of file diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties index 64489cec714f80864c1c98c3b2e125f2bc747f6a..90c2aa5b8c518a87d2ddf1dcf9e448921736bb78 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties @@ -30,8 +30,10 @@ command.glossary.remove=Auswahl l\u00F6schen course.log.changed.message=<br>Detaillierte Kurs-Log-Dateien k\u00F6nnen im Archivierungs-Tool heruntergeladen werden.<br><br>Alte Kurs-Log-Dateien (bis und mit OLAT 6.2) stehen im Ablageordner des Kurses zur Verf\u00FCgung. coursefolder=Ablageordner details.options.title=Glossar und Ressourcenordner +details.results=Resultate error.no.blog.selected=Es ist kein Blog ausgew\u00E4hlt. error.no.wiki.selected=Es ist kein Wiki ausgew\u00E4hlt. +error.positiv.int=Geben Sie eine positive Zahl ein. form.layout.changecustomcss=CSS auswechseln form.layout.choosecustomcss=Eigenes CSS w\u00E4hlen form.layout.choosesystemcss=Standard CSS w\u00E4hlen @@ -42,6 +44,18 @@ glossary.isconfigured=Gew\u00E4hltes Glossar glossary.no.glossary=Kein Glossar gew\u00E4hlt glossary.title=Titel lock.failed=Die Kurseinstellungen werden seit {1} vom Benutzer {0} editiert. +options.efficency.title=Leistungnachweis +options.passed.all=... all Kursbausteine bestanden sind +options.passed.if=Bestanden, wenn ... +options.passed.if.help=Der Teilnehmer muss mindestens eines der Kriterien erf\u00FCllen, um den Kurs zu bestehen. +options.passed.points=... Punkteschwelle erreicht ist +options.passed.points.cut=Punkteschwelle +options.passed.progress=... Lernfortschritt 100% ist +options.score.points=Punkte +options.score.points.average=Durchschnitt +options.score.points.none=Keine Punkte +options.score.points.sum=Summe +options.score.title=Punkte selectfile=Datei ausw\u00E4hlen sf.changesfresource=Auswechseln sf.notconfigured=<i>Kein Ressourcenordner ausgew\u00E4hlt</i> diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties index 1e0c691db08c20b4de1921f3c0abfdacfa37049a..c3a05b9df7e7da7c7f8ba3e7ac4d641584388668 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties @@ -30,8 +30,10 @@ command.glossary.remove=Delete selection course.log.changed.message=<br>Detailed course log files can be downloaded with the archiving tool.<br><br> Older course log files (OLAT 6.2 and earlier versions) are at your disposal in the course's storage folder. coursefolder=Storage folder details.options.title=Glossary and resource folder +details.results=Results error.no.blog.selected=No blog selected. error.no.wiki.selected=No wiki selected. +error.positiv.int=Enter a positive number. form.layout.changecustomcss=Change CSS form.layout.choosecustomcss=Choose your own CSS form.layout.choosesystemcss=Select default CSS @@ -42,6 +44,18 @@ glossary.isconfigured=Selected glossary glossary.no.glossary=No glossary selected glossary.title=Title lock.failed=These course settings are edited since {1} by user {0}. +options.efficency.title=Evidence of achievement +options.passed.all=... all course elements are passed +options.passed.if=Passed if ... +options.passed.if.help=The participant has to meet at least one criterion to pass the course. +options.passed.points=... number of points is reached +options.passed.points.cut=Cut value +options.passed.progress=... learning progess is 100% +options.score.points=Points +options.score.points.average=Average +options.score.points.none=No points +options.score.points.sum=Sum +options.score.title=Score selectfile=Choose file sf.changesfresource=Replace sf.notconfigured=<i>No resource folder selected</i> diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_fr.properties index 89169b1734885e7725fabd6ffe8fdfcacd01da4c..06c4a8120e042c876c5357a9439f724e45053a53 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_fr.properties @@ -40,6 +40,7 @@ glossary.isconfigured=Glossaire s\u00E9lectionn\u00E9 glossary.no.glossary=Aucun glossaire s\u00E9lectionn\u00E9 glossary.title=Titre lock.failed=Les r\u00E9glages du cours sont \u00E9dit\u00E9s depuis {1} par l'utilisateur {0}. +options.efficency.title=Attestions de performance selectfile=S\u00E9lectionner fichier sf.changesfresource=Changer sf.notconfigured=<i>Aucun dossier de ressource s\u00E9lectionn\u00E9</i> diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_it.properties index 0f0e6608de92f3075e50b3ecd10ce7b5d7150006..4c12a9f0014d5541ee67df96118203a9b953381b 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_it.properties @@ -20,6 +20,7 @@ glossary.isconfigured=Glossario selezionato glossary.no.glossary=Nessun glossario selezionato glossary.title=Titolo lock.failed=Le preferenze del corso vengono editate da {1} dall'utente {0}. +options.efficency.title=Attestati di efficienza selectfile=Selezionare file sf.changesfresource=Sostituire sf.notconfigured=<i>Nessuna cartella delle risorse selezionata</i> diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_pt_BR.properties index 2eb52419f84d9036ced233f0d76fa30150ff0e3b..c375ef9c6893afd39576ba2b784452bb230b4759 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_pt_BR.properties @@ -26,6 +26,7 @@ glossary.isconfigured=Atualmente o seguinte gloss\u00E1rio \u00E9 usado\: glossary.no.glossary=Atualmente n\u00E3o h\u00E1 nenhum gloss\u00E1rio usado glossary.title=T\u00EDtulo lock.failed=As configura\u00E7\u00F5s do curso est\u00E3o editadas desde {1} pelo usu\u00E1rio {0}. +options.efficency.title=Comprovantes de conclus\u00E3o selectfile=Escolher arquivo sf.changesfresource=Substituir sf.notconfigured=<i>Nenhuma pasta de recurso selecionado</i> diff --git a/src/main/java/org/olat/course/editor/EditorMainController.java b/src/main/java/org/olat/course/editor/EditorMainController.java index d6b7f26175d6a26c1bae40ed55b4fa193fde5f6e..30662e6404745475e57e624dd3885e202b7ec4b1 100644 --- a/src/main/java/org/olat/course/editor/EditorMainController.java +++ b/src/main/java/org/olat/course/editor/EditorMainController.java @@ -95,6 +95,7 @@ import org.olat.course.assessment.AssessmentModeManager; import org.olat.course.editor.overview.OverviewController; import org.olat.course.folder.CourseContainerOptions; import org.olat.course.groupsandrights.CourseGroupManager; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNodeConfiguration; import org.olat.course.nodes.CourseNodeFactory; @@ -192,6 +193,7 @@ public class EditorMainController extends MainLayoutBasicController implements G private final OLATResourceable ores; private RepositoryEntry repoEntry; + private final NodeAccessType nodeAccessType; private static final Logger log = Tracing.createLoggerFor(EditorMainController.class); private final static String RELEASE_LOCK_AT_CATCH_EXCEPTION = "Must release course lock since an exception occured in " + EditorMainController.class; @@ -201,7 +203,8 @@ public class EditorMainController extends MainLayoutBasicController implements G public EditorMainController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbar, ICourse course, CourseNode selectedNode) { super(ureq,wControl); - this.ores = OresHelper.clone(course); + this.ores = OresHelper.clone(course); + this.nodeAccessType = NodeAccessType.of(course); this.stackPanel = toolbar; // OLAT-4955: setting the stickyActionType here passes it on to any controller defined in the scope of the editor, @@ -1185,8 +1188,8 @@ public class EditorMainController extends MainLayoutBasicController implements G private void launchChecklistsWizard(UserRequest ureq) { removeAsListenerAndDispose(checklistWizard); - Step start = new CheckList_1_CheckboxStep(ureq, ores); - StepRunnerCallback finish = new CheckListStepRunnerCallback(ores); + Step start = new CheckList_1_CheckboxStep(ureq, ores, nodeAccessType); + StepRunnerCallback finish = new CheckListStepRunnerCallback(ores, nodeAccessType); checklistWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, translate("checklist.wizard"), "o_sel_checklist_wizard", "Assessment#_checklist_multiple"); listenTo(checklistWizard); diff --git a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties index d02842d723b4bc55f8196871eaa5243f566426d3..9249be4960f14970a6c6629ceafcba84713dfe15 100644 --- a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties @@ -7,6 +7,7 @@ alternative.choose=Alternativen Kursbaustein w\u00E4hlen und konvertieren alternative.choose.description=W\u00E4hlen Sie aus der Liste der m\u00F6glichen alternativen Kursbausteine mit \u00E4hnlicher Funktionalit\u00E4t einen aus um diesen deaktivierten Kursbaustein zu konvertieren. Es werden der Titel und die Beschreibung sowie die Zugangsregeln und alle Kinderelemente \u00FCbernommen. apply=OK assessment=Wissens\u00FCberpr\u00FCfung +bulk.assessment=Bewertung bulk.general=$\:pane.tab.general bulk.learning.path=$org.olat.course.learningpath.ui\:pane.tab.learning.path checkall=Alle ausw\u00E4hlen @@ -385,9 +386,8 @@ header.tools=Editorwerkzeuge - - - +ignore=ignorieren +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment insert.course.element.title=Kursbaustein einf\u00FCgen insert.navigate.prompt.msg=W\u00E4hlen Sie im Baum links die gew\u00FCnschte Position\! insertAtSelectedTreepos=Kursbaustein einf\u00FCgen @@ -484,6 +484,7 @@ table.header.deleted=Gel\u00F6scht table.header.dirty=Unpublizierte \u00C4nderungen table.header.display=$\:nodeConfigForm.display_options table.header.hints=Hinweis +table.header.ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment table.header.individual.documents=$org.olat.course.nodes.ms\:form.individual.assessment.docs table.header.learning.objectives=$\:nodeConfigForm.learningobjectives table.header.long.title=$\:nodeConfigForm.displaytitle diff --git a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_en.properties index 4fa1ff81b026c7f8cd2c511ea5fd5f0a629a7e90..dd5589280c893787687933068e635523d2c9429c 100644 --- a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_en.properties @@ -7,6 +7,7 @@ alternative.choose=Select an alternative course element and convert alternative.choose.description=Select from the list of alternative course elements that offer similar functionality to convert this deactivated course element. The title, description, access rules and all child element will be copied to the converted element. apply=OK assessment=Assessment +bulk.assessment=Assessment bulk.general=$\:pane.tab.general bulk.learning.path=$org.olat.course.learningpath.ui\:pane.tab.learning.path checkall=Select all @@ -385,9 +386,8 @@ header.tools=Editor tools - - - +ignore=ignore +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment insert.course.element.title=Insert course element insert.navigate.prompt.msg=Please select the favored position using the tree diagram on the left\! insertAtSelectedTreepos=Insert course element @@ -483,6 +483,7 @@ table.header.deleted=Deleted table.header.dirty=Unpublished changes table.header.display=$\:nodeConfigForm.display_options table.header.hints=Hint +table.header.ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment table.header.individual.documents=$org.olat.course.nodes.ms\:form.individual.assessment.docs table.header.learning.objectives=$\:nodeConfigForm.learningobjectives table.header.long.title=$\:nodeConfigForm.displaytitle diff --git a/src/main/java/org/olat/course/editor/overview/BulkChangeController.java b/src/main/java/org/olat/course/editor/overview/BulkChangeController.java index 1f404b371f5fd91565b2e99286ba957dfa468ec3..848a64f5ab2a52780f90793b32cca3b42c831b4e 100644 --- a/src/main/java/org/olat/course/editor/overview/BulkChangeController.java +++ b/src/main/java/org/olat/course/editor/overview/BulkChangeController.java @@ -42,11 +42,14 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.course.ICourse; +import org.olat.course.assessment.CourseAssessmentService; +import org.olat.course.assessment.handler.AssessmentConfig; import org.olat.course.editor.EditorMainController; import org.olat.course.learningpath.LearningPathConfigs; import org.olat.course.learningpath.LearningPathService; import org.olat.course.learningpath.manager.LearningPathNodeAccessProvider; import org.olat.course.learningpath.ui.LearningPathNodeConfigController; +import org.olat.course.nodeaccess.NodeAccessService; import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.CourseNode; import org.olat.modules.assessment.model.AssessmentObligation; @@ -70,15 +73,21 @@ public class BulkChangeController extends FormBasicController { CourseNode.DISPLAY_OPTS_CONTENT}; private SingleSelection displayEl; + private MultipleSelectionElement ignoreInCourseAssessmentEl; private TextElement durationEl; private SingleSelection obligationEl; private Map<MultipleSelectionElement, FormLayoutContainer> checkboxContainer = new HashMap<>(); private final List<MultipleSelectionElement> checkboxSwitch = new ArrayList<>(); - + + private final boolean ignoreInCourseAssessmentAvailable; private final boolean learningPath; private final List<CourseNode> courseNodes; - + + @Autowired + private NodeAccessService nodeAccessService; + @Autowired + private CourseAssessmentService courseAssessmentService; @Autowired private LearningPathService learningPathService; @@ -86,6 +95,7 @@ public class BulkChangeController extends FormBasicController { super(ureq, wControl, LAYOUT_VERTICAL); setTranslator(Util.createPackageTranslator(EditorMainController.class, getLocale(), getTranslator())); setTranslator(Util.createPackageTranslator(LearningPathNodeConfigController.class, getLocale(), getTranslator())); + this.ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(NodeAccessType.of(course)); this.learningPath = LearningPathNodeAccessProvider.TYPE.equals(NodeAccessType.of(course).getType()); this.courseNodes = courseNodes; initForm(ureq); @@ -95,6 +105,10 @@ public class BulkChangeController extends FormBasicController { protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { initGeneralForm(formLayout); + if (ignoreInCourseAssessmentAvailable) { + initAssessmentForm(formLayout); + } + if (learningPath) { initLearningPathForm(formLayout); } @@ -127,6 +141,17 @@ public class BulkChangeController extends FormBasicController { decorate(displayEl, generalCont); } + private void initAssessmentForm(FormItemContainer formLayout) { + FormLayoutContainer assessmentCont = FormLayoutContainer.createDefaultFormLayout("assessment", getTranslator()); + assessmentCont.setFormTitle(translate("bulk.assessment")); + assessmentCont.setRootForm(mainForm); + formLayout.add(assessmentCont); + + ignoreInCourseAssessmentEl = uifactory.addCheckboxesHorizontal("ignore.in.course.assessment", assessmentCont, + new String[] { "xx" }, new String[] { translate("ignore") }); + decorate(ignoreInCourseAssessmentEl, assessmentCont); + } + private void initLearningPathForm(FormItemContainer formLayout) { FormLayoutContainer lpCont = FormLayoutContainer.createDefaultFormLayout("learningPath", getTranslator()); lpCont.setFormTitle(translate("bulk.learning.path")); @@ -214,6 +239,9 @@ public class BulkChangeController extends FormBasicController { protected void formOK(UserRequest ureq) { for (CourseNode courseNode : courseNodes) { formOKGeneral(courseNode); + if (ignoreInCourseAssessmentAvailable) { + formOKAssessment(courseNode); + } if (learningPath) { formOKLearningPath(courseNode); } @@ -227,6 +255,14 @@ public class BulkChangeController extends FormBasicController { courseNode.setDisplayOption(displayOption); } } + + private void formOKAssessment(CourseNode courseNode) { + if (isEnabled(ignoreInCourseAssessmentEl)) { + boolean ignoreInCourseAssessment = ignoreInCourseAssessmentEl.isAtLeastSelected(1); + AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); + assessmentConfig.setIgnoreInCourseAssessment(ignoreInCourseAssessment); + } + } private void formOKLearningPath(CourseNode courseNode) { LearningPathConfigs learningPathConfigs = learningPathService.getConfigs(courseNode); diff --git a/src/main/java/org/olat/course/editor/overview/OverviewDataModel.java b/src/main/java/org/olat/course/editor/overview/OverviewDataModel.java index 45f085ec0721d78b634fb41b63dee941da8f9c78..95744d3b7eece0964fa3c07c45a1f9ac7ce369d6 100644 --- a/src/main/java/org/olat/course/editor/overview/OverviewDataModel.java +++ b/src/main/java/org/olat/course/editor/overview/OverviewDataModel.java @@ -26,6 +26,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTreeTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnDef; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; /** * @@ -73,20 +74,23 @@ public class OverviewDataModel extends DefaultFlexiTreeTableDataModel<OverviewRo case end: return row.getEnd(); case trigger: return row.getTranslatedTrigger(); case score: return row.getAssessmentConfig().isAssessable() - ? Boolean.valueOf(row.getAssessmentConfig().hasScore()) + ? Boolean.valueOf(Mode.none != row.getAssessmentConfig().getScoreMode()) : null; - case scoreMin: return row.getAssessmentConfig().isAssessable() && row.getAssessmentConfig().hasScore() + case scoreMin: return row.getAssessmentConfig().isAssessable() && Mode.none != row.getAssessmentConfig().getScoreMode() ? row.getAssessmentConfig().getMinScore() : null; - case scoreMax: return row.getAssessmentConfig().isAssessable() && row.getAssessmentConfig().hasScore() + case scoreMax: return row.getAssessmentConfig().isAssessable() && Mode.none != row.getAssessmentConfig().getScoreMode() ? row.getAssessmentConfig().getMaxScore() : null; case passed: return row.getAssessmentConfig().isAssessable() - ? Boolean.valueOf(row.getAssessmentConfig().hasPassed()) + ? Boolean.valueOf(Mode.none != row.getAssessmentConfig().getPassedMode()) : null; - case passesCut: return row.getAssessmentConfig().isAssessable() && row.getAssessmentConfig().hasPassed() + case passesCut: return row.getAssessmentConfig().isAssessable() && row.getAssessmentConfig().getPassedMode() != Mode.none ? row.getAssessmentConfig().getCutValue() : null; + case ignoreInCourseAssessment: return row.getAssessmentConfig().isAssessable() + ? Boolean.valueOf(row.getAssessmentConfig().ignoreInCourseAssessment()) + : null; case comment: return row.getAssessmentConfig().isAssessable() ? Boolean.valueOf(row.getAssessmentConfig().hasComment()) : null; @@ -122,6 +126,7 @@ public class OverviewDataModel extends DefaultFlexiTreeTableDataModel<OverviewRo scoreMax("table.header.score.max"), passed("table.header.passed"), passesCut("table.header.passed.cut"), + ignoreInCourseAssessment("table.header.ignore.in.course.assessment"), comment("table.header.comment"), individualAsssessmentDocuments("table.header.individual.documents"); diff --git a/src/main/java/org/olat/course/editor/overview/OverviewListController.java b/src/main/java/org/olat/course/editor/overview/OverviewListController.java index f14ffbe0b0ccee9ea3ad8f86b62db994f1dc65cd..f51b32bde37f7c5ae61d7615b8db3a707a81a08e 100644 --- a/src/main/java/org/olat/course/editor/overview/OverviewListController.java +++ b/src/main/java/org/olat/course/editor/overview/OverviewListController.java @@ -64,6 +64,7 @@ import org.olat.course.learningpath.LearningPathService; import org.olat.course.learningpath.LearningPathTranslations; import org.olat.course.learningpath.manager.LearningPathNodeAccessProvider; import org.olat.course.learningpath.ui.LearningPathNodeConfigController; +import org.olat.course.nodeaccess.NodeAccessService; import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.CourseNode; import org.olat.course.tree.CourseEditorTreeNode; @@ -89,11 +90,14 @@ public class OverviewListController extends FormBasicController implements Flexi private final ICourse course; private final boolean learningPath; + private final boolean ignoreInCourseAssessmentAvailable; @Autowired private LearningPathService learningPathService; @Autowired private CourseAssessmentService courseAssessmentService; + @Autowired + private NodeAccessService nodeAccessService; public OverviewListController(UserRequest ureq, WindowControl wControl, ICourse course) { super(ureq, wControl, LAYOUT_BAREBONE); @@ -101,6 +105,7 @@ public class OverviewListController extends FormBasicController implements Flexi setTranslator(Util.createPackageTranslator(LearningPathNodeConfigController.class, getLocale(), getTranslator())); this.course = course; this.learningPath = LearningPathNodeAccessProvider.TYPE.equals(NodeAccessType.of(course).getType()); + this.ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(NodeAccessType.of(course)); initForm(ureq); } @@ -172,6 +177,12 @@ public class OverviewListController extends FormBasicController implements Flexi DefaultFlexiColumnModel passedCutModel = new DefaultFlexiColumnModel(OverviewCols.passesCut); passedCutModel.setDefaultVisible(false); columnsModel.addFlexiColumnModel(passedCutModel); + if (ignoreInCourseAssessmentAvailable ) { + DefaultFlexiColumnModel ignoreInCourseAssessmentModel = new DefaultFlexiColumnModel(OverviewCols.ignoreInCourseAssessment); + ignoreInCourseAssessmentModel.setCellRenderer(new OnOffCellRenderer(getTranslator())); + ignoreInCourseAssessmentModel.setDefaultVisible(false); + columnsModel.addFlexiColumnModel(ignoreInCourseAssessmentModel); + } DefaultFlexiColumnModel commentModel = new DefaultFlexiColumnModel(OverviewCols.comment); commentModel.setCellRenderer(new OnOffCellRenderer(getTranslator())); commentModel.setDefaultVisible(false); diff --git a/src/main/java/org/olat/course/learningpath/LearningPathOnlyAssessmentConfig.java b/src/main/java/org/olat/course/learningpath/LearningPathOnlyAssessmentConfig.java index e4856ecb57037989c8e8b07690729dcfdb632d6b..b076a4c5d72929296fa64cce6c548f1e60fc0598 100644 --- a/src/main/java/org/olat/course/learningpath/LearningPathOnlyAssessmentConfig.java +++ b/src/main/java/org/olat/course/learningpath/LearningPathOnlyAssessmentConfig.java @@ -33,9 +33,9 @@ public class LearningPathOnlyAssessmentConfig implements AssessmentConfig { public boolean isAssessable() { return false; } - + @Override - public boolean isEvaluationPersisted() { + public boolean ignoreInCourseAssessment() { return true; } @@ -45,8 +45,13 @@ public class LearningPathOnlyAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasScore() { - return false; + public void setIgnoreInCourseAssessment(boolean ignoreInCourseAssessment) { + // + } + + @Override + public Mode getScoreMode() { + return Mode.none; } @Override @@ -60,8 +65,8 @@ public class LearningPathOnlyAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasPassed() { - return false; + public Mode getPassedMode() { + return Mode.none; } @Override diff --git a/src/main/java/org/olat/course/learningpath/LearningPathOnlyAssessmentHandler.java b/src/main/java/org/olat/course/learningpath/LearningPathOnlyAssessmentHandler.java index 9f541dd8fac79ef83c8a214659b4c4abce31e912..483b25b16b37a0938da656976492552fe6814e3b 100644 --- a/src/main/java/org/olat/course/learningpath/LearningPathOnlyAssessmentHandler.java +++ b/src/main/java/org/olat/course/learningpath/LearningPathOnlyAssessmentHandler.java @@ -35,8 +35,6 @@ import org.olat.course.learningpath.manager.LearningPathNodeAccessProvider; import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -74,17 +72,6 @@ public abstract class LearningPathOnlyAssessmentHandler implements AssessmentHan return am.getAssessmentEntry(courseNode, assessedIdentity); } - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } - @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, CourseNode courseNode, UserCourseEnvironment coachCourseEnv, diff --git a/src/main/java/org/olat/course/learningpath/manager/LearningPathNodeAccessProvider.java b/src/main/java/org/olat/course/learningpath/manager/LearningPathNodeAccessProvider.java index 5e35fcac389ed6248bb2efb444f1827ca038e2d1..c07853e1437c97f144cde6cdda998519164e0df7 100644 --- a/src/main/java/org/olat/course/learningpath/manager/LearningPathNodeAccessProvider.java +++ b/src/main/java/org/olat/course/learningpath/manager/LearningPathNodeAccessProvider.java @@ -85,6 +85,11 @@ public class LearningPathNodeAccessProvider implements NodeAccessProvider { public boolean isGuestSupported() { return false; } + + @Override + public boolean isScoreCalculatorSupported() { + return false; + } @Override public TabbableController createEditController(UserRequest ureq, WindowControl wControl, CourseNode courseNode, diff --git a/src/main/java/org/olat/course/learningpath/manager/LearningPathServiceImpl.java b/src/main/java/org/olat/course/learningpath/manager/LearningPathServiceImpl.java index ad06aba317fbe30da073124b214b72a68a16f558..ae31be71419d48cb3f9b2b5a5ef69f935fa2424a 100644 --- a/src/main/java/org/olat/course/learningpath/manager/LearningPathServiceImpl.java +++ b/src/main/java/org/olat/course/learningpath/manager/LearningPathServiceImpl.java @@ -115,7 +115,7 @@ public class LearningPathServiceImpl implements LearningPathService { course.getCourseConfig().setNodeAccessType(LearningPathNodeAccessProvider.TYPE); CourseFactory.setCourseConfig(course.getResourceableId(), course.getCourseConfig()); - TreeVisitor tv = new TreeVisitor(new PostMigrationVisitor(registry), course.getEditorTreeModel().getRootNode(), true); + TreeVisitor tv = new TreeVisitor(new PostMigrationVisitor(registry), course.getEditorTreeModel().getRootNode(), false); tv.visitAll(); CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); diff --git a/src/main/java/org/olat/course/nodeaccess/NodeAccessProvider.java b/src/main/java/org/olat/course/nodeaccess/NodeAccessProvider.java index dd38ea9bf57555e2ea2403b9eec6bbdebb3febd8..8fa4abc53293e8d301495a6c2441f385f5016d0e 100644 --- a/src/main/java/org/olat/course/nodeaccess/NodeAccessProvider.java +++ b/src/main/java/org/olat/course/nodeaccess/NodeAccessProvider.java @@ -42,6 +42,8 @@ public interface NodeAccessProvider extends NodeAccessProviderIdentifier { public boolean isSupported(String courseNodeType); public boolean isGuestSupported(); + + public boolean isScoreCalculatorSupported(); public TabbableController createEditController(UserRequest ureq, WindowControl wControl, CourseNode courseNode, UserCourseEnvironment userCourseEnv, CourseEditorTreeModel editorModel); diff --git a/src/main/java/org/olat/course/nodeaccess/NodeAccessService.java b/src/main/java/org/olat/course/nodeaccess/NodeAccessService.java index 058be43fc51b36e95bc88805a0ab08bfd36f076b..fb25477537179dd4ff8db7874927fc4702a7d517 100644 --- a/src/main/java/org/olat/course/nodeaccess/NodeAccessService.java +++ b/src/main/java/org/olat/course/nodeaccess/NodeAccessService.java @@ -55,6 +55,8 @@ public interface NodeAccessService { * @return if this type supports guest access */ public boolean isGuestSupported(NodeAccessType type); + + public boolean isScoreCalculatorSupported(NodeAccessType type); /** * Creates the controller to edit the access configurations of the node. diff --git a/src/main/java/org/olat/course/nodeaccess/manager/NodeAccessServiceImpl.java b/src/main/java/org/olat/course/nodeaccess/manager/NodeAccessServiceImpl.java index bf45a3b3358ee51ef030305ab7d6470311e83697..5b5b25b6b50a9328953629b73caa8dfa8b965281 100644 --- a/src/main/java/org/olat/course/nodeaccess/manager/NodeAccessServiceImpl.java +++ b/src/main/java/org/olat/course/nodeaccess/manager/NodeAccessServiceImpl.java @@ -92,6 +92,11 @@ public class NodeAccessServiceImpl implements NodeAccessService, NodeVisitedList return getNodeAccessProvider(type).isGuestSupported(); } + @Override + public boolean isScoreCalculatorSupported(NodeAccessType type) { + return getNodeAccessProvider(type).isScoreCalculatorSupported(); + } + @Override public TabbableController createEditController(UserRequest ureq, WindowControl wControl, NodeAccessType type, CourseNode courseNode, UserCourseEnvironment userCourseEnv, CourseEditorTreeModel editorModel) { diff --git a/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java b/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java index 7ff88fa2d6568fa9646753b4e0e467e5ffb54f89..3d3e4de677f141aa30da896e04bcdb70ba5d0355 100644 --- a/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java +++ b/src/main/java/org/olat/course/nodes/BasicLTICourseNode.java @@ -42,6 +42,7 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.nodes.INode; import org.olat.course.ICourse; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.editor.ConditionAccessEditConfig; import org.olat.course.editor.CourseEditorEnv; import org.olat.course.editor.NodeEditController; @@ -82,6 +83,7 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode { public static final String CONFIG_KEY_HAS_SCORE_FIELD = MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD; public static final String CONFIG_KEY_HAS_PASSED_FIELD = MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD; public static final String CONFIG_KEY_PASSED_CUT_VALUE = MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE; + public static final String CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT = MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT; public static final String CONFIG_SKIP_LAUNCH_PAGE = "skiplaunchpage"; public static final String CONFIG_SKIP_ACCEPT_LAUNCH_PAGE = "skipacceptlaunchpage"; public static final String CONFIG_HEIGHT = "displayHeight"; @@ -204,7 +206,7 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedScoreConfigError() { - boolean hasScore = new LTIAssessmentConfig(getModuleConfiguration()).hasScore(); + boolean hasScore = Mode.none != new LTIAssessmentConfig(getModuleConfiguration()).getScoreMode(); boolean isScoreTrigger = CoreSpringFactory.getImpl(LTILearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnScore(null, null) @@ -213,7 +215,7 @@ public class BasicLTICourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedPassedConfigError() { - boolean hasPassed = new LTIAssessmentConfig(getModuleConfiguration()).hasPassed(); + boolean hasPassed = new LTIAssessmentConfig(getModuleConfiguration()).getPassedMode() != Mode.none; boolean isPassedTrigger = CoreSpringFactory.getImpl(LTILearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnPassed(null, null) diff --git a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java index 626cb4f40e94825aba27c3788e391cd0951003bc..1a7ddfac05478d99108bf14dc0806541d2145f3a 100644 --- a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java +++ b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java @@ -58,6 +58,7 @@ import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.editor.ConditionAccessEditConfig; import org.olat.course.editor.CourseEditorEnv; import org.olat.course.editor.NodeEditController; @@ -221,7 +222,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedScoreConfigError() { - boolean hasScore = new MSAssessmentConfig(getModuleConfiguration()).hasScore(); + boolean hasScore = Mode.none != new MSAssessmentConfig(getModuleConfiguration()).getScoreMode(); boolean isScoreTrigger = CoreSpringFactory.getImpl(IQTESTLearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnScore(null, null) @@ -230,7 +231,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedPassedConfigError() { - boolean hasPassed = new MSAssessmentConfig(getModuleConfiguration()).hasPassed(); + boolean hasPassed = new MSAssessmentConfig(getModuleConfiguration()).getPassedMode() != Mode.none; boolean isPassedTrigger = CoreSpringFactory.getImpl(IQTESTLearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnPassed(null, null) @@ -472,7 +473,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode { } CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); - ScoreEvaluation currentEval = courseAssessmentService.getPersistedAssessmentEvaluation(this, assessedUserCourseEnv); + ScoreEvaluation currentEval = courseAssessmentService.getAssessmentEvaluation(this, assessedUserCourseEnv); ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), currentEval.getPassed()); courseAssessmentService.saveScoreEvaluation(this, identity, sceval, assessedUserCourseEnv, false, by); } diff --git a/src/main/java/org/olat/course/nodes/GTACourseNode.java b/src/main/java/org/olat/course/nodes/GTACourseNode.java index b0e9acc67dfa1d7fd2e7f51536450224bc9d5583..5de07b968dcaee8cd96500b87aecfce0ce0c8bdb 100644 --- a/src/main/java/org/olat/course/nodes/GTACourseNode.java +++ b/src/main/java/org/olat/course/nodes/GTACourseNode.java @@ -62,6 +62,7 @@ import org.olat.core.util.vfs.filters.VFSSystemItemFilter; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.archiver.ScoreAccountingHelper; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.editor.ConditionAccessEditConfig; import org.olat.course.editor.CourseEditorEnv; import org.olat.course.editor.NodeEditController; @@ -358,7 +359,7 @@ public class GTACourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedScoreConfigError(LearningPathNodeHandler lpNodeHandler) { - boolean hasScore = new GTAAssessmentConfig(getModuleConfiguration()).hasPassed(); + boolean hasScore = new GTAAssessmentConfig(getModuleConfiguration()).getScoreMode() != Mode.none; boolean isScoreTrigger = lpNodeHandler .getConfigs(this) .isFullyAssessedOnScore(null, null) @@ -367,7 +368,7 @@ public class GTACourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedPassedConfigError(LearningPathNodeHandler lpNodeHandler) { - boolean hasPassed = new GTAAssessmentConfig(getModuleConfiguration()).hasPassed(); + boolean hasPassed = new GTAAssessmentConfig(getModuleConfiguration()).getPassedMode() != Mode.none; boolean isPassedTrigger = lpNodeHandler .getConfigs(this) .isFullyAssessedOnPassed(null, null) diff --git a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java index 44776f7af6ec814fb8e88b0133a15cd60aae7b20..805cb80d9d52037636dd7ad62e1a5cf21af18be4 100644 --- a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java +++ b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java @@ -57,6 +57,7 @@ import org.olat.course.ICourse; import org.olat.course.archiver.ScoreAccountingHelper; import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.CourseAssessmentService; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.editor.ConditionAccessEditConfig; import org.olat.course.editor.CourseEditorEnv; import org.olat.course.editor.NodeEditController; @@ -389,7 +390,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements QT } private boolean isFullyAssessedScoreConfigError() { - boolean hasScore = new IQTESTAssessmentConfig(this).hasScore(); + boolean hasScore = Mode.none != new IQTESTAssessmentConfig(this).getScoreMode(); boolean isScoreTrigger = CoreSpringFactory.getImpl(IQTESTLearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnScore(null, null) @@ -398,7 +399,7 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements QT } private boolean isFullyAssessedPassedConfigError() { - boolean hasPassed = new IQTESTAssessmentConfig(this).hasPassed(); + boolean hasPassed = new IQTESTAssessmentConfig(this).getPassedMode() != Mode.none; boolean isPassedTrigger = CoreSpringFactory.getImpl(IQTESTLearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnPassed(null, null) diff --git a/src/main/java/org/olat/course/nodes/MSCourseNode.java b/src/main/java/org/olat/course/nodes/MSCourseNode.java index 1cc6a81b168ea349eb8db50d4a514050221d1371..4a4189e58569de28ff00e5440d9e054635fee314 100644 --- a/src/main/java/org/olat/course/nodes/MSCourseNode.java +++ b/src/main/java/org/olat/course/nodes/MSCourseNode.java @@ -52,6 +52,7 @@ import org.olat.core.util.Util; import org.olat.core.util.nodes.INode; import org.olat.course.ICourse; import org.olat.course.assessment.CourseAssessmentService; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.editor.ConditionAccessEditConfig; import org.olat.course.editor.CourseEditorEnv; import org.olat.course.editor.NodeEditController; @@ -111,6 +112,7 @@ public class MSCourseNode extends AbstractAccessableCourseNode { public static final String CONFIG_KEY_HAS_PASSED_FIELD = "hasPassedField"; /** configuration: passed set to when score higher than cut value */ public static final String CONFIG_KEY_PASSED_CUT_VALUE = "passedCutValue"; + public static final String CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT = "ignoreInCourseAssessment"; /** configuration: comment can be set */ public static final String CONFIG_KEY_HAS_COMMENT_FIELD = "hasCommentField"; /** configuration: individual assessment document can be set (use getBooleanSafe default false) */ @@ -272,7 +274,7 @@ public class MSCourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedScoreConfigError() { - boolean hasScore = new MSAssessmentConfig(getModuleConfiguration()).hasScore(); + boolean hasScore = Mode.none != new MSAssessmentConfig(getModuleConfiguration()).getScoreMode(); boolean isScoreTrigger = CoreSpringFactory.getImpl(MSLearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnScore(null, null) @@ -281,7 +283,7 @@ public class MSCourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedPassedConfigError() { - boolean hasPassed = new MSAssessmentConfig(getModuleConfiguration()).hasPassed(); + boolean hasPassed = new MSAssessmentConfig(getModuleConfiguration()).getPassedMode() != Mode.none; boolean isPassedTrigger = CoreSpringFactory.getImpl(MSLearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnPassed(null, null) @@ -424,7 +426,7 @@ public class MSCourseNode extends AbstractAccessableCourseNode { IdentityEnvironment identityEnv = new IdentityEnvironment(assessedIdentity, null); UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(identityEnv, course.getCourseEnvironment()); - ScoreEvaluation currentEval = courseAssessmentService.getPersistedAssessmentEvaluation(this, userCourseEnv); + ScoreEvaluation currentEval = courseAssessmentService.getAssessmentEvaluation(this, userCourseEnv); Float currentScore = currentEval.getScore(); Boolean currentPassed = currentEval.getPassed(); @@ -465,7 +467,7 @@ public class MSCourseNode extends AbstractAccessableCourseNode { } if (score == null) { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); - ScoreEvaluation currentEval = courseAssessmentService.getPersistedAssessmentEvaluation(this, assessedUserCourseEnv); + ScoreEvaluation currentEval = courseAssessmentService.getAssessmentEvaluation(this, assessedUserCourseEnv); score = currentEval.getScore(); } @@ -491,7 +493,7 @@ public class MSCourseNode extends AbstractAccessableCourseNode { passed = Boolean.valueOf(aboveCutValue); } else { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); - ScoreEvaluation currentEval = courseAssessmentService.getPersistedAssessmentEvaluation(this, assessedUserCourseEnv); + ScoreEvaluation currentEval = courseAssessmentService.getAssessmentEvaluation(this, assessedUserCourseEnv); passed = currentEval.getPassed(); } return passed; diff --git a/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java b/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java index 4070b56f15930e5bb9328f0d40ac78227d22350b..e2fbdd338e6817d9c6c78b65667bbfe01d8be111 100644 --- a/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java +++ b/src/main/java/org/olat/course/nodes/PortfolioCourseNode.java @@ -136,7 +136,7 @@ public class PortfolioCourseNode extends AbstractAccessableCourseNode { @Override public TabbableController createEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, ICourse course, UserCourseEnvironment euce) { PortfolioCourseNodeEditController childTabCntrllr = new PortfolioCourseNodeEditController(ureq, wControl, stackPanel, - course, this, getModuleConfiguration(), euce); + course, this, getModuleConfiguration()); CourseNode chosenNode = course.getEditorTreeModel().getCourseNode(euce.getCourseEditorEnv().getCurrentCourseNodeId()); return new NodeEditController(ureq, wControl, course, chosenNode, euce, childTabCntrllr); } diff --git a/src/main/java/org/olat/course/nodes/STCourseNode.java b/src/main/java/org/olat/course/nodes/STCourseNode.java index 71c59e6443a19efadea15bddc8c1bb413894454f..464214314ece8de21e980300606b38e3f65c68ff 100644 --- a/src/main/java/org/olat/course/nodes/STCourseNode.java +++ b/src/main/java/org/olat/course/nodes/STCourseNode.java @@ -109,7 +109,18 @@ public class STCourseNode extends AbstractAccessableCourseNode { public static final String CONFIG_LP_SEQUENCE_VALUE_SEQUENTIAL = "learning.path.sequence.sequential"; public static final String CONFIG_LP_SEQUENCE_VALUE_WITHOUT = "learning.path.sequence.without"; public static final String CONFIG_LP_SEQUENCE_DEFAULT = CONFIG_LP_SEQUENCE_VALUE_SEQUENTIAL; + + // Score calculation without conditions. + public static final String CONFIG_SCORE_KEY = "score.key"; + public static final String CONFIG_SCORE_VALUE_SUM = "score.sum"; + public static final String CONFIG_SCORE_VALUE_AVG = "score.avg"; + public static final String CONFIG_PASSED_PROGRESS = "passed.progress"; + public static final String CONFIG_PASSED_ALL = "passed.all"; + public static final String CONFIG_PASSED_POINTS = "passed.points"; + public static final String CONFIG_PASSED_POINTS_CUT = "passed.points.cut"; + // Score calculation with conditions. + public static final String CONFIG_SCORE_CALCULATOR_SUPPORTED = "score.calculator.supported"; private ScoreCalculator scoreCalculator; transient private Condition scoreExpression; transient private Condition passedExpression; @@ -364,8 +375,16 @@ public class STCourseNode extends AbstractAccessableCourseNode { config.setConfigurationVersion(3); - scoreCalculator = new ScoreCalculator(); - scoreCalculator.setFailedType(FailedEvaluationType.failedAsNotPassedAfterEndDate); + STCourseNode stParent = getFirstSTParent(parent); + if (stParent != null) { + boolean scoreCalculatorSupported = stParent.getModuleConfiguration().getBooleanSafe(CONFIG_SCORE_CALCULATOR_SUPPORTED); + config.setBooleanEntry(CONFIG_SCORE_CALCULATOR_SUPPORTED, scoreCalculatorSupported); + if (scoreCalculatorSupported) { + scoreCalculator = new ScoreCalculator(); + scoreCalculator.setFailedType(FailedEvaluationType.failedAsNotPassedAfterEndDate); + } + } // else: is course root and initialized in CreateCourseRepositoryEntryController / REST + } else { // update to version 2 if (config.getConfigurationVersion() < 2) { diff --git a/src/main/java/org/olat/course/nodes/ScormCourseNode.java b/src/main/java/org/olat/course/nodes/ScormCourseNode.java index ae97f85dd537b437a9023942aef5fb4a1dbbcf87..a7c0b07a14b73582125474076538815149557ea6 100644 --- a/src/main/java/org/olat/course/nodes/ScormCourseNode.java +++ b/src/main/java/org/olat/course/nodes/ScormCourseNode.java @@ -53,6 +53,7 @@ import org.olat.core.util.Util; import org.olat.core.util.ZipUtil; import org.olat.core.util.nodes.INode; import org.olat.course.ICourse; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.editor.ConditionAccessEditConfig; import org.olat.course.editor.CourseEditorEnv; import org.olat.course.editor.NodeEditController; @@ -180,7 +181,7 @@ public class ScormCourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedScoreConfigError() { - boolean hasScore = new ScormAssessmentConfig(getModuleConfiguration()).hasScore(); + boolean hasScore = Mode.none != new ScormAssessmentConfig(getModuleConfiguration()).getScoreMode(); boolean isScoreTrigger = CoreSpringFactory.getImpl(ScormLearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnScore(null, null) @@ -189,7 +190,7 @@ public class ScormCourseNode extends AbstractAccessableCourseNode { } private boolean isFullyAssessedPassedConfigError() { - boolean hasPassed = new ScormAssessmentConfig(getModuleConfiguration()).hasPassed(); + boolean hasPassed = new ScormAssessmentConfig(getModuleConfiguration()).getPassedMode() != Mode.none; boolean isPassedTrigger = CoreSpringFactory.getImpl(ScormLearningPathNodeHandler.class) .getConfigs(this) .isFullyAssessedOnPassed(null, null) diff --git a/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java b/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java index dc476c0e08b65150d2d8ffd1a39a882adc3836ab..7340f988741245b4be8f893b1b9d7ee4403a7a08 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java +++ b/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java @@ -36,6 +36,7 @@ import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.BasicLTICourseNode; import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.ScoreEvaluation; @@ -165,7 +166,7 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper { private float getScalingFactor(CourseNode node) { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(node); - if(assessmentConfig.hasScore()) { + if(Mode.none != assessmentConfig.getScoreMode()) { Float scale = node.getModuleConfiguration().getFloatEntry(BasicLTICourseNode.CONFIG_KEY_SCALEVALUE); if(scale == null) { return 1.0f; @@ -176,7 +177,7 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper { } private Float getCutValue(AssessmentConfig assessmentConfig) { - if(assessmentConfig.hasPassed()) { + if(Mode.setByNode == assessmentConfig.getPassedMode()) { Float cutValue = assessmentConfig.getCutValue(); if(cutValue == null) { return null; diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentConfig.java b/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentConfig.java index d5797a29add3f5fdd9129a64c5b217d7bf266e2a..34b8c0e4ce4b75c38cd2de308c106c6e22b39638 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentConfig.java +++ b/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentConfig.java @@ -45,8 +45,13 @@ public class LTIAssessmentConfig implements AssessmentConfig { } @Override - public boolean isEvaluationPersisted() { - return true; + public boolean ignoreInCourseAssessment() { + return config.getBooleanSafe(BasicLTICourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + } + + @Override + public void setIgnoreInCourseAssessment(boolean ignoreInCourseAssessment) { + config.setBooleanEntry(BasicLTICourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); } @Override @@ -55,13 +60,13 @@ public class LTIAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasScore() { - return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD); + public Mode getScoreMode() { + return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD)? Mode.setByNode: Mode.none; } @Override public Float getMaxScore() { - if (!hasScore()) { + if (Mode.none == getScoreMode()) { throw new OLATRuntimeException(LTIAssessmentConfig.class, "getMaxScore not defined when hasScoreConfigured set to false", null); } @@ -74,20 +79,20 @@ public class LTIAssessmentConfig implements AssessmentConfig { @Override public Float getMinScore() { - if (!hasScore()) { + if (Mode.none == getScoreMode()) { throw new OLATRuntimeException(LTIAssessmentConfig.class, "getMaxScore not defined when hasScoreConfigured set to false", null); } return 0.0f; } @Override - public boolean hasPassed() { - return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD); + public Mode getPassedMode() { + return config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD)? Mode.setByNode: Mode.none; } @Override public Float getCutValue() { - if (!hasPassed()) { + if (Mode.none != getPassedMode()) { throw new OLATRuntimeException(LTIAssessmentConfig.class, "getCutValue not defined when hasPassedConfigured set to false", null); } return config.getFloatEntry(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE); diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentHandler.java b/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentHandler.java index 3d2469a19e74fb44097c96c12ae7a9d24ecfec9d..338aff5d5a6dd6d4e76faebe9e180110ee656ae0 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/basiclti/LTIAssessmentHandler.java @@ -36,8 +36,6 @@ import org.olat.course.nodes.BasicLTICourseNode; import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.ims.lti.ui.LTIResultDetailsController; @@ -81,17 +79,6 @@ public class LTIAssessmentHandler implements AssessmentHandler { } return AccountingEvaluatorsBuilder.defaultConventional(); } - - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIConfigForm.java b/src/main/java/org/olat/course/nodes/basiclti/LTIConfigForm.java index 809123ad2cad8af55c9a76e08a49822ba62a6383..cbf32ad2a25335eae842ec7ccb2f72134b9b7148 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/LTIConfigForm.java +++ b/src/main/java/org/olat/course/nodes/basiclti/LTIConfigForm.java @@ -52,7 +52,10 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.BasicLTICourseNode; +import org.olat.course.nodes.MSCourseNode; import org.olat.ims.lti.LTIDisplayOptions; import org.olat.ims.lti.LTIManager; import org.olat.ims.lti.LTIModule; @@ -99,6 +102,7 @@ public class LTIConfigForm extends FormBasicController { private TextElement scaleFactorEl; private TextElement cutValueEl; + private MultipleSelectionElement ignoreInCourseAssessmentEl; private MultipleSelectionElement isAssessableEl; private MultipleSelectionElement authorRoleEl; private MultipleSelectionElement coachRoleEl; @@ -112,6 +116,7 @@ public class LTIConfigForm extends FormBasicController { private Boolean sendNameConfig; private Boolean sendEmailConfig; private Boolean doDebugConfig; + private final boolean ignoreInCourseAssessmentAvailable; private boolean isAssessable; private String key; private String pass; @@ -156,17 +161,21 @@ public class LTIConfigForm extends FormBasicController { private LTIModule ltiModule; @Autowired private UserManager userManager; + @Autowired + private NodeAccessService nodeAccessService; /** * Constructor for the tunneling configuration form * @param name * @param config + * @param nodeAccessType * @param withCancel */ - public LTIConfigForm(UserRequest ureq, WindowControl wControl, ModuleConfiguration config) { + public LTIConfigForm(UserRequest ureq, WindowControl wControl, ModuleConfiguration config, NodeAccessType nodeAccessType) { super(ureq, wControl); this.config = config; int configVersion = config.getConfigurationVersion(); + this.ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(nodeAccessType); Translator userPropsTranslator = userManager.getPropertyHandlerTranslator(getTranslator()); @@ -348,6 +357,12 @@ public class LTIConfigForm extends FormBasicController { cutValueEl.setDisplaySize(3); cutValueEl.setVisible(isAssessable); + ignoreInCourseAssessmentEl = uifactory.addCheckboxesHorizontal("ignore.in.course.assessment", formLayout, + new String[] { "xx" }, new String[] { null }); + boolean ignoreInCourseAssessment = config.getBooleanSafe(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + ignoreInCourseAssessmentEl.select(ignoreInCourseAssessmentEl.getKey(0), ignoreInCourseAssessment); + ignoreInCourseAssessmentEl.setVisible(ignoreInCourseAssessmentAvailable && isAssessable); + uifactory.addSpacerElement("display", formLayout, false); String display = config.getStringValue(BasicLTICourseNode.CONFIG_DISPLAY, "iframe"); @@ -547,6 +562,7 @@ public class LTIConfigForm extends FormBasicController { boolean assessEnabled = isAssessableEl.isAtLeastSelected(1); scaleFactorEl.setVisible(assessEnabled); cutValueEl.setVisible(assessEnabled); + ignoreInCourseAssessmentEl.setVisible(ignoreInCourseAssessmentAvailable && assessEnabled); flc.setDirty(true); } else if (sendName == source || sendEmail == source) { boolean sendEnabled = sendName.isSelected(0) || sendEmail.isSelected(0); @@ -658,6 +674,9 @@ public class LTIConfigForm extends FormBasicController { config.setBooleanEntry(BasicLTICourseNode.CONFIG_KEY_HAS_PASSED_FIELD, Boolean.FALSE); config.remove(BasicLTICourseNode.CONFIG_KEY_PASSED_CUT_VALUE); } + + boolean ignoreInCourseAssessment = ignoreInCourseAssessmentEl.isVisible() && ignoreInCourseAssessmentEl.isAtLeastSelected(1); + config.setBooleanEntry(BasicLTICourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); } else { config.setBooleanEntry(BasicLTICourseNode.CONFIG_KEY_HAS_SCORE_FIELD, Boolean.FALSE); config.setBooleanEntry(BasicLTICourseNode.CONFIG_KEY_HAS_PASSED_FIELD, Boolean.FALSE); diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIEditController.java b/src/main/java/org/olat/course/nodes/basiclti/LTIEditController.java index 8cb346ae961a85e4ddda1c2a0c9788c45247978c..1e1d40727ae20951c848b22897e55e69d2b8c285 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/LTIEditController.java +++ b/src/main/java/org/olat/course/nodes/basiclti/LTIEditController.java @@ -40,6 +40,7 @@ import org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultCon import org.olat.course.ICourse; import org.olat.course.editor.NodeEditController; import org.olat.course.highscore.ui.HighScoreEditController; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.BasicLTICourseNode; import org.olat.course.nodes.MSCourseNode; import org.olat.course.run.environment.CourseEnvironment; @@ -98,7 +99,7 @@ public class LTIEditController extends ActivateableTabbableDefaultController imp highScoreNodeConfigController = new HighScoreEditController(ureq, wControl, config); listenTo(highScoreNodeConfigController); - ltConfigForm = new LTIConfigForm(ureq, wControl, config); + ltConfigForm = new LTIConfigForm(ureq, wControl, config, NodeAccessType.of(course)); listenTo(ltConfigForm); myContent.put("ltConfigForm", ltConfigForm.getInitialComponent()); diff --git a/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_de.properties index d01001fad611e4be8e26e326d91a074b93c9dafc..d8ec95c4821ae156c775a958cbea23f592678c31 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_de.properties @@ -34,6 +34,7 @@ display.config.skipAcceptLaunchPage=Zustimmung "Daten\u00FCbertragung" unterdr\u display.config.skipAcceptLaunchPageConfirm=Es werden pers\u00F6nliche Daten der Benutzer an einen externen Server \u00FCbermittelt. Wenn diese Option aktiviert ist, k\u00F6nnen die Benutzer diese Daten\u00FCbertragung nicht akzeptiern oder ablehnen. Wollen Sie die Option aktivieren? display.config.skipAcceptLaunchPageWarning=Es werden pers\u00F6nliche Daten der Benutzer an einen externen Server \u00FCbermittelt. Wenn diese Option aktiviert ist, k\u00F6nnen die Benutzer diese Daten\u00FCbertragung nicht akzeptiern oder ablehnen. display.config.skipLaunchPage=Inhalt automatisch starten +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment add=+ remove=- height.auto=$org.olat.core.gui.control.generic.iframe\:height.auto diff --git a/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_en.properties index 2f992da54b07144ce96996d87a79347496f5432f..cb135fbbc818b86ef1bf66854995f951f8af3a78 100644 --- a/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/basiclti/_i18n/LocalStrings_en.properties @@ -42,6 +42,7 @@ error.hostmissing.short=No host indicated for "{0}". form.error.wrongFloat=$org.olat.course.assessment\:form.error.wrongFloat form.title=Configuration of LTI page height.auto=$org.olat.core.gui.control.generic.iframe\:height.auto +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment pane.tab.highscore=HighScore pane.tab.ltconfig=Page content participant.roles=Participant diff --git a/src/main/java/org/olat/course/nodes/cl/CheckListAssessmentHandler.java b/src/main/java/org/olat/course/nodes/cl/CheckListAssessmentHandler.java index ec36598d17b32d9af498201229a648fea22c2100..79d2f68d26d3751aeb1168278b43975503a03fdf 100644 --- a/src/main/java/org/olat/course/nodes/cl/CheckListAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/cl/CheckListAssessmentHandler.java @@ -39,8 +39,6 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.cl.ui.AssessedIdentityCheckListController; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -82,17 +80,6 @@ public class CheckListAssessmentHandler implements AssessmentHandler { } return AccountingEvaluatorsBuilder.defaultConventional(); } - - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListConfigurationController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListConfigurationController.java index 7f018e8a03a5c031e8ca754f85e290c3f1a57ae9..039b6e1def3a02ccb1d79a3c1d4d0fc3c0de9706 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListConfigurationController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListConfigurationController.java @@ -28,6 +28,7 @@ import org.olat.core.gui.components.form.flexible.elements.DateChooser; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.SpacerElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; @@ -37,12 +38,15 @@ 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.util.StringHelper; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.CheckListCourseNode; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.MSCourseNode; import org.olat.course.nodes.cl.model.CheckboxList; import org.olat.course.nodes.cl.ui.wizard.GeneratorData; import org.olat.modules.ModuleConfiguration; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -60,29 +64,38 @@ public class CheckListConfigurationController extends FormBasicController { private TextElement minPointsEl, maxPointsEl, cutValueEl, titlePrefixEl; private RichTextElement tipUserEl, tipCoachEl; private DateChooser dueDateChooserEl; + private MultipleSelectionElement ignoreInCourseAssessmentEl; + private SpacerElement ignoreInCourseAssessmentSpacer; private final ModuleConfiguration config; private final boolean inUse; private final boolean wizard; + private final boolean ignoreInCourseAssessmentAvailable; private GeneratorData data; private static final String[] numOfKeys = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" }; - public CheckListConfigurationController(UserRequest ureq, WindowControl wControl, CourseNode courseNode, boolean inUse) { + @Autowired + private NodeAccessService nodeAccessService; + + public CheckListConfigurationController(UserRequest ureq, WindowControl wControl, CourseNode courseNode, + NodeAccessType nodeAccessType, boolean inUse) { super(ureq, wControl); wizard = false; this.inUse = inUse; config = courseNode.getModuleConfiguration(); + this.ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(nodeAccessType); initForm(ureq); } public CheckListConfigurationController(UserRequest ureq, WindowControl wControl, ModuleConfiguration config, - GeneratorData data, Form rootForm) { + NodeAccessType nodeAccessType, GeneratorData data, Form rootForm) { super(ureq, wControl, LAYOUT_DEFAULT, null, rootForm); wizard = true; inUse = false; this.data = data; this.config = config; + this.ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(nodeAccessType); initForm(ureq); } @@ -144,7 +157,6 @@ public class CheckListConfigurationController extends FormBasicController { maxPointsEl = uifactory.addTextElement("pointsmax", "config.points.max", 4, maxValStr, formLayout); maxPointsEl.setMandatory(true); maxPointsEl.setDisplaySize(5); - updateScoreVisibility(); uifactory.addSpacerElement("spacer-points", formLayout, false); @@ -189,9 +201,16 @@ public class CheckListConfigurationController extends FormBasicController { if((cutVal != null && cutVal.floatValue() > -0.1) || !outputEl.isOneSelected()) { outputEl.select(outputKeys[0], true); } - updatePassedAndOutputVisibilty(); uifactory.addSpacerElement("spacer-passed", formLayout, false); + + // course assesment + ignoreInCourseAssessmentEl = uifactory.addCheckboxesHorizontal("ignore.in.course.assessment", formLayout, + new String[] { "xx" }, new String[] { null }); + boolean ignoreInCourseAssessment = config.getBooleanSafe(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + ignoreInCourseAssessmentEl.select(ignoreInCourseAssessmentEl.getKey(0), ignoreInCourseAssessment); + + ignoreInCourseAssessmentSpacer = uifactory.addSpacerElement("spacer3", formLayout, false); //comment commentEl = uifactory.addCheckboxesHorizontal("comment", "config.comment", formLayout, onKeys, theValues); @@ -221,6 +240,9 @@ public class CheckListConfigurationController extends FormBasicController { formLayout.add(buttonsLayout); uifactory.addFormSubmitButton("submit", "submit", buttonsLayout); } + + updateScoreVisibility(); + updatePassedAndOutputVisibilty(); } @Override @@ -276,6 +298,10 @@ public class CheckListConfigurationController extends FormBasicController { config.set(CheckListCourseNode.CONFIG_KEY_PASSED_MANUAL_CORRECTION, Boolean.TRUE); } } + + // course assessment + boolean ignoreInCourseAssessment = ignoreInCourseAssessmentEl.isVisible() && ignoreInCourseAssessmentEl.isAtLeastSelected(1); + config.setBooleanEntry(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); // mandatory comment flag config.set(MSCourseNode.CONFIG_KEY_HAS_COMMENT_FIELD, Boolean.valueOf(commentEl.isSelected(0))); @@ -432,6 +458,7 @@ public class CheckListConfigurationController extends FormBasicController { minPointsEl.setMandatory(granted); maxPointsEl.setVisible(granted); maxPointsEl.setMandatory(granted); + updateIgnoreInCourseAssessmentVisibility(); } private void updatePassedAndOutputVisibilty() { @@ -453,5 +480,14 @@ public class CheckListConfigurationController extends FormBasicController { cutValueEl.setVisible(false); sumCheckboxEl.setVisible(false); } + updateIgnoreInCourseAssessmentVisibility(); } + + private void updateIgnoreInCourseAssessmentVisibility() { + boolean ignoreInScoreVisible = ignoreInCourseAssessmentAvailable + && (scoreGrantedEl.isSelected(0) || passedEl.isSelected(0)); + ignoreInCourseAssessmentEl.setVisible(ignoreInScoreVisible); + ignoreInCourseAssessmentSpacer.setVisible(ignoreInScoreVisible); + } + } \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListEditController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListEditController.java index 39d3c171cccce1d1c498f47dffbcae144a5a944e..f838d58bbb028a61839c14d8925b309168b426ff 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListEditController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListEditController.java @@ -31,6 +31,7 @@ import org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultCon import org.olat.course.ICourse; import org.olat.course.editor.NodeEditController; import org.olat.course.highscore.ui.HighScoreEditController; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.CheckListCourseNode; import org.olat.course.nodes.MSCourseNode; import org.olat.course.nodes.cl.CheckboxManager; @@ -66,7 +67,8 @@ public class CheckListEditController extends ActivateableTabbableDefaultControll checkboxListEditCtrl = new CheckListBoxListEditController(ureq, wControl, course, courseNode, numOfChecks > 0); listenTo(checkboxListEditCtrl); - configurationCtrl = new CheckListConfigurationController(ureq, wControl, courseNode, numOfChecks > 0); + configurationCtrl = new CheckListConfigurationController(ureq, wControl, courseNode, NodeAccessType.of(course), + numOfChecks > 0); listenTo(configurationCtrl); highScoreNodeConfigController = new HighScoreEditController(ureq, wControl, courseNode.getModuleConfiguration()); diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListExcelExport.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListExcelExport.java index 108ad9aaf6e505da78f637d298a36f514abf2da0..838335d5d8a84f3b72372874c53d11e45a44a03c 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListExcelExport.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListExcelExport.java @@ -47,6 +47,7 @@ import org.olat.core.util.openxml.workbookstyle.CellStyle; import org.olat.course.ICourse; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CheckListCourseNode; import org.olat.course.nodes.cl.CheckboxManager; import org.olat.course.nodes.cl.model.AssessmentData; @@ -88,8 +89,8 @@ public class CheckListExcelExport { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - this.hasScore = assessmentConfig.hasScore(); - this.hasPassed = assessmentConfig.hasPassed(); + this.hasScore = Mode.none != assessmentConfig.getScoreMode(); + this.hasPassed = Mode.none != assessmentConfig.getPassedMode(); userManager = CoreSpringFactory.getImpl(UserManager.class); checkboxManager = CoreSpringFactory.getImpl(CheckboxManager.class); diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java index cddafe7fe7edf615d833d72fedd6d6bce037a643..2e41a9a7f77507ebe205638acafdb16c93c5c1e3 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java @@ -57,6 +57,7 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.highscore.ui.HighScoreRunController; import org.olat.course.nodes.CheckListCourseNode; @@ -344,7 +345,7 @@ public class CheckListRunController extends FormBasicController implements Contr exposeUserDataToVC(ureq, flc); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - return assessmentConfig.hasScore() || assessmentConfig.hasPassed(); + return Mode.none != assessmentConfig.getScoreMode() || Mode.none != assessmentConfig.getPassedMode(); } private void logUpdateCheck(String checkboxId, String boxTitle) { diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties index 846c41d4ddd87ae2d5cc47082c79c86241421b29..66b40fe5887efb3114ef911987c6e81a6cdfcaa1 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties @@ -59,6 +59,7 @@ form.error.date=Es muss ein Datum angegeben werden. form.error.scoreOutOfRange=$org.olat.course.assessment\:form.error.scoreOutOfRange form.error.wrongFloat=$org.olat.course.nodes.ms\:form.error.wrongFloat fully.assessed.trigger.status.done=Status durch Betreuer auf "erledigt" gesetzt. +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment info.title=$org.olat.course.nodes.ms\:info.title label=Beschriftung label.achieved=Erreicht diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties index 20135a3147236f4b705278f5e403d1ffa3491d73..0aa82cc10843dab813f2c63e5357057fcc12142f 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties @@ -59,6 +59,7 @@ form.error.date=A date must be indicated. form.error.scoreOutOfRange=$org.olat.course.assessment\:form.error.scoreOutOfRange form.error.wrongFloat=$org.olat.course.nodes.ms\:form.error.wrongFloat form.individual.assessment.docs=$org.olat.course.nodes.ms\:form.individual.assessment.docs +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment info.title=$org.olat.course.nodes.ms\:info.title label=Label label.achieved=Achieved diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListConfigurationStepController.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListConfigurationStepController.java index 103d835ce293c99c1c5b52c28315ad6ab976621b..ff8bfefe66b1c20acfc81ef5a164fce5fe0e58d1 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListConfigurationStepController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListConfigurationStepController.java @@ -28,6 +28,7 @@ import org.olat.core.gui.control.generic.wizard.StepFormBasicController; import org.olat.core.gui.control.generic.wizard.StepsEvent; import org.olat.core.gui.control.generic.wizard.StepsRunContext; import org.olat.core.util.Util; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.cl.ui.CheckListConfigurationController; import org.olat.course.nodes.cl.ui.CheckListEditController; import org.olat.modules.ModuleConfiguration; @@ -43,13 +44,15 @@ public class CheckListConfigurationStepController extends StepFormBasicControlle private final GeneratorData data; private final CheckListConfigurationController configController; - public CheckListConfigurationStepController(UserRequest ureq, WindowControl wControl, Form rootForm, StepsRunContext runContext) { + public CheckListConfigurationStepController(UserRequest ureq, WindowControl wControl, Form rootForm, + StepsRunContext runContext) { super(ureq, wControl, rootForm, runContext, LAYOUT_CUSTOM, "checklist_config"); setTranslator(Util.createPackageTranslator(CheckListEditController.class, getLocale(), getTranslator())); data = (GeneratorData)getFromRunContext("data"); + NodeAccessType nodeAccessType = (NodeAccessType)getFromRunContext("nodeAccessType"); ModuleConfiguration config = data.getModuleConfiguration(); - configController = new CheckListConfigurationController(ureq, wControl, config, data, rootForm); + configController = new CheckListConfigurationController(ureq, wControl, config, nodeAccessType, data, rootForm); listenTo(configController); initForm(ureq); diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListStepRunnerCallback.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListStepRunnerCallback.java index 528b1fa9c93b2a20995c9ca87ea15cae133257d6..0c300a2410fa55888ac175c7e41ae5abc7bcf47a 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListStepRunnerCallback.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListStepRunnerCallback.java @@ -45,6 +45,8 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSManager; import org.olat.course.CourseFactory; import org.olat.course.ICourse; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.CheckListCourseNode; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNodeConfiguration; @@ -69,9 +71,12 @@ public class CheckListStepRunnerCallback implements StepRunnerCallback { private static final Logger log = Tracing.createLoggerFor(CheckListStepRunnerCallback.class); private final OLATResourceable courseOres; + private final boolean scoreCalculatorSupported; - public CheckListStepRunnerCallback(OLATResourceable courseOres) { + public CheckListStepRunnerCallback(OLATResourceable courseOres, NodeAccessType nodeAccessType) { this.courseOres = OresHelper.clone(courseOres); + NodeAccessService nodeAccessService = CoreSpringFactory.getImpl(NodeAccessService.class); + scoreCalculatorSupported = nodeAccessService.isScoreCalculatorSupported(nodeAccessType); } @Override @@ -139,7 +144,9 @@ public class CheckListStepRunnerCallback implements StepRunnerCallback { } } - setScoreCalculation(data, (STCourseNode)structureNode, nodesIdent); + if (scoreCalculatorSupported) { + setScoreCalculation(data, (STCourseNode)structureNode, nodesIdent); + } return StepsMainRunController.DONE_MODIFIED; } diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckList_1_CheckboxStep.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckList_1_CheckboxStep.java index 21b40d0dd0af2d44f11afdbdf5a19fcaebdcb229..2924dfeac00e946b497af709a486388d954dd228 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckList_1_CheckboxStep.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckList_1_CheckboxStep.java @@ -28,6 +28,7 @@ import org.olat.core.gui.control.generic.wizard.StepFormController; import org.olat.core.gui.control.generic.wizard.StepsRunContext; import org.olat.core.id.OLATResourceable; import org.olat.core.util.resource.OresHelper; +import org.olat.course.nodeaccess.NodeAccessType; /** * @@ -38,9 +39,11 @@ import org.olat.core.util.resource.OresHelper; public class CheckList_1_CheckboxStep extends BasicStep { private final OLATResourceable courseOres; + private final NodeAccessType nodeAccessType; - public CheckList_1_CheckboxStep(UserRequest ureq, OLATResourceable courseOres) { + public CheckList_1_CheckboxStep(UserRequest ureq, OLATResourceable courseOres, NodeAccessType nodeAccessType) { super(ureq); + this.nodeAccessType = nodeAccessType; this.courseOres = OresHelper.clone(courseOres); setNextStep(new CheckList_2_ConfigurationStep(ureq)); setI18nTitleAndDescr("checkbox.template", "checkbox.template"); @@ -56,6 +59,9 @@ public class CheckList_1_CheckboxStep extends BasicStep { if(!runContext.containsKey("data")) { runContext.put("data", new GeneratorData()); } + if(!runContext.containsKey("nodeAccessType")) { + runContext.put("nodeAccessType", nodeAccessType); + } return new CheckboxListStepController(ureq, wControl, form, runContext, courseOres); } } diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/StructureNodeStepController.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/StructureNodeStepController.java index 4095296298a8288d556f69c832d3751a656458ca..9d96b9951c51da49728b75075ba92c93b1761b80 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/StructureNodeStepController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/StructureNodeStepController.java @@ -25,6 +25,7 @@ import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.SpacerElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormEvent; @@ -36,7 +37,10 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.course.editor.NodeConfigFormController; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.cl.ui.CheckListEditController; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -53,13 +57,20 @@ public class StructureNodeStepController extends StepFormBasicController { private RichTextElement objectivesEl; private TextElement shortTitleEl, titleEl, cutValueEl; private MultipleSelectionElement pointsEl, passedEl; + private SpacerElement spacer; private final GeneratorData data; + private final boolean scoreCalculatorSupported; + + @Autowired + private NodeAccessService nodeAccessService; public StructureNodeStepController(UserRequest ureq, WindowControl wControl, Form rootForm, StepsRunContext runContext) { super(ureq, wControl, rootForm, runContext, LAYOUT_DEFAULT, null); setTranslator(Util.createPackageTranslator(CheckListEditController.class, getLocale(), getTranslator())); data = (GeneratorData)getFromRunContext("data"); + NodeAccessType nodeAccessType = (NodeAccessType)getFromRunContext("nodeAccessType"); + scoreCalculatorSupported = nodeAccessService.isScoreCalculatorSupported(nodeAccessType); initForm(ureq); } @@ -79,7 +90,7 @@ public class StructureNodeStepController extends StepFormBasicController { objectivesEl = uifactory.addRichTextElementForStringData("nodeConfigForm.learningobjectives", "nodeConfigForm.learningobjectives", null, 10, -1, false, null, null, formLayout, ureq.getUserSession(), getWindowControl()); objectivesEl.setMaxLength(4000); - uifactory.addSpacerElement("spaceman", formLayout, false); + spacer = uifactory.addSpacerElement("spaceman", formLayout, false); String[] pointValues = new String[]{ translate("points.sum.checklists") }; pointsEl = uifactory.addCheckboxesHorizontal("points", formLayout, onKeys, pointValues); @@ -99,6 +110,8 @@ public class StructureNodeStepController extends StepFormBasicController { cutValueEl = uifactory.addTextElement("cutvalue", "config.cutvalue", 4, null, formLayout); cutValueEl.setDisplaySize(5); cutValueEl.setVisible(false); + + updatePassedAndOutputUI(); } @Override @@ -139,31 +152,40 @@ public class StructureNodeStepController extends StepFormBasicController { @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(passedEl == source) { - boolean selected = passedEl.isAtLeastSelected(1); - cutValueEl.setVisible(selected); - outputEl.setVisible(selected); - if(selected) { - boolean cutValueSelected = outputEl.isSelected(0); - cutValueEl.setVisible(cutValueSelected); - } + updatePassedAndOutputUI(); } else if(outputEl == source) { - boolean cutValueSelected = outputEl.isSelected(0); - cutValueEl.setVisible(cutValueSelected); + updatePassedAndOutputUI(); } super.formInnerEvent(ureq, source, event); } + private void updatePassedAndOutputUI() { + spacer.setVisible(scoreCalculatorSupported); + pointsEl.setVisible(scoreCalculatorSupported); + passedEl.setVisible(scoreCalculatorSupported); + + boolean selected = passedEl.isAtLeastSelected(1); + cutValueEl.setVisible(scoreCalculatorSupported && selected); + outputEl.setVisible(scoreCalculatorSupported && selected); + if(selected) { + boolean cutValueSelected = outputEl.isSelected(0); + cutValueEl.setVisible(scoreCalculatorSupported && cutValueSelected); + } + } + @Override protected void formOK(UserRequest ureq) { data.setStructureTitle(titleEl.getValue()); data.setStructureShortTitle(shortTitleEl.getValue()); data.setStructureObjectives(objectivesEl.getValue()); - data.setPoints(pointsEl.isAtLeastSelected(1)); - data.setPassed(passedEl.isAtLeastSelected(1)); - if(outputEl.isVisible() && outputEl.isSelected(0)) { - Float cutValue = new Float(Float.parseFloat(cutValueEl.getValue())); - data.setCutValue(cutValue); + if (scoreCalculatorSupported) { + data.setPoints(pointsEl.isAtLeastSelected(1)); + data.setPassed(passedEl.isAtLeastSelected(1)); + if(outputEl.isVisible() && outputEl.isSelected(0)) { + Float cutValue = new Float(Float.parseFloat(cutValueEl.getValue())); + data.setCutValue(cutValue); + } } fireEvent(ureq, StepsEvent.INFORM_FINISHED); diff --git a/src/main/java/org/olat/course/nodes/gta/AbstractGTAAssessmentHandler.java b/src/main/java/org/olat/course/nodes/gta/AbstractGTAAssessmentHandler.java index 87fddc94dda79a99a84a2f94978bdd8c0c79bef0..e5726f1fafa1caa0556be1501cc04fa26ab6771b 100644 --- a/src/main/java/org/olat/course/nodes/gta/AbstractGTAAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/gta/AbstractGTAAssessmentHandler.java @@ -39,8 +39,6 @@ import org.olat.course.nodes.gta.ui.GTAAssessmentDetailsController; import org.olat.course.nodes.gta.ui.GTAIdentityListCourseNodeController; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -75,17 +73,6 @@ public abstract class AbstractGTAAssessmentHandler implements AssessmentHandler } return AccountingEvaluatorsBuilder.defaultConventional(); } - - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, diff --git a/src/main/java/org/olat/course/nodes/gta/GTAAssessmentConfig.java b/src/main/java/org/olat/course/nodes/gta/GTAAssessmentConfig.java index 7beaa73d428b4b15ead895696b0a92615fb6779b..1ea3f55432ea573cc171974fcc2b1d6027590a20 100644 --- a/src/main/java/org/olat/course/nodes/gta/GTAAssessmentConfig.java +++ b/src/main/java/org/olat/course/nodes/gta/GTAAssessmentConfig.java @@ -40,17 +40,17 @@ public class GTAAssessmentConfig extends ModuleAssessmentConfig { } @Override - public boolean hasScore() { - if (hasNoGrading) return false; + public Mode getScoreMode() { + if (hasNoGrading) return Mode.none; - return super.hasScore(); + return super.getScoreMode(); } @Override - public boolean hasPassed() { - if (hasNoGrading) return false; + public Mode getPassedMode() { + if (hasNoGrading) return Mode.none; - return super.hasPassed(); + return super.getPassedMode(); } @Override diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java b/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java index 2574a0ea5d79937c4e3f5f2155bb5043a1823e50..f3811e9b003707b3cdd5ca8aeb5f6fb50d38302b 100644 --- a/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java +++ b/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java @@ -53,6 +53,7 @@ import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; @@ -593,10 +594,10 @@ class GTANotifications { String status = null; CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(gtaNode); - if(assessmentConfig.hasScore() && assessment.getScore() != null) { + if(Mode.none != assessmentConfig.getScoreMode() && assessment.getScore() != null) { score = AssessmentHelper.getRoundedScore(assessment.getScore()); } - if(assessmentConfig.hasPassed() && assessment.getPassed() != null) { + if(Mode.none != assessmentConfig.getPassedMode() && assessment.getPassed() != null) { status = assessment.getPassed().booleanValue() ? translator.translate("notifications.assessment.passed.true") : translator.translate("notifications.assessment.passed.false"); } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java index 5d09fd91aa95b4f4df10d948212c0d0d3e5dff85..e185e88b124e42b7cc4b3a8ee2ed0dc7979811ba 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java @@ -59,6 +59,7 @@ import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.bulk.PassedCellRenderer; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.highscore.ui.HighScoreRunController; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.MSCourseNode; @@ -141,8 +142,8 @@ public class GTACoachedGroupGradingController extends FormBasicController { assessmentManager = courseEnv.getAssessmentManager(); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(gtaNode); - withScore = assessmentConfig.hasScore(); - withPassed = assessmentConfig.hasPassed(); + withScore = Mode.none != assessmentConfig.getScoreMode(); + withPassed = Mode.none != assessmentConfig.getPassedMode(); withComment = assessmentConfig.hasComment(); Roles roles = ureq.getUserSession().getRoles(); diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAEditController.java index 7af2fc7c180cf3c117c864873402d605a52cfa40..86951b9c6ae58507775eb66d80287e404af3edeb 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTAEditController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAEditController.java @@ -29,6 +29,7 @@ import org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultCon import org.olat.course.ICourse; import org.olat.course.editor.NodeEditController; import org.olat.course.highscore.ui.HighScoreEditController; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.MSCourseNode; import org.olat.course.nodes.gta.GTAType; @@ -70,6 +71,7 @@ public class GTAEditController extends ActivateableTabbableDefaultController { private final ModuleConfiguration config; private final UserCourseEnvironment euce; private final CourseEnvironment courseEnv; + private final NodeAccessType nodeAccessType; public GTAEditController(UserRequest ureq, WindowControl wControl, GTACourseNode gtaNode, ICourse course, UserCourseEnvironment euce) { @@ -78,6 +80,7 @@ public class GTAEditController extends ActivateableTabbableDefaultController { this.euce = euce; this.gtaNode = gtaNode; courseEnv = course.getCourseEnvironment(); + nodeAccessType = NodeAccessType.of(course); config = gtaNode.getModuleConfiguration(); //workflow @@ -224,7 +227,7 @@ public class GTAEditController extends ActivateableTabbableDefaultController { public MSEditFormController createManualAssessmentCtrl(UserRequest ureq) { boolean singleIdentityTask = GTAType.individual.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE)); - return new MSEditFormController(ureq, getWindowControl(), config, translate("pane.tab.grading"), - "Three Steps to Your Task#_task_configuration", singleIdentityTask); + return new MSEditFormController(ureq, getWindowControl(), config, nodeAccessType, + translate("pane.tab.grading"), "Three Steps to Your Task#_task_configuration", singleIdentityTask); } } \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java index ccc5ba28180af5483ae9d7c2c76ee49811ee9bf5..0506f0ea619cc033cba58b51e6a6a9afe2494de4 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java @@ -60,6 +60,7 @@ import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.ui.GroupAssessmentModel.Cols; @@ -128,8 +129,8 @@ public class GroupAssessmentController extends FormBasicController { this.assessedGroup = assessedGroup; AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode);; - withScore = assessmentConfig.hasScore(); - withPassed = assessmentConfig.hasPassed(); + withScore = Mode.none != assessmentConfig.getScoreMode(); + withPassed = Mode.none != assessmentConfig.getPassedMode(); if(withPassed) { cutValue = assessmentConfig.getCutValue(); } diff --git a/src/main/java/org/olat/course/nodes/iq/IQConfigurationController.java b/src/main/java/org/olat/course/nodes/iq/IQConfigurationController.java index e15db0c5e94c51ba428329a83723a8346ba28b47..09e2e797c70c9fe0a0f4f77eff356650a7ca3104 100644 --- a/src/main/java/org/olat/course/nodes/iq/IQConfigurationController.java +++ b/src/main/java/org/olat/course/nodes/iq/IQConfigurationController.java @@ -49,6 +49,7 @@ import org.olat.core.util.vfs.VFSConstants; import org.olat.core.util.vfs.VFSStatus; import org.olat.course.ICourse; import org.olat.course.editor.NodeEditController; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.AbstractAccessableCourseNode; import org.olat.course.nodes.CourseNodeFactory; import org.olat.course.nodes.IQSELFCourseNode; @@ -124,16 +125,6 @@ public class IQConfigurationController extends BasicController { @Autowired private RepositoryService repositoryService; - /** - * - * @param ureq - * @param wControl - * @param stackPanel - * @param course - * @param courseNode - * @param euce - * @param type - */ public IQConfigurationController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, ICourse course, AbstractAccessableCourseNode courseNode, String type) { super(ureq, wControl); @@ -222,7 +213,8 @@ public class IQConfigurationController extends BasicController { fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT); } QTI21DeliveryOptions deliveryOptions = qti21service.getDeliveryOptions(re); - mod21ConfigForm = new QTI21EditForm(ureq, getWindowControl(), moduleConfiguration, deliveryOptions, needManualCorrection); + mod21ConfigForm = new QTI21EditForm(ureq, getWindowControl(), moduleConfiguration, + NodeAccessType.of(course), deliveryOptions, needManualCorrection); mod21ConfigForm.update(re); listenTo(mod21ConfigForm); myContent.put("iqeditform", mod21ConfigForm.getInitialComponent()); diff --git a/src/main/java/org/olat/course/nodes/iq/IQEditController.java b/src/main/java/org/olat/course/nodes/iq/IQEditController.java index df9dc64443332e8f83e1c42d1e3c81557d7918f4..5ccffae1ab861376fe2d6b877b64a839dd6ede2e 100644 --- a/src/main/java/org/olat/course/nodes/iq/IQEditController.java +++ b/src/main/java/org/olat/course/nodes/iq/IQEditController.java @@ -44,6 +44,7 @@ import org.olat.course.nodes.AbstractAccessableCourseNode; import org.olat.course.nodes.IQSELFCourseNode; import org.olat.course.nodes.IQSURVCourseNode; import org.olat.course.nodes.IQTESTCourseNode; +import org.olat.course.nodes.MSCourseNode; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.ims.qti.process.AssessmentInstance; import org.olat.modules.ModuleConfiguration; @@ -149,6 +150,7 @@ public class IQEditController extends ActivateableTabbableDefaultController impl public static final String CONFIG_KEY_RESULT_ON_FINISH = "showResultsOnFinish"; public static final String CONFIG_KEY_RESULT_ON_HOME_PAGE = "showResultsOnHomePage"; + public static final String CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT = MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT; public static final String CONFIG_KEY_DATE_DEPENDENT_TEST = "dateDependentTest"; public static final String CONFIG_KEY_RESULTS_START_TEST_DATE = "resultsStartTestDate"; public static final String CONFIG_KEY_RESULTS_END_TEST_DATE = "resultsEndTestDate"; diff --git a/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentConfig.java b/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentConfig.java index c639e372c955fda8d987f446b6dbd5dd117af497..4b830278e95c3a06377a0b3f99c0a59674d233ef 100644 --- a/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentConfig.java +++ b/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentConfig.java @@ -48,8 +48,15 @@ public class IQTESTAssessmentConfig implements AssessmentConfig { } @Override - public boolean isEvaluationPersisted() { - return true; + public boolean ignoreInCourseAssessment() { + ModuleConfiguration config = courseNode.getModuleConfiguration(); + return config.getBooleanSafe(IQEditController.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + } + + @Override + public void setIgnoreInCourseAssessment(boolean ignoreInCourseAssessment) { + ModuleConfiguration config = courseNode.getModuleConfiguration(); + config.setBooleanEntry(IQEditController.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); } @Override @@ -58,8 +65,8 @@ public class IQTESTAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasScore() { - return true; + public Mode getScoreMode() { + return Mode.setByNode; } @Override @@ -120,8 +127,8 @@ public class IQTESTAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasPassed() { - return true; + public Mode getPassedMode() { + return Mode.setByNode; } @Override diff --git a/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentHandler.java b/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentHandler.java index d057ec755897ad7c6ba4abb5efecbc0b4a0e0812..78a3b79c8f9f024e4718141c9a16ce6e9237b4cd 100644 --- a/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/iq/IQTESTAssessmentHandler.java @@ -41,8 +41,6 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.IQTESTCourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.group.BusinessGroup; @@ -100,17 +98,6 @@ public class IQTESTAssessmentHandler implements AssessmentHandler { private String getRepositoryEntrySoftKey(CourseNode courseNode) { return (String)courseNode.getModuleConfiguration().get(IQEditController.CONFIG_KEY_REPOSITORY_SOFTKEY); } - - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java index a204d9180e5cde3ba4c2bee538200cbc9b448a42..bab766a50367b1c2ae4c031f4e26decd3b95cffb 100644 --- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java +++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java @@ -62,6 +62,7 @@ import org.olat.course.DisposedCourseRestartController; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.assessment.manager.AssessmentNotificationsHandler; import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.highscore.ui.HighScoreRunController; @@ -250,7 +251,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); if (assessmentConfig.isAssessable()) { - if (assessmentConfig.hasScore() || userCourseEnv.isCoach()){ + if (Mode.none != assessmentConfig.getScoreMode() || userCourseEnv.isCoach()){ HighScoreRunController highScoreCtr = new HighScoreRunController(ureq, getWindowControl(), userCourseEnv, courseNode); if (highScoreCtr.isViewHighscore()) { Component highScoreComponent = highScoreCtr.getInitialComponent(); diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21EditForm.java b/src/main/java/org/olat/course/nodes/iq/QTI21EditForm.java index 36c4b7d69081e37e76baca962a95dbab912ccbbe..f8a94075532e6b8ae90afbc7168ab7a2b47d66a3 100644 --- a/src/main/java/org/olat/course/nodes/iq/QTI21EditForm.java +++ b/src/main/java/org/olat/course/nodes/iq/QTI21EditForm.java @@ -39,6 +39,8 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.course.assessment.AssessmentHelper; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.fileresource.FileResourceManager; import org.olat.ims.qti.process.AssessmentInstance; import org.olat.ims.qti21.QTI21AssessmentResultsOptions; @@ -83,24 +85,29 @@ public class QTI21EditForm extends FormBasicController { private StaticTextElement minScoreEl; private StaticTextElement maxScoreEl; private StaticTextElement cutValueEl; + private MultipleSelectionElement ignoreInCourseAssessmentEl; private MultipleSelectionElement showResultsOnFinishEl; private MultipleSelectionElement assessmentResultsOnFinishEl; private FormLayoutContainer reportLayout; private final boolean needManualCorrection; private final ModuleConfiguration modConfig; + private final boolean ignoreInCourseAssessmentAvailable; private final QTI21DeliveryOptions deliveryOptions; private DialogBoxController confirmTestDateCtrl; @Autowired private QTI21Service qtiService; + @Autowired + private NodeAccessService nodeAccessService; public QTI21EditForm(UserRequest ureq, WindowControl wControl, ModuleConfiguration modConfig, - QTI21DeliveryOptions deliveryOptions, boolean needManualCorrection) { + NodeAccessType nodeAccessType, QTI21DeliveryOptions deliveryOptions, boolean needManualCorrection) { super(ureq, wControl, LAYOUT_BAREBONE); this.modConfig = modConfig; + this.ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(nodeAccessType); this.deliveryOptions = (deliveryOptions == null ? new QTI21DeliveryOptions() : deliveryOptions); this.needManualCorrection = needManualCorrection; @@ -137,6 +144,12 @@ public class QTI21EditForm extends FormBasicController { cutValueEl = uifactory.addStaticTextElement("score.cut", "", formLayout); cutValueEl.setVisible(false); + ignoreInCourseAssessmentEl = uifactory.addCheckboxesHorizontal("ignore.in.course.assessment", formLayout, + new String[] { "xx" }, new String[] { null }); + boolean ignoreInCourseAssessment = modConfig.getBooleanSafe(IQEditController.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + ignoreInCourseAssessmentEl.select(ignoreInCourseAssessmentEl.getKey(0), ignoreInCourseAssessment); + ignoreInCourseAssessmentEl.setVisible(ignoreInCourseAssessmentAvailable); + boolean testDateDependent = modConfig.getBooleanSafe(IQEditController.CONFIG_KEY_DATE_DEPENDENT_TEST); testDateDependentEl = uifactory.addCheckboxesHorizontal("qti_datetest", "qti.form.test.date", formLayout, new String[]{"xx"}, new String[]{null}); testDateDependentEl.select("xx", testDateDependent); @@ -393,6 +406,9 @@ public class QTI21EditForm extends FormBasicController { @Override protected void formOK(UserRequest ureq) { + boolean ignoreInCourseAssessment = ignoreInCourseAssessmentEl.isVisible() && ignoreInCourseAssessmentEl.isAtLeastSelected(1); + modConfig.setBooleanEntry(IQEditController.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); + modConfig.setBooleanEntry(IQEditController.CONFIG_KEY_DATE_DEPENDENT_TEST, testDateDependentEl.isSelected(0)); modConfig.setDateValue(IQEditController.CONFIG_KEY_RESULTS_START_TEST_DATE, startTestDateElement.getDate()); diff --git a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_de.properties index f216a8cacd7b6b5a97314b245cc035c6e9ddbc78..10602a6c4574009dfdcafbbc4c09a79a99dfd13d 100644 --- a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_de.properties @@ -72,6 +72,7 @@ fieldset.chosecreateeditfile=Informationstext (HTML-Seite) file.name=Gew\u00E4hlte Datei fully.assessed.trigger.status.in.review=Test beendet grade.nobody=Es gibt kein Resultat zu korrigieren. +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment info.assessment=Bei diesem Test k\u00F6nnen Ihre Resultate von den Administratoren und den Betreuern dieses Kurses eingesehen werden. info.nodedelete=Die bisher angefallenen Daten dieses Kursbausteins werden in Ihrem pers\u00F6nlichen Ordner unter private/archive/[Kursname]/. archiviert. info.selfassessment=Beim Selbsttest werden alle Eingaben anonym gespeichert. diff --git a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_en.properties index f8b455e0ff1dffb753de8e27dc1176d4e4744fd4..e4535ac8c98eb705bcd1a5db21d9f1be95fee728 100644 --- a/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/iq/_i18n/LocalStrings_en.properties @@ -72,6 +72,7 @@ fieldset.chosecreateeditfile=Information (HTML page) file.name=Selected file fully.assessed.trigger.status.in.review=Test finished hour.short=h +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment info.assessment=Results of this test are visible to administrators and tutors of this course. info.nodedelete=All user data of this course element will be archived in your personal folder, section private/archive/[coursename]/. info.selfassessment=For the self-test all entries are saved anonymously. diff --git a/src/main/java/org/olat/course/nodes/ms/MSAssessmentConfig.java b/src/main/java/org/olat/course/nodes/ms/MSAssessmentConfig.java index 649e771cd01f1ea80a6357fc860d6dc1d0114217..6aa9f40a36218e65a7b2e6d5595b31210fa3d73d 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSAssessmentConfig.java +++ b/src/main/java/org/olat/course/nodes/ms/MSAssessmentConfig.java @@ -37,14 +37,14 @@ public class MSAssessmentConfig extends ModuleAssessmentConfig { } @Override - public boolean hasScore() { + public Mode getScoreMode() { String scoreKey = config.getStringValue(MSCourseNode.CONFIG_KEY_SCORE); - return !MSCourseNode.CONFIG_VALUE_SCORE_NONE.equals(scoreKey); + return !MSCourseNode.CONFIG_VALUE_SCORE_NONE.equals(scoreKey)? Mode.setByNode: Mode.none; } @Override public Float getMaxScore() { - if (!hasScore()) { + if (Mode.none == getScoreMode()) { throw new OLATRuntimeException(MSAssessmentConfig.class, "getMaxScore not defined when hasScoreConfigured set to false", null); } return MSCourseNode.getMinMax(config).getMax(); @@ -52,7 +52,7 @@ public class MSAssessmentConfig extends ModuleAssessmentConfig { @Override public Float getMinScore() { - if (!hasScore()) { + if (Mode.none == getScoreMode()) { throw new OLATRuntimeException(MSAssessmentConfig.class, "getMinScore not defined when hasScoreConfigured set to false", null); } return MSCourseNode.getMinMax(config).getMin(); diff --git a/src/main/java/org/olat/course/nodes/ms/MSAssessmentHandler.java b/src/main/java/org/olat/course/nodes/ms/MSAssessmentHandler.java index de15398c7d41a9dd8f269dfaf32c99cf990e2554..ae3f0a27ce614ea0248980d58419bc0624fa65ab 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/ms/MSAssessmentHandler.java @@ -36,8 +36,6 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.MSCourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -81,17 +79,6 @@ public class MSAssessmentHandler implements AssessmentHandler { } return AccountingEvaluatorsBuilder.defaultConventional(); } - - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, diff --git a/src/main/java/org/olat/course/nodes/ms/MSConfigController.java b/src/main/java/org/olat/course/nodes/ms/MSConfigController.java index 55fe2e43190e94017304c29d3f6257d1123231d4..18de2a80a7f3ec5942f7af04ceb3879bda303435 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSConfigController.java +++ b/src/main/java/org/olat/course/nodes/ms/MSConfigController.java @@ -35,6 +35,7 @@ import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.SpacerElement; import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; @@ -48,6 +49,8 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.util.StringHelper; import org.olat.course.ICourse; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.MSCourseNode; import org.olat.fileresource.FileResourceManager; import org.olat.modules.ModuleConfiguration; @@ -86,6 +89,8 @@ public class MSConfigController extends FormBasicController { private String[] trueFalseKeys; private String[] passedTypeValues; private TextElement cutEl; + private MultipleSelectionElement ignoreInCourseAssessmentEl; + private SpacerElement ignoreInCourseAssessmentSpacer; private MultipleSelectionElement commentFlagEl; private MultipleSelectionElement individualAssessmentDocsFlagEl; private RichTextElement infotextUserEl; @@ -98,6 +103,7 @@ public class MSConfigController extends FormBasicController { private final ModuleConfiguration config; private final RepositoryEntry ores; private final String nodeIdent; + private final boolean ignoreInCourseAssessmentAvailable; private RepositoryEntry formEntry; private MinMax formMinMax; @@ -105,6 +111,8 @@ public class MSConfigController extends FormBasicController { private MSService msService; @Autowired private EvaluationFormManager evaluationFormManager; + @Autowired + private NodeAccessService nodeAccessService; public MSConfigController(UserRequest ureq, WindowControl wControl, ICourse course, MSCourseNode courseNode) { @@ -112,6 +120,7 @@ public class MSConfigController extends FormBasicController { this.config = courseNode.getModuleConfiguration(); this.ores = RepositoryManager.getInstance().lookupRepositoryEntry(course, true); this.nodeIdent = courseNode.getIdent(); + this.ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(NodeAccessType.of(course)); this.formEntry = MSCourseNode.getEvaluationForm(config); doCalculateMinMax(); @@ -205,6 +214,14 @@ public class MSConfigController extends FormBasicController { cutEl.setElementCssClass("o_sel_course_ms_cut"); uifactory.addSpacerElement("spacer2", formLayout, false); + + // Ignore in course assessment + ignoreInCourseAssessmentEl = uifactory.addCheckboxesHorizontal("ignore.in.course.assessment", formLayout, + new String[] { "xx" }, new String[] { null }); + boolean ignoreInCourseAssessment = config.getBooleanSafe(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + ignoreInCourseAssessmentEl.select(ignoreInCourseAssessmentEl.getKey(0), ignoreInCourseAssessment); + + ignoreInCourseAssessmentSpacer = uifactory.addSpacerElement("spacer3", formLayout, false); // Comments commentFlagEl = uifactory.addCheckboxesHorizontal("form.comment", formLayout, ENABLED_KEYS, @@ -217,7 +234,7 @@ public class MSConfigController extends FormBasicController { Boolean docsCf = config.getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_INDIVIDUAL_ASSESSMENT_DOCS, false); individualAssessmentDocsFlagEl.select(ENABLED_KEYS[0], docsCf); - uifactory.addSpacerElement("spacer3", formLayout, false); + uifactory.addSpacerElement("spacer4", formLayout, false); // Create the rich text fields. String infoUser = (String) config.get(MSCourseNode.CONFIG_KEY_INFOTEXT_USER); @@ -293,6 +310,13 @@ public class MSConfigController extends FormBasicController { // cut value boolean cutVisible = passedTypeVisible && passedTypeEl.isOneSelected() && passedTypeEl.getSelected() == 0; cutEl.setVisible(cutVisible); + + // ignore in course assessment + boolean hasScore = scoreEl.isOneSelected() && !scoreEl.getSelectedKey().equals(MSCourseNode.CONFIG_VALUE_SCORE_NONE); + boolean ignoreInScoreVisible = ignoreInCourseAssessmentAvailable + && (hasScore || passedEl.isAtLeastSelected(1)); + ignoreInCourseAssessmentEl.setVisible(ignoreInScoreVisible); + ignoreInCourseAssessmentSpacer.setVisible(ignoreInScoreVisible); } @Override @@ -487,6 +511,9 @@ public class MSConfigController extends FormBasicController { config.remove(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE); } + boolean ignoreInCourseAssessment = ignoreInCourseAssessmentEl.isVisible() && ignoreInCourseAssessmentEl.isAtLeastSelected(1); + config.setBooleanEntry(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); + Boolean commentFieldEnabled = Boolean.valueOf(commentFlagEl.isSelected(0)); config.set(MSCourseNode.CONFIG_KEY_HAS_COMMENT_FIELD, commentFieldEnabled); diff --git a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeEditController.java b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeEditController.java index eccf172b4e4343f3444728a9c7b85ea3bcd996e0..c509a39eb7dea00590fea52ee446a23afe8dadc4 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeEditController.java +++ b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeEditController.java @@ -40,6 +40,7 @@ import org.olat.core.util.Util; import org.olat.course.ICourse; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.editor.NodeEditController; import org.olat.course.highscore.ui.HighScoreEditController; @@ -126,7 +127,7 @@ public class MSCourseNodeEditController extends ActivateableTabbableDefaultContr private void updateHighscoreTab() { AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(msNode); myTabbedPane.setEnabled(myTabbedPane.indexOfTab(highScoreNodeConfigController.getInitialComponent()), - assessmentConfig.hasScore()); + Mode.none != assessmentConfig.getScoreMode()); } @Override diff --git a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java index aeb3b85ae67e81b0988380c26eae93450e623065..ebf95e2e38e2fc9e4658333bfafdbd2f67b9d5c8 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java +++ b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java @@ -48,6 +48,7 @@ import org.olat.course.CourseModule; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.highscore.ui.HighScoreRunController; import org.olat.course.nodes.CourseNode; @@ -117,7 +118,7 @@ public class MSCourseNodeRunController extends BasicController implements Activa myContent = createVelocityContainer("run"); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if (assessmentConfig.hasScore()) { + if (Mode.none != assessmentConfig.getScoreMode()) { HighScoreRunController highScoreCtr = new HighScoreRunController(ureq, wControl, userCourseEnv, courseNode); if (highScoreCtr.isViewHighscore()) { Component highScoreComponent = highScoreCtr.getInitialComponent(); @@ -196,13 +197,13 @@ public class MSCourseNodeRunController extends BasicController implements Activa private void exposeConfigToVC(UserRequest ureq) { AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); ModuleConfiguration config = courseNode.getModuleConfiguration(); - myContent.contextPut("hasScoreField", assessmentConfig.hasScore()); - if (assessmentConfig.hasScore()) { + myContent.contextPut("hasScoreField", assessmentConfig.getScoreMode()); + if (Mode.none != assessmentConfig.getScoreMode()) { myContent.contextPut("scoreMin", AssessmentHelper.getRoundedScore(assessmentConfig.getMinScore())); myContent.contextPut("scoreMax", AssessmentHelper.getRoundedScore(assessmentConfig.getMaxScore())); } - myContent.contextPut("hasPassedField", assessmentConfig.hasPassed()); - if (assessmentConfig.hasPassed()) { + myContent.contextPut("hasPassedField", assessmentConfig.getPassedMode()); + if (Mode.none != assessmentConfig.getPassedMode()) { myContent.contextPut("passedCutValue", AssessmentHelper.getRoundedScore(assessmentConfig.getCutValue())); } myContent.contextPut("hasCommentField", assessmentConfig.hasComment()); diff --git a/src/main/java/org/olat/course/nodes/ms/MSEditFormController.java b/src/main/java/org/olat/course/nodes/ms/MSEditFormController.java index 6ff7b92a5a50f7e73316d56f6681881a8f44493b..d50056c896bd0fc85eafaeb85305a945000f12db 100644 --- a/src/main/java/org/olat/course/nodes/ms/MSEditFormController.java +++ b/src/main/java/org/olat/course/nodes/ms/MSEditFormController.java @@ -28,6 +28,7 @@ import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.SpacerElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; @@ -36,8 +37,11 @@ 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.util.StringHelper; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.MSCourseNode; import org.olat.modules.ModuleConfiguration; +import org.springframework.beans.factory.annotation.Autowired; /** * Provides a FlexiForm for the assesment settings dialog, including custom @@ -50,6 +54,7 @@ public class MSEditFormController extends FormBasicController { /** Configuration this controller will modify. */ private final ModuleConfiguration modConfig; + private final boolean ignoreInCourseAssessmentAvailable; /** whether score will be awarded or not. */ private MultipleSelectionElement scoreGranted; @@ -76,6 +81,9 @@ public class MSEditFormController extends FormBasicController { /** Text input element for the passing score. */ private TextElement cutVal; + + private MultipleSelectionElement ignoreInCourseAssessmentEl; + private SpacerElement ignoreInCourseAssessmentSpacer; /** Rich text input element for a notice to all users. */ private RichTextElement infotextUser; @@ -95,19 +103,23 @@ public class MSEditFormController extends FormBasicController { private final String helpUrl; private final boolean withIndividualAssessmentDocs; - public MSEditFormController(UserRequest ureq, WindowControl wControl, ModuleConfiguration modConfig) { - this(ureq, wControl, modConfig, null, null, true); + @Autowired + private NodeAccessService nodeAccessService; + + public MSEditFormController(UserRequest ureq, WindowControl wControl, ModuleConfiguration modConfig, NodeAccessType nodeAccessType) { + this(ureq, wControl, modConfig, nodeAccessType, null, null, true); } - public MSEditFormController(UserRequest ureq, WindowControl wControl, ModuleConfiguration modConfig, String title, - String helpUrl) { - this(ureq, wControl, modConfig, title, helpUrl, true); + public MSEditFormController(UserRequest ureq, WindowControl wControl, ModuleConfiguration modConfig, NodeAccessType nodeAccessType, + String title, String helpUrl) { + this(ureq, wControl, modConfig, nodeAccessType, title, helpUrl, true); } - public MSEditFormController(UserRequest ureq, WindowControl wControl, ModuleConfiguration modConfig, String title, - String helpUrl, boolean withIndividualAssessmentDocs) { + public MSEditFormController(UserRequest ureq, WindowControl wControl, ModuleConfiguration modConfig, NodeAccessType nodeAccessType, + String title, String helpUrl, boolean withIndividualAssessmentDocs) { super(ureq, wControl, FormBasicController.LAYOUT_DEFAULT); this.modConfig = modConfig; + this.ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(nodeAccessType); this.title = title; this.helpUrl = helpUrl; this.withIndividualAssessmentDocs = withIndividualAssessmentDocs; @@ -116,21 +128,11 @@ public class MSEditFormController extends FormBasicController { initForm(ureq); } - /** - * - * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#doDispose - * () - */ @Override protected void doDispose() { // Don't dispose anything } - /** - * - * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formOK - * (org.olat.core.gui.UserRequest) - */ @Override protected void formOK(UserRequest ureq) { fireEvent(ureq, Event.DONE_EVENT); @@ -212,7 +214,14 @@ public class MSEditFormController extends FormBasicController { cutVal.setElementCssClass("o_sel_course_ms_cut_val"); uifactory.addSpacerElement("spacer2", formLayout, false); - + + ignoreInCourseAssessmentEl = uifactory.addCheckboxesHorizontal("ignore.in.course.assessment", formLayout, + new String[] { "xx" }, new String[] { null }); + boolean ignoreInCourseAssessment = modConfig.getBooleanSafe(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + ignoreInCourseAssessmentEl.select(ignoreInCourseAssessmentEl.getKey(0), ignoreInCourseAssessment); + + ignoreInCourseAssessmentSpacer = uifactory.addSpacerElement("spacer3", formLayout, false); + // Create the "individual comment" dropdown. commentFlag = uifactory.addCheckboxesHorizontal("form.comment", formLayout, new String[]{"xx"}, new String[]{null}); Boolean cf = (Boolean) modConfig.get(MSCourseNode.CONFIG_KEY_HAS_COMMENT_FIELD); @@ -226,7 +235,7 @@ public class MSEditFormController extends FormBasicController { } individualAssessmentDocsFlag.setVisible(withIndividualAssessmentDocs); - uifactory.addSpacerElement("spacer3", formLayout, false); + uifactory.addSpacerElement("spacer4", formLayout, false); // Create the rich text fields. String infoUser = (String) modConfig.get(MSCourseNode.CONFIG_KEY_INFOTEXT_USER); @@ -264,6 +273,12 @@ public class MSEditFormController extends FormBasicController { displayType.setVisible(displayPassed.isSelected(0)); cutVal.setVisible(displayType.isVisible() && displayType.isSelected(0)); cutVal.setMandatory(cutVal.isVisible()); + + boolean ignoreInScoreVisible = ignoreInCourseAssessmentAvailable + && (scoreGranted.isSelected(0) || displayPassed.isSelected(0)); + ignoreInCourseAssessmentEl.setVisible(ignoreInScoreVisible); + ignoreInCourseAssessmentSpacer.setVisible(ignoreInScoreVisible); + validateFormLogic(ureq); } @@ -335,9 +350,6 @@ public class MSEditFormController extends FormBasicController { } } - /** - * @param moduleConfiguration - */ public void updateModuleConfiguration(ModuleConfiguration moduleConfiguration) { // mandatory score flag Boolean sf = Boolean.valueOf(scoreGranted.isSelected(0)); @@ -368,6 +380,9 @@ public class MSEditFormController extends FormBasicController { // remove old config moduleConfiguration.remove(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE); } + + boolean ignoreInCourseAssessment = ignoreInCourseAssessmentEl.isVisible() && ignoreInCourseAssessmentEl.isAtLeastSelected(1); + moduleConfiguration.setBooleanEntry(MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); // mandatory comment flag moduleConfiguration.set(MSCourseNode.CONFIG_KEY_HAS_COMMENT_FIELD, Boolean.valueOf(commentFlag.isSelected(0))); diff --git a/src/main/java/org/olat/course/nodes/ms/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/ms/_i18n/LocalStrings_de.properties index 8d103e4b2a603540c55749c272425da0312a1185..e9f3e0a5c3a484031036a489f7a97738d98f68b2 100644 --- a/src/main/java/org/olat/course/nodes/ms/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/ms/_i18n/LocalStrings_de.properties @@ -47,6 +47,7 @@ form.score.none=Keine Punkte vergeben form.title={0} form.yes=Ja fully.assessed.trigger.status.done=Status durch Betreuer auf "erledigt" gesetzt. +ignore.in.course.assessment=Bei Kurs-Bewertung ausschliessen in.review=In Korrektur info.title=Information zur Bewertung log.title=\u00C4nderungsverlauf diff --git a/src/main/java/org/olat/course/nodes/ms/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/ms/_i18n/LocalStrings_en.properties index f390fe75129d10b11633cf6571159edc6557a1cb..bec7fb022ff979d1716f414d4569aa10be42c2b7 100644 --- a/src/main/java/org/olat/course/nodes/ms/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/ms/_i18n/LocalStrings_en.properties @@ -46,6 +46,7 @@ form.score.none=No points form.title={0} form.yes=Yes fully.assessed.trigger.status.done=Coach has set status to "done". +ignore.in.course.assessment=Ignore in course assessment in.review=In review info.title=Assessment information log.title=Change log diff --git a/src/main/java/org/olat/course/nodes/portfolio/PortfolioAssessmentHandler.java b/src/main/java/org/olat/course/nodes/portfolio/PortfolioAssessmentHandler.java index 601b2aa2886b2a631dc95bafb9f5f4b37adf2176..ebd8cbcbc6e67a2b6c3559e7038d759c9c9abe4e 100644 --- a/src/main/java/org/olat/course/nodes/portfolio/PortfolioAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/portfolio/PortfolioAssessmentHandler.java @@ -37,8 +37,6 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.PortfolioCourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -103,17 +101,6 @@ public class PortfolioAssessmentHandler implements AssessmentHandler { return referenceSoftkey; } - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } - @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, CourseNode courseNode, UserCourseEnvironment coachCourseEnv, UserCourseEnvironment assessedUserCourseEnv) { diff --git a/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeEditController.java b/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeEditController.java index 87f23323bf9ba9a0782b7c51681410673f3a2378..dc66de623713758927904dcd53156a20b3daabcd 100644 --- a/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeEditController.java +++ b/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeEditController.java @@ -34,10 +34,10 @@ import org.olat.course.ICourse; import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.editor.NodeEditController; import org.olat.course.highscore.ui.HighScoreEditController; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.MSCourseNode; import org.olat.course.nodes.PortfolioCourseNode; import org.olat.course.nodes.ms.MSEditFormController; -import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; import org.olat.portfolio.model.structel.PortfolioStructure; import org.olat.repository.RepositoryEntry; @@ -66,15 +66,16 @@ public class PortfolioCourseNodeEditController extends ActivateableTabbableDefau private ModuleConfiguration config; private PortfolioCourseNode courseNode; - public PortfolioCourseNodeEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, ICourse course, PortfolioCourseNode node, - ModuleConfiguration config, UserCourseEnvironment euce) { + public PortfolioCourseNodeEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, + ICourse course, PortfolioCourseNode node, ModuleConfiguration config) { super(ureq, wControl); this.config = config; this.courseNode = node; configForm = new PortfolioConfigForm(ureq, wControl, stackPanel, course, node); listenTo(configForm); - scoringController = new MSEditFormController(ureq, wControl, config, translate("pane.tab.portfolio_scoring"), "Creating Portfolio Tasks"); + scoringController = new MSEditFormController(ureq, wControl, config, NodeAccessType.of(course), + translate("pane.tab.portfolio_scoring"), "Creating Portfolio Tasks"); scoringContent = scoringController.getInitialComponent(); listenTo(scoringController); textForm = new PortfolioTextForm(ureq, wControl, course, node); diff --git a/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeRunController.java index 361564aaa5e18cc8b81e5e209fec8aac23fc2675..a1e9cf9be8de230ea282956482c8e17a1457985a 100644 --- a/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeRunController.java +++ b/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeRunController.java @@ -56,6 +56,7 @@ import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.highscore.ui.HighScoreRunController; import org.olat.course.nodes.MSCourseNode; import org.olat.course.nodes.PortfolioCourseNode; @@ -333,8 +334,10 @@ public class PortfolioCourseNodeRunController extends FormBasicController { boolean resultsVisible = scoreEval.getUserVisible() == null || scoreEval.getUserVisible().booleanValue(); assessmentInfosContainer.contextPut("resultsVisible", resultsVisible); //score - assessmentInfosContainer.contextPut("hasScoreField", new Boolean(assessmentConfig.hasScore())); - if(assessmentConfig.hasScore()) { + Boolean hasScore = Boolean.valueOf(Mode.none != assessmentConfig.getScoreMode()); + Boolean hasPassed = Boolean.valueOf(Mode.none != assessmentConfig.getPassedMode()); + assessmentInfosContainer.contextPut("hasScoreField", hasScore); + if(hasScore.booleanValue()) { Float score = scoreEval.getScore(); Float minScore = assessmentConfig.getMinScore(); Float maxScore = assessmentConfig.getMaxScore(); @@ -344,8 +347,8 @@ public class PortfolioCourseNodeRunController extends FormBasicController { } //passed - assessmentInfosContainer.contextPut("hasPassedField", new Boolean(assessmentConfig.hasPassed())); - if(assessmentConfig.hasPassed()) { + assessmentInfosContainer.contextPut("hasPassedField", hasPassed); + if(hasPassed.booleanValue()) { Boolean passed = scoreEval.getPassed(); assessmentInfosContainer.contextPut("passed", passed); assessmentInfosContainer.contextPut("hasPassedValue", new Boolean(passed != null)); diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentConfig.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentConfig.java index 1b297614b7a6487b28383742fe793578629fd726..ca6b67f0f5dd740cbdb78560cbb03565debd61e1 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentConfig.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentConfig.java @@ -41,13 +41,13 @@ public class ProjectBrokerAssessmentConfig extends ModuleAssessmentConfig { } @Override - public boolean hasScore() { - return false; + public Mode getScoreMode() { + return Mode.none; } @Override - public boolean hasPassed() { - return false; + public Mode getPassedMode() { + return Mode.none; } @Override diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentHandler.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentHandler.java index a2c9a564d49de176ae65d56265b45c07814e7ec3..59ca8c846e1e7c52acb999d2e81eece7b0329ab2 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerAssessmentHandler.java @@ -36,8 +36,6 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.ProjectBrokerCourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -80,17 +78,6 @@ public class ProjectBrokerAssessmentHandler implements AssessmentHandler { return AccountingEvaluatorsBuilder.defaultConventional(); } - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } - @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, CourseNode courseNode, UserCourseEnvironment coachCourseEnv, UserCourseEnvironment assessedUserCourseEnv) { diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerCourseEditorController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerCourseEditorController.java index 34a39592c45096b103cd3a24046e1ba4793eb906..bb3b5123582f56469bbd8d6ea4df6ab50a8483e4 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerCourseEditorController.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectBrokerCourseEditorController.java @@ -60,6 +60,7 @@ import org.olat.course.ICourse; import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.condition.ConditionEditController; import org.olat.course.editor.NodeEditController; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.ProjectBrokerCourseNode; import org.olat.course.nodes.TACourseNode; import org.olat.course.nodes.ms.MSCourseNodeEditController; @@ -200,7 +201,7 @@ public class ProjectBrokerCourseEditorController extends ActivateableTabbableDef editScoring = this.createVelocityContainer("editScoring"); editScoringConfigButton = LinkFactory.createButtonSmall("scoring.config.enable.button", editScoring, this); - scoringController = new MSEditFormController(ureq, wControl, config); + scoringController = new MSEditFormController(ureq, wControl, config, NodeAccessType.of(course)); listenTo(scoringController); editScoring.put("scoringController", scoringController.getInitialComponent()); diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentConfig.java b/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentConfig.java index e8fc3837eeaf52592bcb3a0117f368898ac1ad82..a5e8a1bac5958b4bbad13a1a29ce2293bb6da676 100644 --- a/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentConfig.java +++ b/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentConfig.java @@ -42,8 +42,13 @@ public class ScormAssessmentConfig implements AssessmentConfig { } @Override - public boolean isEvaluationPersisted() { - return true; + public boolean ignoreInCourseAssessment() { + return config.getBooleanSafe(ScormEditController.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + } + + @Override + public void setIgnoreInCourseAssessment(boolean ignoreInCourseAssessment) { + config.setBooleanEntry(ScormEditController.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, ignoreInCourseAssessment); } @Override @@ -52,14 +57,14 @@ public class ScormAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasScore() { + public Mode getScoreMode() { boolean assessable = config.getBooleanSafe(ScormEditController.CONFIG_ISASSESSABLE, true); if (assessable) { String type = config.getStringValue(ScormEditController.CONFIG_ASSESSABLE_TYPE, ScormEditController.CONFIG_ASSESSABLE_TYPE_SCORE); - return ScormEditController.CONFIG_ASSESSABLE_TYPE_SCORE.equals(type); + return ScormEditController.CONFIG_ASSESSABLE_TYPE_SCORE.equals(type)? Mode.setByNode: Mode.none; } - return false; + return Mode.none; } @Override @@ -75,8 +80,8 @@ public class ScormAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasPassed() { - return config.getBooleanSafe(ScormEditController.CONFIG_ISASSESSABLE, true); + public Mode getPassedMode() { + return config.getBooleanSafe(ScormEditController.CONFIG_ISASSESSABLE, true)? Mode.setByNode: Mode.none; } @Override diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentHandler.java b/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentHandler.java index 6309bd182c7bfdb4f2edf3458161bdf625d63dc8..4574a21c4624f933a027324d12a191cdfdcd7b6d 100644 --- a/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/scorm/ScormAssessmentHandler.java @@ -36,8 +36,6 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.ScormCourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -81,17 +79,6 @@ public class ScormAssessmentHandler implements AssessmentHandler { return AccountingEvaluatorsBuilder.defaultConventional(); } - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } - @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, CourseNode courseNode, UserCourseEnvironment coachCourseEnv, UserCourseEnvironment assessedUserCourseEnv) { diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormEditController.java b/src/main/java/org/olat/course/nodes/scorm/ScormEditController.java index 5df14ea82a5b402d679a042201e0015f7902dc5b..02e7294def01895e46a477332f5e53c6e8b5a6d8 100644 --- a/src/main/java/org/olat/course/nodes/scorm/ScormEditController.java +++ b/src/main/java/org/olat/course/nodes/scorm/ScormEditController.java @@ -56,6 +56,9 @@ import org.olat.core.util.StringHelper; import org.olat.course.ICourse; import org.olat.course.editor.NodeEditController; import org.olat.course.highscore.ui.HighScoreEditController; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; +import org.olat.course.nodes.MSCourseNode; import org.olat.course.nodes.ScormCourseNode; import org.olat.fileresource.FileResourceManager; import org.olat.fileresource.types.ScormCPFileResource; @@ -92,6 +95,7 @@ public class ScormEditController extends ActivateableTabbableDefaultController i public static final String CONFIG_ASSESSABLE_TYPE_SCORE = "score"; public static final String CONFIG_ASSESSABLE_TYPE_PASSED = "passed"; public static final String CONFIG_CUTVALUE = "cutvalue"; + public static final String CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT = MSCourseNode.CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT; public static final String CONFIG_DELIVERY_OPTIONS = "deliveryOptions"; public static final String CONFIG_FULLWINDOW = "fullwindow"; @@ -133,13 +137,16 @@ public class ScormEditController extends ActivateableTabbableDefaultController i @Autowired private ScormMainManager scormMainManager; + @Autowired + private NodeAccessService nodeAccessService; public ScormEditController(ScormCourseNode scormNode, UserRequest ureq, WindowControl wControl, ICourse course) { super(ureq, wControl); this.course = course; this.scormNode = scormNode; this.config = scormNode.getModuleConfiguration(); - main = new Panel("cpmain"); + + main = new Panel("cpmain"); cpConfigurationVc = this.createVelocityContainer("edit"); chooseCPButton = LinkFactory.createButtonSmall("command.importcp", cpConfigurationVc, this); @@ -191,12 +198,15 @@ public class ScormEditController extends ActivateableTabbableDefaultController i int maxAttempts = config.getIntegerSafe(CONFIG_MAXATTEMPTS, 0); boolean advanceScore = config.getBooleanSafe(CONFIG_ADVANCESCORE, true); int cutvalue = config.getIntegerSafe(CONFIG_CUTVALUE, 0); + boolean ignoreInCourseAssessmentAvailable = !nodeAccessService.isScoreCalculatorSupported(NodeAccessType.of(course)); + boolean ignoreInCourseAssessment = config.getBooleanSafe(CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT); + boolean fullWindow = config.getBooleanSafe(CONFIG_FULLWINDOW, true); boolean closeOnFinish = config.getBooleanSafe(CONFIG_CLOSE_ON_FINISH, false); - scorevarform = new VarForm(ureq, wControl, showMenu, skipLaunchPage, showNavButtons, - assessableType, cutvalue, fullWindow, - closeOnFinish, maxAttempts, advanceScore, attemptsDependOnScore); + scorevarform = new VarForm(ureq, wControl, showMenu, skipLaunchPage, showNavButtons, assessableType, cutvalue, + ignoreInCourseAssessmentAvailable, ignoreInCourseAssessment, fullWindow, closeOnFinish, maxAttempts, + advanceScore, attemptsDependOnScore); listenTo(scorevarform); cpConfigurationVc.put("scorevarform", scorevarform.getInitialComponent()); @@ -282,6 +292,7 @@ public class ScormEditController extends ActivateableTabbableDefaultController i config.setBooleanEntry(CONFIG_ISASSESSABLE, scorevarform.isAssessable()); config.setStringValue(CONFIG_ASSESSABLE_TYPE, scorevarform.getAssessableType()); config.setIntValue(CONFIG_CUTVALUE, scorevarform.getCutValue()); + config.setBooleanEntry(CONFIG_KEY_IGNORE_IN_COURSE_ASSESSMENT, scorevarform.isIgnoreInCourseAssessment()); config.setBooleanEntry(CONFIG_FULLWINDOW, scorevarform.isFullWindow()); config.setBooleanEntry(CONFIG_CLOSE_ON_FINISH, scorevarform.isCloseOnFinish()); // <OLATCE-289> @@ -385,6 +396,7 @@ class VarForm extends FormBasicController { private SingleSelection isAssessableEl; private SelectionElement skipLaunchPageEl; private TextElement cutValueEl; + private MultipleSelectionElement ignoreInCourseAssessmentEl; private SingleSelection attemptsEl; private MultipleSelectionElement advanceScoreEl; private MultipleSelectionElement scoreAttemptsEl; @@ -392,6 +404,8 @@ class VarForm extends FormBasicController { private boolean showMenu, showNavButtons, skipLaunchPage; private String assessableType; private int cutValue; + private final boolean ignoreInCourseAssessmentAvailable; + private boolean ignoreInCourseAssessment; private boolean fullWindow; private boolean closeOnFinish; private String[] assessableKeys, assessableValues; @@ -400,19 +414,18 @@ class VarForm extends FormBasicController { private boolean scoreAttempts; private int maxattempts; - /** - * - * @param name Name of the form - */ - public VarForm(UserRequest ureq, WindowControl wControl, boolean showMenu, boolean skipLaunchPage, boolean showNavButtons, - String assessableType, int cutValue, boolean fullWindow, boolean closeOnFinish, - int maxattempts, boolean advanceScore, boolean attemptsDependOnScore) { + public VarForm(UserRequest ureq, WindowControl wControl, boolean showMenu, boolean skipLaunchPage, + boolean showNavButtons, String assessableType, int cutValue, boolean ignoreInCourseAssessmentAvailable, + boolean ignoreInCourseAssessment, boolean fullWindow, boolean closeOnFinish, int maxattempts, + boolean advanceScore, boolean attemptsDependOnScore) { super(ureq, wControl); this.showMenu = showMenu; this.skipLaunchPage = skipLaunchPage; this.showNavButtons = showNavButtons; this.assessableType = assessableType; this.cutValue = cutValue; + this.ignoreInCourseAssessmentAvailable = ignoreInCourseAssessmentAvailable; + this.ignoreInCourseAssessment = ignoreInCourseAssessment; this.fullWindow = fullWindow; this.closeOnFinish = closeOnFinish; @@ -438,6 +451,10 @@ class VarForm extends FormBasicController { return 0; } + public boolean isIgnoreInCourseAssessment() { + return ignoreInCourseAssessmentEl.isVisible() && ignoreInCourseAssessmentEl.isAtLeastSelected(1); + } + public boolean isFullWindow() { return fullWindowEl.isMultiselect() && fullWindowEl.isSelected(0); } @@ -539,6 +556,10 @@ class VarForm extends FormBasicController { String val = cutValue < 0 ? "" : Integer.toString(cutValue); cutValueEl = uifactory.addTextElement("cutvalue", "cutvalue.label", 5, val, formLayout); cutValueEl.setDisplaySize(3); + + ignoreInCourseAssessmentEl = uifactory.addCheckboxesHorizontal("ignore.in.course.assessment", formLayout, + new String[] { "xx" }, new String[] { null }); + ignoreInCourseAssessmentEl.select(ignoreInCourseAssessmentEl.getKey(0), ignoreInCourseAssessment); advanceScoreEl = uifactory.addCheckboxesHorizontal("advanceScore", "advance.score.label", formLayout, new String[]{ "ison" }, new String[]{ "" }); advanceScoreEl.select("ison", advanceScore); @@ -575,6 +596,7 @@ class VarForm extends FormBasicController { advanceScoreEl.getComponent().setDirty(true); //assessable type score or none -> show "Score needed to pass" cutValueEl.setVisible(assessableKeys[0].equals(isAssessable) || assessableKeys[1].equals(isAssessable)); + ignoreInCourseAssessmentEl.setVisible(ignoreInCourseAssessmentAvailable); } public int getAttemptsValue() { diff --git a/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_de.properties index 7e9264a11e9f9805b6a05fe706ece12c396a2fd4..e1d3706e9070e6bfa884361f9aa6b8910f2d8ae3 100644 --- a/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_de.properties @@ -48,8 +48,7 @@ header=SCORM-Lerninhalt ausw\u00E4hlen headerform=Einstellungen fullwindow.label=Nur Modul anzeigen, LMS ausblenden closeonfinish.label=Modul automatisch schliessen wenn beendet - - +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment no.cp.chosen=<i>Kein SCORM-Lerninhalt ausgew\u00E4hlt</i> pane.tab.cpconfig=Lerninhalt pane.tab.delivery=$org.olat.core.gui.control.generic.iframe\:option.delivery diff --git a/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_en.properties index 70fec7f286a0bfd4ec1c22ff709f1fcee0b6443e..3a125c5b6f2cf7b1afb2d65b72358fbf3af99963 100644 --- a/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/scorm/_i18n/LocalStrings_en.properties @@ -53,8 +53,7 @@ form.scormmode.normal=Remember learning status in module fullwindow.label=Display only module, hide LMS header=Choose SCORM learning content headerform=Settings - - +ignore.in.course.assessment=$org.olat.course.nodes.ms\:ignore.in.course.assessment no.cp.chosen=<i>No SCORM learning content selected</i> pane.tab.cpconfig=Learning content pane.tab.delivery=$org.olat.core.gui.control.generic.iframe\:option.delivery diff --git a/src/main/java/org/olat/course/nodes/st/STCourseNodeEditController.java b/src/main/java/org/olat/course/nodes/st/STCourseNodeEditController.java index 62e22fdef9cd0d32952e70f63156e8d1a7a9198d..fb3b89e6a58c7f69ba8329cbb183448ff155d0e6 100644 --- a/src/main/java/org/olat/course/nodes/st/STCourseNodeEditController.java +++ b/src/main/java/org/olat/course/nodes/st/STCourseNodeEditController.java @@ -50,10 +50,13 @@ import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.condition.Condition; import org.olat.course.editor.CourseEditorHelper; import org.olat.course.editor.NodeEditController; import org.olat.course.highscore.ui.HighScoreEditController; +import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.STCourseNode; import org.olat.course.nodes.sp.SecuritySettingsForm; @@ -138,6 +141,8 @@ public class STCourseNodeEditController extends ActivateableTabbableDefaultContr @Autowired private CourseAssessmentService courseAssessmentService; + @Autowired + private NodeAccessService nodeAccessService; public STCourseNodeEditController(UserRequest ureq, WindowControl wControl, STCourseNode stNode, ICourse course, UserCourseEnvironment euce) { super(ureq, wControl); @@ -150,11 +155,7 @@ public class STCourseNodeEditController extends ActivateableTabbableDefaultContr Translator fallback = Util.createPackageTranslator(Condition.class, getLocale()); Translator newTranslator = Util.createPackageTranslator(STCourseNodeEditController.class, getLocale(), fallback); setTranslator(newTranslator); - - score = createVelocityContainer("scoreedit"); - activateEasyModeButton = LinkFactory.createButtonSmall("cmd.activate.easyMode", score, this); - activateExpertModeButton = LinkFactory.createButtonSmall("cmd.activate.expertMode", score, this); - + configvc = createVelocityContainer("config"); // type of display configuration: manual, auto, peekview etc nodeDisplayConfigFormController = new STCourseNodeDisplayConfigFormController(ureq, wControl, stNode.getModuleConfiguration(), editorModel.getCourseEditorNodeById(stNode.getIdent())); @@ -183,30 +184,37 @@ public class STCourseNodeEditController extends ActivateableTabbableDefaultContr // HighScore Controller highScoreNodeConfigController = new HighScoreEditController(ureq, wControl, stNode.getModuleConfiguration()); listenTo(highScoreNodeConfigController); - - ScoreCalculator scoreCalc = stNode.getScoreCalculator(); - if (scoreCalc != null) { - if (scoreCalc.isExpertMode() && scoreCalc.getPassedExpression() == null && scoreCalc.getScoreExpression() == null) { - scoreCalc = null; - } else if (!scoreCalc.isExpertMode() && scoreCalc.getPassedExpressionFromEasyModeConfiguration() == null - && scoreCalc.getScoreExpressionFromEasyModeConfiguration() == null) { - scoreCalc = null; + + + if (nodeAccessService.isScoreCalculatorSupported(NodeAccessType.of(course))) { + score = createVelocityContainer("scoreedit"); + activateEasyModeButton = LinkFactory.createButtonSmall("cmd.activate.easyMode", score, this); + activateExpertModeButton = LinkFactory.createButtonSmall("cmd.activate.expertMode", score, this); + + ScoreCalculator scoreCalc = stNode.getScoreCalculator(); + if (scoreCalc != null) { + if (scoreCalc.isExpertMode() && scoreCalc.getPassedExpression() == null && scoreCalc.getScoreExpression() == null) { + scoreCalc = null; + } else if (!scoreCalc.isExpertMode() && scoreCalc.getPassedExpressionFromEasyModeConfiguration() == null + && scoreCalc.getScoreExpressionFromEasyModeConfiguration() == null) { + scoreCalc = null; + } } - } - if (assessableChildren.isEmpty() && scoreCalc == null) { - // show only the no assessable children message, if no previous score - // config exists. - score.contextPut("noAssessableChildren", Boolean.TRUE); - } else { - score.contextPut("noAssessableChildren", Boolean.FALSE); - } + if (assessableChildren.isEmpty() && scoreCalc == null) { + // show only the no assessable children message, if no previous score + // config exists. + score.contextPut("noAssessableChildren", Boolean.TRUE); + } else { + score.contextPut("noAssessableChildren", Boolean.FALSE); + } - // Init score calculator form - if (scoreCalc != null && scoreCalc.isExpertMode()) { - initScoreExpertForm(ureq); - } else { - initScoreEasyForm(ureq); + // Init score calculator form + if (scoreCalc != null && scoreCalc.isExpertMode()) { + initScoreExpertForm(ureq); + } else { + initScoreEasyForm(ureq); + } } } @@ -421,14 +429,16 @@ public class STCourseNodeEditController extends ActivateableTabbableDefaultContr private void updateHighscoreTab() { AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(stNode); - myTabbedPane.setEnabled(highScoreTabPos, assessmentConfig.hasScore()); + myTabbedPane.setEnabled(highScoreTabPos, Mode.none != assessmentConfig.getScoreMode()); } @Override public void addTabs(TabbedPane tabbedPane) { myTabbedPane = tabbedPane; tabbedPane.addTab(translate(PANE_TAB_ST_CONFIG), configvc); - tabbedPane.addTab(translate(PANE_TAB_ST_SCORECALCULATION), score); + if (score != null) { + tabbedPane.addTab(translate(PANE_TAB_ST_SCORECALCULATION), score); + } highScoreTabPos = tabbedPane.addTab(translate(PANE_TAB_HIGHSCORE) , highScoreNodeConfigController.getInitialComponent()); updateHighscoreTab(); diff --git a/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java index eda6c76a0f16209a4323583e6a76d67598410d82..5f8d1cb374c5b7d9622a6d3c8408b0ee0118c833 100644 --- a/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java +++ b/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java @@ -49,6 +49,7 @@ import org.olat.core.util.nodes.INode; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.config.CourseConfig; import org.olat.course.highscore.ui.HighScoreRunController; import org.olat.course.nodeaccess.NodeAccessService; @@ -100,7 +101,9 @@ public class STCourseNodeRunController extends BasicController { myContent.setDomReplacementWrapperRequired(false); // we provide our own DOM replacement ID AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(stCourseNode); - if (se != null && (assessmentConfig.hasScore() || assessmentConfig.hasPassed())) { + boolean hasScore = Mode.none != assessmentConfig.getScoreMode(); + boolean hasPassed = Mode.none != assessmentConfig.getPassedMode(); + if (se != null && (hasScore || hasPassed)) { HighScoreRunController highScoreCtr = new HighScoreRunController(ureq, wControl, userCourseEnv, stCourseNode); if (highScoreCtr.isViewHighscore()) { Component highScoreComponent = highScoreCtr.getInitialComponent(); @@ -185,10 +188,10 @@ public class STCourseNodeRunController extends BasicController { myContent.contextPut("hasScore", Boolean.FALSE); myContent.contextPut("hasPassed", Boolean.FALSE); } else { - myContent.contextPut("hasScore", new Boolean(assessmentConfig.hasScore())); - myContent.contextPut("hasPassed", new Boolean(assessmentConfig.hasPassed())); + myContent.contextPut("hasScore", Boolean.valueOf(hasScore)); + myContent.contextPut("hasPassed", Boolean.valueOf(hasPassed)); - if(assessmentConfig.hasScore() || assessmentConfig.hasPassed()) { + if(hasScore|| hasPassed) { CourseConfig cc = userCourseEnv.getCourseEnvironment().getCourseConfig(); if((cc.isEfficencyStatementEnabled() || cc.isCertificateEnabled()) && userCourseEnv.hasEfficiencyStatementOrCertificate(false)) { diff --git a/src/main/java/org/olat/course/nodes/st/assessment/ConditionScoreEvaluator.java b/src/main/java/org/olat/course/nodes/st/assessment/ConditionScoreEvaluator.java index 2167f2cf61908476e8a8c77874168fdd82359795..fc9516ce144fcec12ef13d2d219097c88f7b9a0f 100644 --- a/src/main/java/org/olat/course/nodes/st/assessment/ConditionScoreEvaluator.java +++ b/src/main/java/org/olat/course/nodes/st/assessment/ConditionScoreEvaluator.java @@ -24,6 +24,7 @@ import org.olat.course.condition.interpreter.ConditionInterpreter; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.STCourseNode; import org.olat.course.run.scoring.AssessmentEvaluation; +import org.olat.course.run.scoring.ScoreAccounting; import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.scoring.ScoreEvaluator; @@ -37,7 +38,7 @@ public class ConditionScoreEvaluator implements ScoreEvaluator { @Override public Float getScore(AssessmentEvaluation currentEvaluation, CourseNode courseNode, - ConditionInterpreter conditionInterpreter) { + ScoreAccounting scoreAccounting, ConditionInterpreter conditionInterpreter) { ScoreCalculator scoreCalculator = getScoreCalculator(courseNode); if (scoreCalculator != null) { String scoreExpression = scoreCalculator.getScoreExpression(); diff --git a/src/main/java/org/olat/course/nodes/st/assessment/ConventionalSTCompletionEvaluator.java b/src/main/java/org/olat/course/nodes/st/assessment/ConventionalSTCompletionEvaluator.java index a91a38ab9d1503bb621621729b1d2df188bb9084..68761931152f7e22fe18af020e7939a3302d45ef 100644 --- a/src/main/java/org/olat/course/nodes/st/assessment/ConventionalSTCompletionEvaluator.java +++ b/src/main/java/org/olat/course/nodes/st/assessment/ConventionalSTCompletionEvaluator.java @@ -22,6 +22,7 @@ package org.olat.course.nodes.st.assessment; import org.olat.core.CoreSpringFactory; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.scoring.CompletionEvaluator; @@ -67,7 +68,7 @@ public class ConventionalSTCompletionEvaluator implements CompletionEvaluator { } private boolean isPassedConfigurated(AssessmentConfig assessmentConfig) { - return Boolean.TRUE.equals(assessmentConfig.hasPassed()); + return Mode.setByNode == assessmentConfig.getPassedMode(); } } diff --git a/src/main/java/org/olat/course/nodes/st/assessment/CumulatingScoreEvaluator.java b/src/main/java/org/olat/course/nodes/st/assessment/CumulatingScoreEvaluator.java new file mode 100644 index 0000000000000000000000000000000000000000..b99617ebffa815229b1b12b7ba1aaa984ee5f95a --- /dev/null +++ b/src/main/java/org/olat/course/nodes/st/assessment/CumulatingScoreEvaluator.java @@ -0,0 +1,126 @@ +/** + * <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.course.nodes.st.assessment; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.util.nodes.INode; +import org.olat.core.util.tree.TreeVisitor; +import org.olat.core.util.tree.Visitor; +import org.olat.course.assessment.CourseAssessmentService; +import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; +import org.olat.course.condition.interpreter.ConditionInterpreter; +import org.olat.course.nodes.CourseNode; +import org.olat.course.run.scoring.AssessmentEvaluation; +import org.olat.course.run.scoring.ScoreAccounting; +import org.olat.course.run.scoring.ScoreEvaluator; + +/** + * + * Initial date: 9 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +class CumulatingScoreEvaluator implements ScoreEvaluator { + + public interface Score { + + public Float getSum(); + + public Float getAverage(); + } + + private final boolean average; + + private CourseAssessmentService courseAssessmentService; + + CumulatingScoreEvaluator(boolean average) { + this.average = average; + } + + @Override + public Float getScore(AssessmentEvaluation currentEvaluation, CourseNode courseNode, + ScoreAccounting scoreAccounting, ConditionInterpreter conditionInterpreter) { + Score score = getScore(courseNode, scoreAccounting, courseAssessmentService()); + return average? score.getAverage(): score.getSum(); + } + + Score getScore(CourseNode courseNode, ScoreAccounting scoreAccounting, CourseAssessmentService courseAssessmentService) { + ScoreVisitor visitor = new ScoreVisitor(courseNode, scoreAccounting, courseAssessmentService); + TreeVisitor treeVisitor = new TreeVisitor(visitor, courseNode, true); + treeVisitor.visitAll(); + return visitor; + } + + private CourseAssessmentService courseAssessmentService() { + if (courseAssessmentService== null) { + courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); + } + return courseAssessmentService; + } + + private final static class ScoreVisitor implements Score, Visitor { + + private final CourseNode root; + private final ScoreAccounting scoreAccounting; + private float sum; + private int count; + + private final CourseAssessmentService courseAssessmentService; + + private ScoreVisitor(CourseNode root, ScoreAccounting scoreAccounting, CourseAssessmentService courseAssessmentService) { + this.root = root; + this.scoreAccounting = scoreAccounting; + this.courseAssessmentService = courseAssessmentService; + } + + @Override + public Float getSum() { + return count > 0? Float.valueOf(sum): null; + } + + @Override + public Float getAverage() { + return count > 0? Float.valueOf(sum / count): null; + } + + @Override + public void visit(INode node) { + if (node.getIdent().equals(root.getIdent())) return; + + if (node instanceof CourseNode) { + CourseNode courseNode = (CourseNode)node; + AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); + if (Mode.setByNode == assessmentConfig.getScoreMode() && !assessmentConfig.ignoreInCourseAssessment()) { + AssessmentEvaluation assessmentEvaluation = scoreAccounting.evalCourseNode(courseNode); + Boolean userVisible = assessmentEvaluation.getUserVisible(); + if (userVisible != null && userVisible.booleanValue()) { + Float score = assessmentEvaluation.getScore(); + if (score != null) { + sum += score.floatValue(); + count++; + } + } + } + } + } + } + +} diff --git a/src/main/java/org/olat/course/nodes/st/assessment/PassCounter.java b/src/main/java/org/olat/course/nodes/st/assessment/PassCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..9d2b675f74da200b08ce8efbfe8229426574a6e7 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/st/assessment/PassCounter.java @@ -0,0 +1,135 @@ +/** + * <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.course.nodes.st.assessment; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.util.nodes.INode; +import org.olat.core.util.tree.TreeVisitor; +import org.olat.core.util.tree.Visitor; +import org.olat.course.assessment.CourseAssessmentService; +import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; +import org.olat.course.nodes.CourseNode; +import org.olat.course.run.scoring.AssessmentEvaluation; +import org.olat.course.run.scoring.ScoreAccounting; + +/** + * + * Initial date: 13 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class PassCounter { + + public interface Counts { + + public int getPassable(); + + public int getPassed(); + + public int getFailed(); + + public boolean isAllAssessed(); + } + + private CourseAssessmentService courseAssessmentService; + + public Counts getCounts(CourseNode courseNode, ScoreAccounting scoreAccounting) { + return getCounts(courseNode, scoreAccounting, getCourseAssessmentService()); + } + + Counts getCounts(CourseNode courseNode, ScoreAccounting scoreAccounting, CourseAssessmentService courseAssessmentService) { + PassedCountVisitor visitor = new PassedCountVisitor(courseNode, scoreAccounting, courseAssessmentService); + TreeVisitor treeVisitor = new TreeVisitor(visitor, courseNode, true); + treeVisitor.visitAll(); + return visitor; + } + + private CourseAssessmentService getCourseAssessmentService() { + if (courseAssessmentService == null) { + courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); + } + return courseAssessmentService; + } + + private final static class PassedCountVisitor implements Counts, Visitor { + + private final CourseNode root; + private final ScoreAccounting scoreAccounting; + private int passable; + private int passed; + private int failed; + + private final CourseAssessmentService courseAssessmentService; + + private PassedCountVisitor(CourseNode root, ScoreAccounting scoreAccounting, CourseAssessmentService courseAssessmentService) { + this.root = root; + this.scoreAccounting = scoreAccounting; + this.courseAssessmentService = courseAssessmentService; + } + + @Override + public int getPassable() { + return passable; + } + + @Override + public int getPassed() { + return passed; + } + + @Override + public int getFailed() { + return failed; + } + + @Override + public boolean isAllAssessed() { + return passable == passed + failed; + } + + @Override + public void visit(INode node) { + if (node.getIdent().equals(root.getIdent())) return; + + if (node instanceof CourseNode) { + CourseNode courseNode = (CourseNode)node; + AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); + if (Mode.setByNode == assessmentConfig.getPassedMode() && !assessmentConfig.ignoreInCourseAssessment()) { + passable++; + AssessmentEvaluation assessmentEvaluation = scoreAccounting.evalCourseNode(courseNode); + Boolean userVisible = assessmentEvaluation.getUserVisible(); + if (userVisible != null && userVisible.booleanValue()) { + Boolean nodePassed = assessmentEvaluation.getPassed(); + if (nodePassed != null) { + if (nodePassed) { + passed++; + } else { + failed++; + } + } + } + } + } + } + + } + +} diff --git a/src/main/java/org/olat/course/nodes/st/assessment/STAssessmentConfig.java b/src/main/java/org/olat/course/nodes/st/assessment/STAssessmentConfig.java index a22e7cd14e96f138584c5bf3fe4778d6775be1c7..fdb8b368f66e7d6f958d89192c475ce036feb776 100644 --- a/src/main/java/org/olat/course/nodes/st/assessment/STAssessmentConfig.java +++ b/src/main/java/org/olat/course/nodes/st/assessment/STAssessmentConfig.java @@ -21,7 +21,9 @@ package org.olat.course.nodes.st.assessment; import org.olat.core.util.StringHelper; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.nodes.STCourseNode; import org.olat.course.run.scoring.ScoreCalculator; +import org.olat.modules.ModuleConfiguration; /** * @@ -31,9 +33,13 @@ import org.olat.course.run.scoring.ScoreCalculator; */ public class STAssessmentConfig implements AssessmentConfig { + private final boolean isRoot; + private final ModuleConfiguration rootConfig; private final ScoreCalculator scoreCalculator; - public STAssessmentConfig(ScoreCalculator scoreCalculator) { + public STAssessmentConfig(boolean isRoot, ModuleConfiguration rootConfig, ScoreCalculator scoreCalculator) { + this.isRoot = isRoot; + this.rootConfig = rootConfig; this.scoreCalculator = scoreCalculator; } @@ -43,8 +49,13 @@ public class STAssessmentConfig implements AssessmentConfig { } @Override - public boolean isEvaluationPersisted() { - return true; + public boolean ignoreInCourseAssessment() { + return false; + } + + @Override + public void setIgnoreInCourseAssessment(boolean ignoreInCourseAssessment) { + // } @Override @@ -53,11 +64,13 @@ public class STAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasScore() { + public Mode getScoreMode() { if (scoreCalculator != null && StringHelper.containsNonWhitespace(scoreCalculator.getScoreExpression())) { - return true; + return Mode.evaluated; + } else if (rootConfig.has(STCourseNode.CONFIG_SCORE_KEY)) { + return Mode.evaluated; } - return false; + return Mode.none; } @Override @@ -71,11 +84,21 @@ public class STAssessmentConfig implements AssessmentConfig { } @Override - public boolean hasPassed() { + public Mode getPassedMode() { if (scoreCalculator != null && StringHelper.containsNonWhitespace(scoreCalculator.getPassedExpression())) { - return true; + return Mode.evaluated; + } else if (isEvaluatedRoot()) { + return Mode.evaluated; } - return false; + return Mode.none; + } + + private boolean isEvaluatedRoot() { + return isRoot && ( + rootConfig.has(STCourseNode.CONFIG_PASSED_PROGRESS) + || rootConfig.has(STCourseNode.CONFIG_PASSED_ALL) + || rootConfig.has(STCourseNode.CONFIG_PASSED_POINTS) + ); } @Override diff --git a/src/main/java/org/olat/course/nodes/st/assessment/STAssessmentHandler.java b/src/main/java/org/olat/course/nodes/st/assessment/STAssessmentHandler.java index 8c9c2506658f162d1bde1c0f25967931f1480f1b..b2f1851f6e2194959a84fa87da61f8b55715caca 100644 --- a/src/main/java/org/olat/course/nodes/st/assessment/STAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/st/assessment/STAssessmentHandler.java @@ -28,12 +28,12 @@ import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.id.Identity; +import org.olat.core.util.nodes.INode; import org.olat.course.assessment.AssessmentManager; import org.olat.course.assessment.handler.AssessmentConfig; import org.olat.course.assessment.handler.AssessmentHandler; import org.olat.course.assessment.handler.NonAssessmentConfig; import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController; -import org.olat.course.condition.interpreter.ConditionInterpreter; import org.olat.course.config.CompletionType; import org.olat.course.config.CourseConfig; import org.olat.course.learningpath.manager.LearningPathNodeAccessProvider; @@ -42,7 +42,6 @@ import org.olat.course.nodes.STCourseNode; import org.olat.course.nodes.st.STIdentityListCourseNodeController; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; import org.olat.course.run.scoring.AverageCompletionEvaluator; import org.olat.course.run.scoring.BlockerEvaluator; import org.olat.course.run.scoring.CompletionEvaluator; @@ -50,11 +49,13 @@ import org.olat.course.run.scoring.FullyAssessedEvaluator; import org.olat.course.run.scoring.LastModificationsEvaluator; import org.olat.course.run.scoring.ObligationEvaluator; import org.olat.course.run.scoring.PassedEvaluator; +import org.olat.course.run.scoring.RootPassedEvaluator; import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.scoring.ScoreEvaluator; import org.olat.course.run.scoring.StatusEvaluator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; +import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.ui.AssessmentToolContainer; import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback; @@ -75,7 +76,10 @@ public class STAssessmentHandler implements AssessmentHandler { private static final ObligationEvaluator MANDATORY_OBLIGATION_EVALUATOR = new MandatoryObligationEvaluator(); private static final CumulatingDurationEvaluator CUMULATION_DURATION_EVALUATOR = new CumulatingDurationEvaluator(); private static final ScoreEvaluator CONDITION_SCORE_EVALUATOR = new ConditionScoreEvaluator(); + private static final ScoreEvaluator SUM_SCORE_EVALUATOR = new CumulatingScoreEvaluator(false); + private static final ScoreEvaluator AVG_SCORE_EVALUATOR = new CumulatingScoreEvaluator(true); private static final PassedEvaluator CONDITION_PASSED_EVALUATOR = new ConditionPassedEvaluator(); + private static final RootPassedEvaluator ROOT_PASSED_EVALUATOR = new STRootPassedEvaluator(); private static final StatusEvaluator SCORE_STATUS_EVALUATOR = new ScoreStatusEvaluator(); private static final StatusEvaluator LEARNING_PATH_STATUS_EVALUATOR = new STStatusEvaluator(); private static final FullyAssessedEvaluator FULLY_ASSESSED_EVALUATOR = new STFullyAssessedEvaluator(); @@ -90,10 +94,32 @@ public class STAssessmentHandler implements AssessmentHandler { public AssessmentConfig getAssessmentConfig(CourseNode courseNode) { if (courseNode instanceof STCourseNode) { STCourseNode stCourseNode = (STCourseNode) courseNode; - return new STAssessmentConfig(stCourseNode.getScoreCalculator()); + STCourseNode root = getRoot(courseNode); + boolean isRoot = courseNode.getIdent().equals(root.getIdent()); + ScoreCalculator scoreCalclualtor = root.getModuleConfiguration().getBooleanSafe(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED) + ? stCourseNode.getScoreCalculator() + : null; + return new STAssessmentConfig(isRoot, root.getModuleConfiguration(), scoreCalclualtor); } return NonAssessmentConfig.create(); } + + private STCourseNode getRoot(INode node) { + STCourseNode root = null; + if (node instanceof STCourseNode) { + root = (STCourseNode)node; + } + + INode parent = node.getParent(); + if (parent != null) { + STCourseNode parentRoot = getRoot(parent); + if (parentRoot != null) { + root = parentRoot; + } + } + + return root; + } @Override public AssessmentEntry getAssessmentEntry(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) { @@ -108,21 +134,35 @@ public class STAssessmentHandler implements AssessmentHandler { AccountingEvaluatorsBuilder builder = AccountingEvaluatorsBuilder.builder() .withObligationEvaluator(MANDATORY_OBLIGATION_EVALUATOR) .withDurationEvaluator(CUMULATION_DURATION_EVALUATOR) - .withScoreEvaluator(CONDITION_SCORE_EVALUATOR) .withPassedEvaluator(CONDITION_PASSED_EVALUATOR) .withStatusEvaluator(LEARNING_PATH_STATUS_EVALUATOR) .withFullyAssessedEvaluator(FULLY_ASSESSED_EVALUATOR) - .withLastModificationsEvaluator(LAST_MODIFICATION_EVALUATOR); + .withLastModificationsEvaluator(LAST_MODIFICATION_EVALUATOR) + .withRootPassedEvaluator(ROOT_PASSED_EVALUATOR); CompletionEvaluator completionEvaluator = CompletionType.duration.equals(courseConfig.getCompletionType()) ? new AverageCompletionEvaluator(DURATION_WEIGHTED) : new AverageCompletionEvaluator(UNWEIGHTED); builder.withCompletionEvaluator(completionEvaluator); - String sequenceKey = courseNode.getModuleConfiguration().getStringValue(STCourseNode.CONFIG_LP_SEQUENCE_KEY, STCourseNode.CONFIG_LP_SEQUENCE_DEFAULT); + + ModuleConfiguration moduleConfig = courseNode.getModuleConfiguration(); + String sequenceKey = moduleConfig.getStringValue(STCourseNode.CONFIG_LP_SEQUENCE_KEY, STCourseNode.CONFIG_LP_SEQUENCE_DEFAULT); if (STCourseNode.CONFIG_LP_SEQUENCE_VALUE_SEQUENTIAL.equals(sequenceKey)) { builder.withBlockerEvaluator(SEQUENTIAL_BLOCKER_EVALUATOR); } else { builder.withBlockerEvaluator(WITHOUT_SEQUENCE_BLOCKER_EVALUATOR); } + + ModuleConfiguration rootConfig = getRoot(courseNode).getModuleConfiguration(); + if (rootConfig.has(STCourseNode.CONFIG_SCORE_KEY)) { + String scoreKey = rootConfig.getStringValue(STCourseNode.CONFIG_SCORE_KEY); + if (STCourseNode.CONFIG_SCORE_VALUE_SUM.equals(scoreKey)) { + builder.withScoreEvaluator(SUM_SCORE_EVALUATOR); + } else if (STCourseNode.CONFIG_SCORE_VALUE_AVG.equals(scoreKey)) { + builder.withScoreEvaluator(AVG_SCORE_EVALUATOR); + } + } else { + builder.withNullScoreEvaluator(); + } return builder.build(); } return AccountingEvaluatorsBuilder.builder() @@ -134,39 +174,6 @@ public class STAssessmentHandler implements AssessmentHandler { .build(); } - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) { - ScoreCalculator scoreCalculator = getScoreCalculator(courseNode); - if (scoreCalculator == null) { - // this is a not-computable course node at the moment (no scoring/passing rules defined) - return null; - } - - Float score = null; - Boolean passed = null; - - String scoreExpressionStr = scoreCalculator.getScoreExpression(); - String passedExpressionStr = scoreCalculator.getPassedExpression(); - - ConditionInterpreter ci = userCourseEnvironment.getConditionInterpreter(); - if (scoreExpressionStr != null) { - score = new Float(ci.evaluateCalculation(scoreExpressionStr)); - } - if (passedExpressionStr != null) { - passed = new Boolean(ci.evaluateCondition(passedExpressionStr)); - } - return new AssessmentEvaluation(score, passed); - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - if (courseNode instanceof STCourseNode) { - STCourseNode stCourseNode = (STCourseNode) courseNode; - return stCourseNode.getScoreCalculator(); - } - return null; - } - @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, CourseNode courseNode, UserCourseEnvironment coachCourseEnv, UserCourseEnvironment assessedUserCourseEnv) { diff --git a/src/main/java/org/olat/course/nodes/st/assessment/STLearningPathNodeHandler.java b/src/main/java/org/olat/course/nodes/st/assessment/STLearningPathNodeHandler.java index 14bbdd37b4de1ec9649f3d7034a6f1bcd7de05db..cbd5470599f9cc6b5be45656b5990902cc0106dc 100644 --- a/src/main/java/org/olat/course/nodes/st/assessment/STLearningPathNodeHandler.java +++ b/src/main/java/org/olat/course/nodes/st/assessment/STLearningPathNodeHandler.java @@ -27,6 +27,7 @@ import org.olat.course.learningpath.LearningPathEditConfigs; import org.olat.course.learningpath.LearningPathNodeHandler; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.STCourseNode; +import org.olat.modules.ModuleConfiguration; import org.olat.repository.RepositoryEntry; import org.springframework.stereotype.Service; @@ -67,7 +68,16 @@ public class STLearningPathNodeHandler implements LearningPathNodeHandler { @Override public void onMigrated(CourseNode courseNode) { - // + if (courseNode instanceof STCourseNode) { + STCourseNode stCourseNode = (STCourseNode)courseNode; + ModuleConfiguration config = stCourseNode.getModuleConfiguration(); + config.setBooleanEntry(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED, false); + stCourseNode.setScoreCalculator(null); + if (stCourseNode.getParent() == null) { + config.setStringValue(STCourseNode.CONFIG_SCORE_KEY, STCourseNode.CONFIG_SCORE_VALUE_SUM); + config.setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + } + } } } diff --git a/src/main/java/org/olat/course/nodes/st/assessment/STRootPassedEvaluator.java b/src/main/java/org/olat/course/nodes/st/assessment/STRootPassedEvaluator.java new file mode 100644 index 0000000000000000000000000000000000000000..0ab5e9ea8aa74f545e06ab242805ba4c1157b81f --- /dev/null +++ b/src/main/java/org/olat/course/nodes/st/assessment/STRootPassedEvaluator.java @@ -0,0 +1,132 @@ +/** + * <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.course.nodes.st.assessment; + +import java.util.Date; + +import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.STCourseNode; +import org.olat.course.nodes.st.assessment.PassCounter.Counts; +import org.olat.course.run.scoring.AssessmentEvaluation; +import org.olat.course.run.scoring.RootPassedEvaluator; +import org.olat.course.run.scoring.ScoreAccounting; +import org.olat.modules.ModuleConfiguration; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 13 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class STRootPassedEvaluator implements RootPassedEvaluator { + + private final PassCounter passCounter; + + public STRootPassedEvaluator() { + this(new PassCounter()); + } + + STRootPassedEvaluator(PassCounter passCounter) { + this.passCounter = passCounter; + } + + @Override + public Boolean getPassed(AssessmentEvaluation currentEvaluation, CourseNode courseNode, + ScoreAccounting scoreAccounting, RepositoryEntry courseEntry) { + //TODO uh wenn es überschieben ist => nicht ändern + + Boolean currentPassed = currentEvaluation.getPassed(); + if (currentPassed != null && currentPassed.booleanValue()) { + // Never reset a passed course to null or failed + return currentPassed; + } + + ModuleConfiguration config = courseNode.getModuleConfiguration(); + + // Progress + if (config.getBooleanSafe(STCourseNode.CONFIG_PASSED_PROGRESS)) { + Boolean fullyAssessed = currentEvaluation.getFullyAssessed(); + if (fullyAssessed != null && fullyAssessed.booleanValue()) { + return Boolean.TRUE; + } + } + + // Points + if (config.getBooleanSafe(STCourseNode.CONFIG_PASSED_POINTS)) { + Float score = currentEvaluation.getScore(); + if (score != null) { + int cutvalue = config.getIntegerSafe(STCourseNode.CONFIG_PASSED_POINTS_CUT, Integer.MAX_VALUE); + if (score.floatValue() >= cutvalue) { + return Boolean.TRUE; + } + } + } + + // All passed + if (config.getBooleanSafe(STCourseNode.CONFIG_PASSED_ALL)) { + Counts counts = passCounter.getCounts(courseNode, scoreAccounting); + if (counts.isAllAssessed() && counts.getPassable() > 0) { + if (counts.getPassable() == counts.getPassed()) { + return Boolean.TRUE; + } else if (getActivePassedConfigs(config) == 1) { + return Boolean.FALSE; + } + } + } + + if (currentPassed == null && getActivePassedConfigs(config) > 0) { + Counts counts = passCounter.getCounts(courseNode, scoreAccounting); + if (counts.getPassable() > 0) { + + // Failed if course is fully assessed + Boolean fullyAssessed = currentEvaluation.getFullyAssessed(); + if (fullyAssessed != null && fullyAssessed.booleanValue()) { + return Boolean.FALSE; + } + + // Failed if course end date is over + if (courseEntry != null && courseEntry.getLifecycle() != null && courseEntry.getLifecycle().getValidTo() != null) { + Date validTo = courseEntry.getLifecycle().getValidTo(); + if (validTo.before(new Date())) { + return Boolean.FALSE; + } + } + } + } + + return currentPassed; + } + + private int getActivePassedConfigs(ModuleConfiguration config) { + int active = 0; + if (config.has(STCourseNode.CONFIG_PASSED_PROGRESS)) { + active++; + } + if (config.has(STCourseNode.CONFIG_PASSED_ALL)) { + active++; + } + if (config.has(STCourseNode.CONFIG_PASSED_POINTS)) { + active++; + } + return active; + } + +} diff --git a/src/main/java/org/olat/course/nodes/ta/TAAssessmentConfig.java b/src/main/java/org/olat/course/nodes/ta/TAAssessmentConfig.java index 8b45fa132ee56ca5e5bd17702181b8ab971a8097..88448c03f705cb9344958219dd3b4818e4cb46f1 100644 --- a/src/main/java/org/olat/course/nodes/ta/TAAssessmentConfig.java +++ b/src/main/java/org/olat/course/nodes/ta/TAAssessmentConfig.java @@ -39,17 +39,17 @@ public class TAAssessmentConfig extends ModuleAssessmentConfig { } @Override - public boolean hasScore() { - if (hasNoScoring) return false; + public Mode getScoreMode() { + if (hasNoScoring) return Mode.none; - return super.hasScore(); + return super.getScoreMode(); } @Override - public boolean hasPassed() { - if (hasNoScoring) return false; + public Mode getPassedMode() { + if (hasNoScoring) return Mode.none; - return super.hasPassed(); + return super.getPassedMode(); } @Override diff --git a/src/main/java/org/olat/course/nodes/ta/TAAssessmentHandler.java b/src/main/java/org/olat/course/nodes/ta/TAAssessmentHandler.java index cb1749c58b178d0d9fd021b0f3308a90a9412edb..a867e5ec23884acf33e66e7abc9cfb84168fe210 100644 --- a/src/main/java/org/olat/course/nodes/ta/TAAssessmentHandler.java +++ b/src/main/java/org/olat/course/nodes/ta/TAAssessmentHandler.java @@ -36,8 +36,6 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.TACourseNode; import org.olat.course.run.scoring.AccountingEvaluators; import org.olat.course.run.scoring.AccountingEvaluatorsBuilder; -import org.olat.course.run.scoring.AssessmentEvaluation; -import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.modules.assessment.AssessmentEntry; @@ -81,17 +79,6 @@ public class TAAssessmentHandler implements AssessmentHandler { return AccountingEvaluatorsBuilder.defaultConventional(); } - @Override - public AssessmentEvaluation getCalculatedScoreEvaluation(CourseNode courseNode, - UserCourseEnvironment userCourseEnvironment) { - return null; - } - - @Override - public ScoreCalculator getScoreCalculator(CourseNode courseNode) { - return null; - } - @Override public Controller getDetailsEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, CourseNode courseNode, UserCourseEnvironment coachCourseEnv, UserCourseEnvironment assessedUserCourseEnv) { diff --git a/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java b/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java index eac28869e572415c9795d4acc79a082148241c35..b4ec323b8410766f4aca20220a6c6c112310a52b 100644 --- a/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java +++ b/src/main/java/org/olat/course/nodes/ta/TACourseNodeEditController.java @@ -79,6 +79,7 @@ import org.olat.course.auditing.UserNodeAuditManager; import org.olat.course.condition.Condition; import org.olat.course.condition.ConditionEditController; import org.olat.course.editor.NodeEditController; +import org.olat.course.nodeaccess.NodeAccessType; import org.olat.course.nodes.TACourseNode; import org.olat.course.nodes.ms.MSCourseNodeEditController; import org.olat.course.nodes.ms.MSEditFormController; @@ -244,7 +245,7 @@ public class TACourseNodeEditController extends ActivateableTabbableDefaultContr editScoring = this.createVelocityContainer("editScoring"); editScoringConfigButton = LinkFactory.createButtonSmall("scoring.config.enable.button", editScoring, this); - scoringController = new MSEditFormController(ureq, wControl, config); + scoringController = new MSEditFormController(ureq, wControl, config, NodeAccessType.of(course)); listenTo(scoringController); editScoring.put("scoringController", scoringController.getInitialComponent()); @@ -571,6 +572,7 @@ public class TACourseNodeEditController extends ActivateableTabbableDefaultContr /** * @see org.olat.core.gui.control.generic.tabbable.TabbableController#addTabs(org.olat.core.gui.components.TabbedPane) */ + @Override public void addTabs(TabbedPane theTabbedPane) { this.myTabbedPane = theTabbedPane; myTabbedPane.addTab(translate(PANE_TAB_ACCESSIBILITY), accessabilityVC); diff --git a/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java index cf03763453bc70358013dab6a943d898beab58f2..ec252b7e4b9bb781345d3bde1fbe5b5816a3e235 100644 --- a/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java +++ b/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java @@ -33,6 +33,7 @@ import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.export.CourseEnvironmentMapper; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.STCourseNode; @@ -103,7 +104,7 @@ public class PassedRuleSPI implements FilterRuleSPI { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if(assessmentConfig.hasPassed()) { + if(Mode.none != assessmentConfig.getPassedMode()) { for(Identity identity:identities) { UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course); ScoreEvaluation scoreEval = courseAssessmentService.getAssessmentEvaluation(courseNode, uce); diff --git a/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java index 497859a8f029ca5366a83c0c7988f2e6cc76eb80..34994ea07ba63870b8849191f68af1e929be9d54 100644 --- a/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java +++ b/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java @@ -33,6 +33,7 @@ import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.export.CourseEnvironmentMapper; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.STCourseNode; @@ -105,7 +106,7 @@ public class ScoreRuleSPI implements FilterRuleSPI { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if(assessmentConfig.hasScore()) { + if(Mode.none != assessmentConfig.getScoreMode()) { for(Identity identity:identities) { UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course); ScoreEvaluation scoreEval = courseAssessmentService.getAssessmentEvaluation(courseNode, uce); diff --git a/src/main/java/org/olat/course/reminder/ui/PassedRuleEditor.java b/src/main/java/org/olat/course/reminder/ui/PassedRuleEditor.java index fbd90e9c32bad49a4f606033217a0d2c9d17e210..c0e56cec5f496a73f52eae2613670cc0efc8be11 100644 --- a/src/main/java/org/olat/course/reminder/ui/PassedRuleEditor.java +++ b/src/main/java/org/olat/course/reminder/ui/PassedRuleEditor.java @@ -37,6 +37,7 @@ import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.course.reminder.rule.PassedRuleSPI; import org.olat.modules.reminder.ReminderRule; @@ -142,7 +143,7 @@ public class PassedRuleEditor extends RuleEditorFragment { private void searchPassedNodes(CourseNode courseNode, List<CourseNode> nodes) { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if (assessmentConfig.hasPassed()) { + if (Mode.none != assessmentConfig.getPassedMode()) { nodes.add(courseNode); } diff --git a/src/main/java/org/olat/course/reminder/ui/ScoreRuleEditor.java b/src/main/java/org/olat/course/reminder/ui/ScoreRuleEditor.java index b67e30bd666783d2d1d64cb0a7e1702e913bb4ed..a8dc1c42b5616b67047935a40aa39750d6795cbf 100644 --- a/src/main/java/org/olat/course/reminder/ui/ScoreRuleEditor.java +++ b/src/main/java/org/olat/course/reminder/ui/ScoreRuleEditor.java @@ -37,6 +37,7 @@ import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.course.reminder.rule.ScoreRuleSPI; import org.olat.modules.reminder.ReminderRule; @@ -145,7 +146,7 @@ public class ScoreRuleEditor extends RuleEditorFragment { private void searchScoreableNodes(CourseNode courseNode, List<CourseNode> nodes) { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if (assessmentConfig.hasScore()) { + if (Mode.none != assessmentConfig.getScoreMode()) { nodes.add(courseNode); } diff --git a/src/main/java/org/olat/course/run/scoring/AccountingEvaluators.java b/src/main/java/org/olat/course/run/scoring/AccountingEvaluators.java index 637bf93e27bb97097c0f8a85e92466b1f0a3204a..81916dfbdc0d7aca3e24bad81e9b359fb94b8325 100644 --- a/src/main/java/org/olat/course/run/scoring/AccountingEvaluators.java +++ b/src/main/java/org/olat/course/run/scoring/AccountingEvaluators.java @@ -41,6 +41,8 @@ public interface AccountingEvaluators { public PassedEvaluator getPassedEvaluator(); + public RootPassedEvaluator getRootPassedEvaluator(); + public LastModificationsEvaluator getLastModificationsEvaluator(); public CompletionEvaluator getCompletionEvaluator(); diff --git a/src/main/java/org/olat/course/run/scoring/AccountingEvaluatorsBuilder.java b/src/main/java/org/olat/course/run/scoring/AccountingEvaluatorsBuilder.java index 7b6dc5ef30a583d1989f63e92623e638733b68c4..8ba8f1a0754c07e712a3afd842419447772c9dfe 100644 --- a/src/main/java/org/olat/course/run/scoring/AccountingEvaluatorsBuilder.java +++ b/src/main/java/org/olat/course/run/scoring/AccountingEvaluatorsBuilder.java @@ -35,6 +35,7 @@ public class AccountingEvaluatorsBuilder { .withDurationEvaluator(AccountingEvaluatorsFactory.createNullDurationEvaluator()) .withScoreEvaluator(AccountingEvaluatorsFactory.createUnchangingScoreEvaluator()) .withPassedEvaluator(AccountingEvaluatorsFactory.createUnchangingPassedEvaluator()) + .withRootPassedEvaluator(AccountingEvaluatorsFactory.createUnchangingRootPassedEvaluator()) .withCompletionEvaluator(AccountingEvaluatorsFactory.createUnchangingCompletionEvaluator()) .withStatusEvaluator(AccountingEvaluatorsFactory.createUnchangingStatusEvaluator()) .withFullyAssessedEvaluator(AccountingEvaluatorsFactory.createUnchangingFullyAssessedEvaluator()) @@ -48,6 +49,7 @@ public class AccountingEvaluatorsBuilder { private DurationEvaluator durationEvaluator; private ScoreEvaluator scoreEvaluator; private PassedEvaluator passedEvaluator; + private RootPassedEvaluator rootPassedEvaluator; private CompletionEvaluator completionEvaluator; private StatusEvaluator statusEvaluator; private FullyAssessedEvaluator fullyAssessedEvaluator; @@ -86,12 +88,22 @@ public class AccountingEvaluatorsBuilder { this.scoreEvaluator = scoreEvaluator; return this; } + + public AccountingEvaluatorsBuilder withNullScoreEvaluator() { + this.scoreEvaluator = AccountingEvaluatorsFactory.createNullScoreEvaluator(); + return this; + } public AccountingEvaluatorsBuilder withPassedEvaluator(PassedEvaluator passedEvaluator) { this.passedEvaluator = passedEvaluator; return this; } + public AccountingEvaluatorsBuilder withRootPassedEvaluator(RootPassedEvaluator rootPassedEvaluator) { + this.rootPassedEvaluator = rootPassedEvaluator; + return this; + } + public AccountingEvaluatorsBuilder withCompletionEvaluator(CompletionEvaluator completionEvaluator) { this.completionEvaluator = completionEvaluator; return this; @@ -135,6 +147,9 @@ public class AccountingEvaluatorsBuilder { impl.passedEvaluator = this.passedEvaluator != null ? this.passedEvaluator : AccountingEvaluatorsFactory.createUnchangingPassedEvaluator(); + impl.rootPassedEvaluator = this.rootPassedEvaluator != null + ? this.rootPassedEvaluator + : AccountingEvaluatorsFactory.createUnchangingRootPassedEvaluator(); impl.completionEvaluator = this.completionEvaluator != null ? this.completionEvaluator : AccountingEvaluatorsFactory.createUnchangingCompletionEvaluator(); @@ -167,6 +182,7 @@ public class AccountingEvaluatorsBuilder { private DurationEvaluator durationEvaluator; private ScoreEvaluator scoreEvaluator; private PassedEvaluator passedEvaluator; + private RootPassedEvaluator rootPassedEvaluator; private CompletionEvaluator completionEvaluator; private StatusEvaluator statusEvaluator; private FullyAssessedEvaluator fullyAssessedEvaluator; @@ -206,6 +222,11 @@ public class AccountingEvaluatorsBuilder { public PassedEvaluator getPassedEvaluator() { return passedEvaluator; } + + @Override + public RootPassedEvaluator getRootPassedEvaluator() { + return rootPassedEvaluator; + } @Override public CompletionEvaluator getCompletionEvaluator() { diff --git a/src/main/java/org/olat/course/run/scoring/AccountingEvaluatorsFactory.java b/src/main/java/org/olat/course/run/scoring/AccountingEvaluatorsFactory.java index b0afdf7569f83f9cdf675cf26dc353bdc18c6f30..14c852e0afe6ddf6573f174ce1ad29a936df3cba 100644 --- a/src/main/java/org/olat/course/run/scoring/AccountingEvaluatorsFactory.java +++ b/src/main/java/org/olat/course/run/scoring/AccountingEvaluatorsFactory.java @@ -44,7 +44,9 @@ class AccountingEvaluatorsFactory { private static final ObligationEvaluator NONE_OBLIGATION_EVALUATOR = new NoneObligationEvaluator(); private static final DurationEvaluator NULL_DURATION_EVALUATOR = new NullDurationEvaluator(); private static final ScoreEvaluator UNCHANGING_SCORE_EVALUATOR = new UnchangingScoreEvaluator(); + private static final ScoreEvaluator NULL_SCORE_EVALUATOR = new NullScoreEvaluator(); private static final PassedEvaluator UNCHANGING_PASSED_EVALUATOR = new UnchangingPassedEvaluator(); + private static final RootPassedEvaluator UNCHANGING_ROOT_PASSED_EVALUATOR = new UnchangingRootPassedEvaluator(); private static final CompletionEvaluator UNCHANGING_COMPLETION_EVALUATOR = new UnchangingCompletionEvaluator(); private static final StatusEvaluator UNCHANGING_STATUS_EVALUATOR = new UnchangingStatusEvaluator(); private static final FullyAssessedEvaluator UNCHANGING_FULLY_ASSESSED_EVALUATOR = new UnchangingFullyAssessedEvaluator(); @@ -65,6 +67,7 @@ class AccountingEvaluatorsFactory { static ObligationEvaluator createNoneObligationEvaluator() { return NONE_OBLIGATION_EVALUATOR; } + static DurationEvaluator createNullDurationEvaluator() { return NULL_DURATION_EVALUATOR; } @@ -73,10 +76,18 @@ class AccountingEvaluatorsFactory { return UNCHANGING_SCORE_EVALUATOR; } + static ScoreEvaluator createNullScoreEvaluator() { + return NULL_SCORE_EVALUATOR; + } + static PassedEvaluator createUnchangingPassedEvaluator() { return UNCHANGING_PASSED_EVALUATOR; } + static RootPassedEvaluator createUnchangingRootPassedEvaluator() { + return UNCHANGING_ROOT_PASSED_EVALUATOR; + } + public static CompletionEvaluator createUnchangingCompletionEvaluator() { return UNCHANGING_COMPLETION_EVALUATOR; } @@ -172,12 +183,21 @@ class AccountingEvaluatorsFactory { private static class UnchangingScoreEvaluator implements ScoreEvaluator { @Override - public Float getScore(AssessmentEvaluation currentEvaluation, CourseNode courseNode, ConditionInterpreter conditionInterpreter) { + public Float getScore(AssessmentEvaluation currentEvaluation, CourseNode courseNode, ScoreAccounting scoreAccounting, ConditionInterpreter conditionInterpreter) { return currentEvaluation.getScore(); } } + private static class NullScoreEvaluator implements ScoreEvaluator { + + @Override + public Float getScore(AssessmentEvaluation currentEvaluation, CourseNode courseNode, ScoreAccounting scoreAccounting, ConditionInterpreter conditionInterpreter) { + return null; + } + + } + private static class UnchangingPassedEvaluator implements PassedEvaluator { @Override @@ -187,6 +207,15 @@ class AccountingEvaluatorsFactory { } } + private static class UnchangingRootPassedEvaluator implements RootPassedEvaluator { + + @Override + public Boolean getPassed(AssessmentEvaluation currentEvaluation, CourseNode courseNode, + ScoreAccounting scoreAccounting, RepositoryEntry courseEntry) { + return currentEvaluation.getPassed(); + } + } + private static class UnchangingCompletionEvaluator implements CompletionEvaluator { @Override diff --git a/src/main/java/org/olat/course/run/scoring/AssessmentAccounting.java b/src/main/java/org/olat/course/run/scoring/AssessmentAccounting.java index b88bbade6a87df7a22c841c7d5c0d0430908202e..9905e968c99e4d699af4e5523babf91869fb548b 100644 --- a/src/main/java/org/olat/course/run/scoring/AssessmentAccounting.java +++ b/src/main/java/org/olat/course/run/scoring/AssessmentAccounting.java @@ -101,7 +101,7 @@ public class AssessmentAccounting implements ScoreAccounting { if (update) { Blocker blocker = courseAssessmentService.getEvaluators(root, courseConfig).getBlockerEvaluator() .getChildrenBlocker(null); - updateEntryRecursiv(root, true, blocker); + updateEntryRecursiv(root, blocker); } return false; @@ -147,7 +147,7 @@ public class AssessmentAccounting implements ScoreAccounting { return entry; } - private AccountingResult updateEntryRecursiv(CourseNode courseNode, boolean firstChild, Blocker blocker) { + private AccountingResult updateEntryRecursiv(CourseNode courseNode, Blocker blocker) { log.debug("Evaluate course node: type '{}', ident: '{}'", courseNode.getType(), courseNode.getIdent()); AssessmentEvaluation currentEvaluation = courseNodeToEval.get(courseNode); @@ -173,10 +173,6 @@ public class AssessmentAccounting implements ScoreAccounting { result.setDuration(duration); } - ScoreEvaluator scoreEvaluator = evaluators.getScoreEvaluator(); - Float score = scoreEvaluator.getScore(result, courseNode, userCourseEnvironment.getConditionInterpreter()); - result.setScore(score); - PassedEvaluator passedEvaluator = evaluators.getPassedEvaluator(); Boolean passed = passedEvaluator.getPassed(result, courseNode, userCourseEnvironment.getCourseEnvironment().getCourseGroupManager().getCourseEntry(), @@ -193,16 +189,19 @@ public class AssessmentAccounting implements ScoreAccounting { List<AssessmentEvaluation> children = new ArrayList<>(childCount); for (int i = 0; i < childCount; i++) { INode child = courseNode.getChildAt(i); - firstChild = i== 0; if (child instanceof CourseNode) { CourseNode childCourseNode = (CourseNode) child; - AccountingResult childResult = updateEntryRecursiv(childCourseNode, firstChild, childrenBlocker); + AccountingResult childResult = updateEntryRecursiv(childCourseNode, childrenBlocker); children.add(childResult); } } blockerEvaluator.mergeChildrenBlocker(blocker, childrenBlocker); + ScoreEvaluator scoreEvaluator = evaluators.getScoreEvaluator(); + Float score = scoreEvaluator.getScore(result, courseNode, this, userCourseEnvironment.getConditionInterpreter()); + result.setScore(score); + if (durationEvaluator.isDependingOnChildNodes()) { Integer duration = durationEvaluator.getDuration(children); result.setDuration(duration); @@ -227,6 +226,13 @@ public class AssessmentAccounting implements ScoreAccounting { status = statusEvaluator.getStatus(result, children); result.setStatus(status); + if (courseNode.getParent() == null) { + RootPassedEvaluator rootPassedEvaluator = evaluators.getRootPassedEvaluator(); + Boolean rootPassed = rootPassedEvaluator.getPassed(currentEvaluation, courseNode, this, + userCourseEnvironment.getCourseEnvironment().getCourseGroupManager().getCourseEntry()); + result.setPassed(rootPassed); + } + if (result.hasChanges()) { update(courseNode, result); } diff --git a/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java b/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java index 0bd0952b3194484f6efee56324653bab9d049336..6ac394b806b0adeaedaf0036a55dc3b9a4f486d6 100644 --- a/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java +++ b/src/main/java/org/olat/course/run/scoring/AssessmentEvaluation.java @@ -196,12 +196,12 @@ public class AssessmentEvaluation extends ScoreEvaluation { } Float score = null; - if(assessmentConfig.hasScore()) { + if(Mode.none != assessmentConfig.getScoreMode()) { score = entry.getScore() == null ? null : entry.getScore().floatValue(); } Boolean passed = null; - if(assessmentConfig.hasPassed()) { + if(Mode.none != assessmentConfig.getPassedMode()) { passed = entry.getPassed(); } diff --git a/src/main/java/org/olat/course/run/scoring/RootPassedEvaluator.java b/src/main/java/org/olat/course/run/scoring/RootPassedEvaluator.java new file mode 100644 index 0000000000000000000000000000000000000000..a81c6d2475b42dc5eec87650266156618a769da5 --- /dev/null +++ b/src/main/java/org/olat/course/run/scoring/RootPassedEvaluator.java @@ -0,0 +1,36 @@ +/** + * <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.course.run.scoring; + +import org.olat.course.nodes.CourseNode; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 13 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface RootPassedEvaluator { + + public Boolean getPassed(AssessmentEvaluation currentEvaluation, CourseNode courseNode, + ScoreAccounting scoreAccounting, RepositoryEntry courseEntry); + +} diff --git a/src/main/java/org/olat/course/run/scoring/ScoreEvaluator.java b/src/main/java/org/olat/course/run/scoring/ScoreEvaluator.java index 34b931f4d3a161f562b401cb7ad56f626df0edc1..257f9fcebd22c2cd4801f6a50b48ac5e849f7121 100644 --- a/src/main/java/org/olat/course/run/scoring/ScoreEvaluator.java +++ b/src/main/java/org/olat/course/run/scoring/ScoreEvaluator.java @@ -30,6 +30,7 @@ import org.olat.course.nodes.CourseNode; */ public interface ScoreEvaluator { - public Float getScore(AssessmentEvaluation currentEvaluation, CourseNode courseNode, ConditionInterpreter conditionInterpreter); + public Float getScore(AssessmentEvaluation currentEvaluation, CourseNode courseNode, + ScoreAccounting scoreAccounting, ConditionInterpreter conditionInterpreter); } 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 54c257167716c048786d76d690e9512987a05158..e0e13e6f88a77c212fea4a1c46b52e84a70e3090 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 @@ -60,6 +60,7 @@ import org.olat.course.ICourse; import org.olat.course.archiver.ExportFormat; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.fileresource.FileResourceManager; import org.olat.ims.qti.export.QTIArchiver; @@ -327,11 +328,13 @@ public class QTI21ArchiveFormat { // course node points and passed AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if(assessmentConfig.hasScore()) { + boolean hasScore = Mode.none != assessmentConfig.getScoreMode(); + boolean hasPassed = Mode.none != assessmentConfig.getPassedMode(); + if(hasScore) { header1Row.addCell(col++, translator.translate("archive.table.header.node"), headerStyle); } - if(assessmentConfig.hasPassed()) { - if(assessmentConfig.hasScore()) { + if(hasPassed) { + if(hasScore) { col++; } else { header1Row.addCell(col++, translator.translate("archive.table.header.node"), headerStyle); @@ -403,10 +406,10 @@ public class QTI21ArchiveFormat { // course node points and passed AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if(assessmentConfig.hasScore()) { + if(Mode.none != assessmentConfig.getScoreMode()) { header2Row.addCell(col++, translator.translate("archive.table.header.node.points"), headerStyle); } - if(assessmentConfig.hasPassed()) { + if(Mode.none != assessmentConfig.getPassedMode()) { header2Row.addCell(col++, translator.translate("archive.table.header.node.passed"), headerStyle); } @@ -528,14 +531,14 @@ public class QTI21ArchiveFormat { // course node points and passed AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - if(assessmentConfig.hasScore()) { + if(Mode.none != assessmentConfig.getScoreMode()) { if(entry.getScore() != null) { dataRow.addCell(col++, entry.getScore(), null); } else { col++; } } - if(assessmentConfig.hasPassed()) { + if(Mode.none != assessmentConfig.getPassedMode()) { if(entry.getPassed() != null) { dataRow.addCell(col++, entry.getPassed().toString(), null); } else { diff --git a/src/main/java/org/olat/modules/portfolio/BinderConfiguration.java b/src/main/java/org/olat/modules/portfolio/BinderConfiguration.java index 97fb76f70b2fde094d65552798f84d8d47e7cc61..c76a3bdd1cfff49c95807421b4fded1fe377e309 100644 --- a/src/main/java/org/olat/modules/portfolio/BinderConfiguration.java +++ b/src/main/java/org/olat/modules/portfolio/BinderConfiguration.java @@ -27,6 +27,7 @@ import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.PortfolioCourseNode; import org.olat.repository.RepositoryEntry; @@ -147,12 +148,12 @@ public class BinderConfiguration { if(courseNode instanceof PortfolioCourseNode) { CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode); - withScore = assessmentConfig.hasScore(); + withScore = Mode.none != assessmentConfig.getScoreMode(); if(withScore) { maxScore = assessmentConfig.getMaxScore(); minScore = assessmentConfig.getMinScore(); } - withPassed = assessmentConfig.hasPassed(); + withPassed = Mode.none != assessmentConfig.getPassedMode(); assessable = withPassed || withScore; } else { withPassed = true; diff --git a/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java b/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java index 2021f50e29bc2bf52b4117cd60b640bfee7cd1aa..3ef2ae794d6111734dececeae1cdf6572fe9ab48 100644 --- a/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java +++ b/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java @@ -51,6 +51,7 @@ import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.assessment.manager.AssessmentNotificationsHandler; import org.olat.course.nodes.ScormCourseNode; import org.olat.course.nodes.scorm.ScormEditController; @@ -117,10 +118,10 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable { checkForLms(); CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(scormNode); - if(assessmentConfig.hasScore()) { + if(Mode.none != assessmentConfig.getScoreMode()) { currentScore = courseAssessmentService.getAssessmentEvaluation(scormNode, userCourseEnv).getScore(); } - if(assessmentConfig.hasPassed()) { + if(Mode.none != assessmentConfig.getPassedMode()) { currentPassed = courseAssessmentService.getAssessmentEvaluation(scormNode, userCourseEnv).getPassed(); } } diff --git a/src/main/java/org/olat/repository/ui/author/CreateCourseRepositoryEntryController.java b/src/main/java/org/olat/repository/ui/author/CreateCourseRepositoryEntryController.java index 4c7ed5700cd78e79138c4ed7f861db46fec5cda1..3f15b4fc8dd514b7450528d8534b5c9d6620bf08 100644 --- a/src/main/java/org/olat/repository/ui/author/CreateCourseRepositoryEntryController.java +++ b/src/main/java/org/olat/repository/ui/author/CreateCourseRepositoryEntryController.java @@ -36,6 +36,10 @@ import org.olat.course.condition.ConditionNodeAccessProvider; import org.olat.course.config.CourseConfig; import org.olat.course.nodeaccess.NodeAccessProviderIdentifier; import org.olat.course.nodeaccess.NodeAccessService; +import org.olat.course.nodeaccess.NodeAccessType; +import org.olat.course.nodes.STCourseNode; +import org.olat.course.tree.CourseEditorTreeNode; +import org.olat.modules.ModuleConfiguration; import org.olat.repository.handlers.RepositoryHandler; import org.springframework.beans.factory.annotation.Autowired; @@ -86,26 +90,35 @@ public class CreateCourseRepositoryEntryController extends CreateRepositoryEntry @Override protected void afterEntryCreated() { - if (isNotDefaultNodeAccessType()) { - OLATResourceable courseOres = getAddedEntry().getOlatResource(); - if (CourseFactory.isCourseEditSessionOpen(courseOres.getResourceableId())) { - log.warn("Not able to set the course node access type: Edit session is already open!"); - return; - } - - ICourse course = CourseFactory.openCourseEditSession(courseOres.getResourceableId()); - CourseConfig courseConfig = course.getCourseEnvironment().getCourseConfig(); - String nodeAccessType = nodeAccessEl.getSelectedKey(); - courseConfig.setNodeAccessType(nodeAccessType); - - CourseFactory.setCourseConfig(course.getResourceableId(), courseConfig); - CourseFactory.closeCourseEditSession(course.getResourceableId(), true); + OLATResourceable courseOres = getAddedEntry().getOlatResource(); + if (CourseFactory.isCourseEditSessionOpen(courseOres.getResourceableId())) { + log.warn("Not able to set the course node access type: Edit session is already open!"); + return; } - } - - private boolean isNotDefaultNodeAccessType() { - return nodeAccessEl.isOneSelected() - && !CourseConfig.NODE_ACCESS_TYPE_DEFAULT.equals(nodeAccessEl.getSelectedValue()); + + ICourse course = CourseFactory.openCourseEditSession(courseOres.getResourceableId()); + CourseConfig courseConfig = course.getCourseEnvironment().getCourseConfig(); + String nodeAccessType = nodeAccessEl.getSelectedKey(); + courseConfig.setNodeAccessType(nodeAccessType); + + ModuleConfiguration runConfig = course.getCourseEnvironment().getRunStructure().getRootNode().getModuleConfiguration(); + CourseEditorTreeNode courseEditorTreeNode = (CourseEditorTreeNode)course.getEditorTreeModel().getRootNode(); + ModuleConfiguration editorConfig = courseEditorTreeNode.getCourseNode().getModuleConfiguration(); + + boolean scoreCalculatorSupported = nodeAccessService.isScoreCalculatorSupported(NodeAccessType.of(nodeAccessType)); + runConfig.setBooleanEntry(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED, scoreCalculatorSupported); + editorConfig.setBooleanEntry(STCourseNode.CONFIG_SCORE_CALCULATOR_SUPPORTED, scoreCalculatorSupported); + + if (!scoreCalculatorSupported) { + runConfig.setStringValue(STCourseNode.CONFIG_SCORE_KEY, STCourseNode.CONFIG_SCORE_VALUE_SUM); + runConfig.setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + editorConfig.setStringValue(STCourseNode.CONFIG_SCORE_KEY, STCourseNode.CONFIG_SCORE_VALUE_SUM); + editorConfig.setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + } + + CourseFactory.setCourseConfig(course.getResourceableId(), courseConfig); + CourseFactory.saveCourse(getAddedEntry().getOlatResource().getResourceableId()); + CourseFactory.closeCourseEditSession(course.getResourceableId(), true); } } diff --git a/src/test/java/org/olat/course/nodes/st/assessment/ConventionalSTCompletionEvaluatorTest.java b/src/test/java/org/olat/course/nodes/st/assessment/ConventionalSTCompletionEvaluatorTest.java index 466ff56ff1a6b96f7801ae77f8263626a9c4963b..2a791bbcfe335bd67a274ae82e5c10720577eab3 100644 --- a/src/test/java/org/olat/course/nodes/st/assessment/ConventionalSTCompletionEvaluatorTest.java +++ b/src/test/java/org/olat/course/nodes/st/assessment/ConventionalSTCompletionEvaluatorTest.java @@ -29,6 +29,7 @@ import org.mockito.MockitoAnnotations; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.MappedScoreAccounting; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.STCourseNode; import org.olat.course.run.scoring.AssessmentEvaluation; @@ -55,8 +56,8 @@ public class ConventionalSTCompletionEvaluatorTest { public void setUp() { MockitoAnnotations.initMocks(this); - when(configWithPassed.hasPassed()).thenReturn(Boolean.TRUE); - when(configWithoutPassed.hasPassed()).thenReturn(Boolean.FALSE); + when(configWithPassed.getPassedMode()).thenReturn(Mode.setByNode); + when(configWithoutPassed.getPassedMode()).thenReturn(Mode.none); sut= new ConventionalSTCompletionEvaluator(courseAssessmentService); } diff --git a/src/test/java/org/olat/course/nodes/st/assessment/CumulatingScoreEvaluatorTest.java b/src/test/java/org/olat/course/nodes/st/assessment/CumulatingScoreEvaluatorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3c2adfa72ef987550603cdadb855833d49aaafdc --- /dev/null +++ b/src/test/java/org/olat/course/nodes/st/assessment/CumulatingScoreEvaluatorTest.java @@ -0,0 +1,167 @@ +/** + * <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.course.nodes.st.assessment; + +import static org.mockito.Mockito.when; + +import org.assertj.core.api.SoftAssertions; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.course.assessment.CourseAssessmentService; +import org.olat.course.assessment.MappedScoreAccounting; +import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; +import org.olat.course.nodes.Card2BrainCourseNode; +import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.SPCourseNode; +import org.olat.course.nodes.STCourseNode; +import org.olat.course.nodes.st.assessment.CumulatingScoreEvaluator.Score; +import org.olat.course.run.scoring.AssessmentEvaluation; + +/** + * + * Initial date: 10.03.2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class CumulatingScoreEvaluatorTest { + + @Mock + private AssessmentConfig configSetByNode; + @Mock + private AssessmentConfig configSetByNodeIgnore; + @Mock + private AssessmentConfig configEvaluated; + @Mock + private AssessmentConfig configNone; + + @Mock + private CourseAssessmentService courseAssessmentService; + + private CumulatingScoreEvaluator sut; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(configEvaluated.getScoreMode()).thenReturn(Mode.evaluated); + when(configSetByNode.getScoreMode()).thenReturn(Mode.setByNode); + when(configSetByNode.ignoreInCourseAssessment()).thenReturn(Boolean.FALSE); + when(configSetByNodeIgnore.getScoreMode()).thenReturn(Mode.setByNode); + when(configSetByNodeIgnore.ignoreInCourseAssessment()).thenReturn(Boolean.TRUE); + when(configNone.getScoreMode()).thenReturn(Mode.none); + + sut = new CumulatingScoreEvaluator(true); + } + + @Test + public void shouldGetCummulatingScore() { + MappedScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + // Parent + CourseNode parent = new STCourseNode(); + // Child: uncalculated + CourseNode childUncalculated = new Card2BrainCourseNode(); + parent.addChild(childUncalculated); + AssessmentEvaluation childUncalculatedEvaluation = createAssessmentEvaluation(Float.valueOf(14), Boolean.TRUE); + scoreAccounting.put(childUncalculated, childUncalculatedEvaluation); + when(courseAssessmentService.getAssessmentConfig(childUncalculated)).thenReturn(configSetByNode); + // Child: Calculated + CourseNode childCalculated = new STCourseNode(); + parent.addChild(childCalculated); + AssessmentEvaluation childCalculatedEvaluation = createAssessmentEvaluation(Float.valueOf(4), Boolean.TRUE); + scoreAccounting.put(childCalculated, childCalculatedEvaluation); + when(courseAssessmentService.getAssessmentConfig(childCalculated)).thenReturn(configEvaluated); + // Child: uncalculated, not visible + CourseNode childUncalculated2 = new STCourseNode(); + parent.addChild(childUncalculated2); + AssessmentEvaluation childCalculatedEvaluation2 = createAssessmentEvaluation(Float.valueOf(3), Boolean.FALSE); + scoreAccounting.put(childUncalculated2, childCalculatedEvaluation2); + when(courseAssessmentService.getAssessmentConfig(childUncalculated2)).thenReturn(configSetByNode); + // Child: uncalculated + CourseNode childUncalculated3 = new Card2BrainCourseNode(); + parent.addChild(childUncalculated3); + AssessmentEvaluation childUncalculatedEvaluation3 = createAssessmentEvaluation(Float.valueOf(5), Boolean.TRUE); + scoreAccounting.put(childUncalculated3, childUncalculatedEvaluation3); + when(courseAssessmentService.getAssessmentConfig(childUncalculated3)).thenReturn(configSetByNode); + // Child: uncalculated + CourseNode childUncalculatedIgnored = new Card2BrainCourseNode(); + parent.addChild(childUncalculatedIgnored); + AssessmentEvaluation childUncalculatedEvaluationIgnored = createAssessmentEvaluation(Float.valueOf(5), Boolean.TRUE); + scoreAccounting.put(childUncalculatedIgnored, childUncalculatedEvaluationIgnored); + when(courseAssessmentService.getAssessmentConfig(childUncalculatedIgnored)).thenReturn(configSetByNodeIgnore); + + // Child level 2: uncalculated + CourseNode child2Uncalculated = new SPCourseNode(); + childCalculated.addChild(child2Uncalculated); + AssessmentEvaluation child2UncalculatedEvaluation = createAssessmentEvaluation(Float.valueOf(2), Boolean.TRUE); + scoreAccounting.put(child2Uncalculated, child2UncalculatedEvaluation); + when(courseAssessmentService.getAssessmentConfig(child2Uncalculated)).thenReturn(configSetByNode); + // Child level 2: calculated + CourseNode child2Calculated = new STCourseNode(); + childCalculated.addChild(child2Calculated); + AssessmentEvaluation child2CalculatedEvaluation = createAssessmentEvaluation(Float.valueOf(1), Boolean.TRUE); + scoreAccounting.put(child2Calculated, child2CalculatedEvaluation); + when(courseAssessmentService.getAssessmentConfig(child2Calculated)).thenReturn(configEvaluated); + + Score score = sut.getScore(parent, scoreAccounting, courseAssessmentService); + + SoftAssertions softly = new SoftAssertions(); + softly.assertThat(score.getSum()).isEqualTo(21); + softly.assertThat(score.getAverage()).isEqualTo(7); + softly.assertAll(); + } + + @Test + public void shouldReturnNullIfNoChildrenWithScore() { + MappedScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + // Parent + CourseNode parent = new STCourseNode(); + // Child: Calculated + CourseNode childCalculated = new STCourseNode(); + parent.addChild(childCalculated); + AssessmentEvaluation childCalculatedEvaluation = createAssessmentEvaluation(Float.valueOf(4), Boolean.TRUE); + scoreAccounting.put(childCalculated, childCalculatedEvaluation); + when(courseAssessmentService.getAssessmentConfig(childCalculated)).thenReturn(configEvaluated); + // Child: uncalculated, not visible + CourseNode childNotVisible = new SPCourseNode(); + parent.addChild(childNotVisible); + AssessmentEvaluation childNotVisibleEvaluation = createAssessmentEvaluation(Float.valueOf(3), Boolean.FALSE); + scoreAccounting.put(childNotVisible, childNotVisibleEvaluation); + when(courseAssessmentService.getAssessmentConfig(childNotVisible)).thenReturn(configSetByNode); + + Score score = sut.getScore(parent, scoreAccounting, courseAssessmentService); + + SoftAssertions softly = new SoftAssertions(); + softly.assertThat(score.getSum()).isNull(); + softly.assertThat(score.getAverage()).isNull(); + softly.assertAll(); + } + + + private AssessmentEvaluation createAssessmentEvaluation(Float score, Boolean userVisibility) { + return new AssessmentEvaluation(score, null, null, null, null, userVisibility, null, null, null, null, null, + null, null, 0, null, null, null, null, null, null, null, null, null, null); + } + +} diff --git a/src/test/java/org/olat/course/nodes/st/assessment/PassCounterTest.java b/src/test/java/org/olat/course/nodes/st/assessment/PassCounterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0651f820a4cae1a69a1d2315f835c5eb83e4592f --- /dev/null +++ b/src/test/java/org/olat/course/nodes/st/assessment/PassCounterTest.java @@ -0,0 +1,150 @@ +/** + * <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.course.nodes.st.assessment; + +import static org.mockito.Mockito.when; + +import org.assertj.core.api.SoftAssertions; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.olat.course.assessment.CourseAssessmentService; +import org.olat.course.assessment.MappedScoreAccounting; +import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; +import org.olat.course.nodes.Card2BrainCourseNode; +import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.STCourseNode; +import org.olat.course.nodes.st.assessment.PassCounter.Counts; +import org.olat.course.run.scoring.AssessmentEvaluation; + +/** + * + * Initial date: 13 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class PassCounterTest { + + @Mock + private AssessmentConfig configSetByNode; + @Mock + private AssessmentConfig configSetByNodeIgnore; + @Mock + private AssessmentConfig configEvaluated; + @Mock + private AssessmentConfig configNone; + + @Mock + private CourseAssessmentService courseAssessmentService; + + private PassCounter sut; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(configEvaluated.getPassedMode()).thenReturn(Mode.evaluated); + when(configSetByNode.getPassedMode()).thenReturn(Mode.setByNode); + when(configSetByNode.ignoreInCourseAssessment()).thenReturn(Boolean.FALSE); + when(configSetByNodeIgnore.getPassedMode()).thenReturn(Mode.setByNode); + when(configSetByNodeIgnore.ignoreInCourseAssessment()).thenReturn(Boolean.TRUE); + when(configNone.getPassedMode()).thenReturn(Mode.none); + + sut = new PassCounter(); + } + + @Test + public void shouldGetCummulatingScore() { + MappedScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + // Parent + CourseNode parent = new STCourseNode(); + // Child: set by node, passed, user visible + CourseNode child11 = new Card2BrainCourseNode(); + parent.addChild(child11); + AssessmentEvaluation child11Evaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE); + scoreAccounting.put(child11, child11Evaluation); + when(courseAssessmentService.getAssessmentConfig(child11)).thenReturn(configSetByNode); + // Child: set by node, not passed, user visible + CourseNode child12 = new Card2BrainCourseNode(); + parent.addChild(child12); + AssessmentEvaluation child12Evaluation = createAssessmentEvaluation(Boolean.FALSE, Boolean.TRUE); + scoreAccounting.put(child12, child12Evaluation); + when(courseAssessmentService.getAssessmentConfig(child12)).thenReturn(configSetByNode); + // Child: set by node, not passed, not user visible + CourseNode child13 = new Card2BrainCourseNode(); + parent.addChild(child13); + AssessmentEvaluation child13Evaluation = createAssessmentEvaluation(Boolean.FALSE, Boolean.FALSE); + scoreAccounting.put(child13, child13Evaluation); + when(courseAssessmentService.getAssessmentConfig(child13)).thenReturn(configSetByNode); + // Child: set by node, passed, not user visible + CourseNode child14 = new Card2BrainCourseNode(); + parent.addChild(child14); + AssessmentEvaluation child14Evaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.FALSE); + scoreAccounting.put(child14, child14Evaluation); + when(courseAssessmentService.getAssessmentConfig(child14)).thenReturn(configSetByNode); + // Child: none, passed, user visible + CourseNode child15 = new Card2BrainCourseNode(); + parent.addChild(child15); + AssessmentEvaluation child15Evaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE); + scoreAccounting.put(child15, child15Evaluation); + when(courseAssessmentService.getAssessmentConfig(child15)).thenReturn(configNone); + // Child: set by node, null passed, not user visible + CourseNode child16 = new Card2BrainCourseNode(); + parent.addChild(child16); + AssessmentEvaluation child16Evaluation = createAssessmentEvaluation(null, Boolean.TRUE); + scoreAccounting.put(child16, child16Evaluation); + when(courseAssessmentService.getAssessmentConfig(child16)).thenReturn(configSetByNode); + // Child: evaluated, passed, user visible + CourseNode child17 = new STCourseNode(); + parent.addChild(child17); + AssessmentEvaluation child17Evaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE); + scoreAccounting.put(child17, child17Evaluation); + when(courseAssessmentService.getAssessmentConfig(child17)).thenReturn(configEvaluated); + // Child: set by node, passed, user visible, ignored + CourseNode child18 = new Card2BrainCourseNode(); + parent.addChild(child18); + AssessmentEvaluation child18Evaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE); + scoreAccounting.put(child18, child18Evaluation); + when(courseAssessmentService.getAssessmentConfig(child18)).thenReturn(configSetByNodeIgnore); + + // Child level 2: set by node, passed, user visible + CourseNode child21 = new Card2BrainCourseNode(); + child17.addChild(child21); + AssessmentEvaluation child21Evaluation = createAssessmentEvaluation(Boolean.TRUE, Boolean.TRUE); + scoreAccounting.put(child21, child21Evaluation); + when(courseAssessmentService.getAssessmentConfig(child21)).thenReturn(configSetByNode); + + Counts counts = sut.getCounts(parent, scoreAccounting, courseAssessmentService); + + SoftAssertions softly = new SoftAssertions(); + softly.assertThat(counts.getPassable()).isEqualTo(6); + softly.assertThat(counts.getPassed()).isEqualTo(2); + softly.assertThat(counts.getFailed()).isEqualTo(1); + softly.assertAll(); + } + + private AssessmentEvaluation createAssessmentEvaluation(Boolean passed, Boolean userVisibility) { + return new AssessmentEvaluation(null, passed, null, null, null, userVisibility, null, null, null, null, null, + null, null, 0, null, null, null, null, null, null, null, null, null, null); + } +} diff --git a/src/test/java/org/olat/course/nodes/st/assessment/STRootPassedEvaluatorTest.java b/src/test/java/org/olat/course/nodes/st/assessment/STRootPassedEvaluatorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..23a63d9772a9b99f8e4b45a12b0622fe9172a3df --- /dev/null +++ b/src/test/java/org/olat/course/nodes/st/assessment/STRootPassedEvaluatorTest.java @@ -0,0 +1,449 @@ +/** + * <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.course.nodes.st.assessment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.assertj.core.util.DateUtil; +import org.junit.Before; +import org.junit.Test; +import org.olat.course.assessment.MappedScoreAccounting; +import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.STCourseNode; +import org.olat.course.nodes.st.assessment.PassCounter.Counts; +import org.olat.course.run.scoring.AssessmentEvaluation; +import org.olat.course.run.scoring.ScoreAccounting; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.model.RepositoryEntryLifecycle; + +/** + * + * Initial date: 13 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class STRootPassedEvaluatorTest { + + private RepositoryEntry dummyEntry = new RepositoryEntry(); + private PassCounter oneHalfPassed; + + @Before + public void setUp() { + Counts counts = new CountsImpl(3, 2, 1); + oneHalfPassed = mock(PassCounter.class); + when(oneHalfPassed.getCounts(any(), any())).thenReturn(counts); + } + + @Test + public void shouldReturnNullPerDefault() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, null, null); + CourseNode courseNode = new STCourseNode(); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isNull(); + } + + @Test + public void shouldReturnCurrentTrueIfNoConfiguration() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, Boolean.TRUE, null, null); + CourseNode courseNode = new STCourseNode(); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isTrue(); + } + + @Test + public void shouldReturnCurrentFalseIfNoConfiguration() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, Boolean.FALSE, null, null); + CourseNode courseNode = new STCourseNode(); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isFalse(); + } + + @Test + public void shouldReturnTrueIfFullyAssessed() { + AssessmentEvaluation currentEvaluation = createEvalaution(Boolean.FALSE, Boolean.TRUE); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isTrue(); + } + + @Test + public void shouldReturnCurrentIfNotFullyAssessed() { + AssessmentEvaluation currentEvaluation = createEvalaution(null, Boolean.FALSE); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isNull(); + } + + @Test + public void shouldReturnNotResetIfNotFullyAssessed() { + AssessmentEvaluation currentEvaluation = createEvalaution(Boolean.TRUE, Boolean.FALSE); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isTrue(); + } + + private AssessmentEvaluation createEvalaution(Boolean passed, Boolean fullyAssessed) { + return new AssessmentEvaluation(null, passed, null, null, null, null, fullyAssessed, null, null, null, null, + null, null, 0, null, null, null, null, null, null, null, null, null, null); + } + + @Test + public void shouldReturnTrueIfPointCutReached() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(Float.valueOf(20), null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_POINTS, true); + courseNode.getModuleConfiguration().setIntValue(STCourseNode.CONFIG_PASSED_POINTS_CUT, 10); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isTrue(); + } + + @Test + public void shouldReturnTrueIfPointCutReachedExactly() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(Float.valueOf(10), null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_POINTS, true); + courseNode.getModuleConfiguration().setIntValue(STCourseNode.CONFIG_PASSED_POINTS_CUT, 10); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isTrue(); + } + + @Test + public void shouldReturnCurrentIfPointCutNotReached() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(Float.valueOf(2), null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_POINTS, true); + courseNode.getModuleConfiguration().setIntValue(STCourseNode.CONFIG_PASSED_POINTS_CUT, 10); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isNull(); + } + + @Test + public void shouldNotResetIfPointCutNotReached() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(Float.valueOf(2), Boolean.TRUE, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_POINTS, true); + courseNode.getModuleConfiguration().setIntValue(STCourseNode.CONFIG_PASSED_POINTS_CUT, 10); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + STRootPassedEvaluator sut = new STRootPassedEvaluator(oneHalfPassed); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isTrue(); + } + + @Test + public void shouldReturnTrueIfAllPassed() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(Float.valueOf(20), null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + Counts counts = new CountsImpl(3, 3, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isTrue(); + } + + @Test + public void shouldReturnFailedIfAllNotPassedAndOnlyCriterion() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(Float.valueOf(20), null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + Counts counts = new CountsImpl(3, 2, 1); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isFalse(); + } + + @Test + public void shouldNotReturnNullIfAllNotPassedAndMultipleCriterion() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(Float.valueOf(20), null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + Counts counts = new CountsImpl(3, 2, 1); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isNull(); + } + + @Test + public void shouldReturnNullIfNotAllAssessed() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(Float.valueOf(20), null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + Counts counts = new CountsImpl(3, 2, 1); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, dummyEntry); + + assertThat(passed).isNull(); + } + + @Test + public void shouldReturnFailedIfCourseHasEndedAndItIsNotPassed() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + RepositoryEntryLifecycle lifecycle = new RepositoryEntryLifecycle(); + lifecycle.setValidTo(DateUtil.yesterday()); + RepositoryEntry endedEntry = new RepositoryEntry(); + endedEntry.setLifecycle(lifecycle); + + Counts counts = new CountsImpl(3, 2, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, endedEntry); + + assertThat(passed).isFalse(); + } + + @Test + public void shouldReturnNullIfCourseHasNotEndedAndItIsNotPassed() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + RepositoryEntryLifecycle lifecycle = new RepositoryEntryLifecycle(); + lifecycle.setValidTo(DateUtil.tomorrow()); + RepositoryEntry runningEntry = new RepositoryEntry(); + runningEntry.setLifecycle(lifecycle); + + Counts counts = new CountsImpl(3, 2, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, runningEntry); + + assertThat(passed).isNull(); + } + + @Test + public void shouldReturnNullIfCourseHasEndedAndItIsNotPassedAndHasNoPassableNodes() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_PROGRESS, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + RepositoryEntryLifecycle lifecycle = new RepositoryEntryLifecycle(); + lifecycle.setValidTo(DateUtil.yesterday()); + RepositoryEntry endedEntry = new RepositoryEntry(); + endedEntry.setLifecycle(lifecycle); + + Counts counts = new CountsImpl(0, 0, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, endedEntry); + + assertThat(passed).isNull(); + } + + @Test + public void shouldReturnNullIfCourseHasEndedAndItIsNotPassedAndHAsNoPassConfigs() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, null, null); + CourseNode courseNode = new STCourseNode(); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + RepositoryEntryLifecycle lifecycle = new RepositoryEntryLifecycle(); + lifecycle.setValidTo(DateUtil.yesterday()); + RepositoryEntry endedEntry = new RepositoryEntry(); + endedEntry.setLifecycle(lifecycle); + + Counts counts = new CountsImpl(3, 2, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, endedEntry); + + assertThat(passed).isNull(); + } + + @Test + public void shouldReturnFailedIfCourseIsFullyAssessedAndItIsNotPassed() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, Boolean.TRUE, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + Counts counts = new CountsImpl(3, 2, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, null); + + assertThat(passed).isFalse(); + } + + @Test + public void shouldReturnNullIfCourseIsNotFullyAssessedAndItIsNotPassed() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, null, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + Counts counts = new CountsImpl(3, 2, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, null); + + assertThat(passed).isNull(); + } + + @Test + public void shouldReturnNullIfCourseIsFullyAssessedButHasNoPassableNodes() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, Boolean.TRUE, null); + CourseNode courseNode = new STCourseNode(); + courseNode.getModuleConfiguration().setBooleanEntry(STCourseNode.CONFIG_PASSED_ALL, true); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + Counts counts = new CountsImpl(0, 0, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, null); + + assertThat(passed).isNull(); + } + + + @Test + public void shouldReturnNullIfCourseIsFullyAssessedButHassNoPassConfigs() { + AssessmentEvaluation currentEvaluation = new AssessmentEvaluation(null, null, Boolean.TRUE, null); + CourseNode courseNode = new STCourseNode(); + ScoreAccounting scoreAccounting = new MappedScoreAccounting(); + + Counts counts = new CountsImpl(3, 2, 0); + PassCounter passCounter = mock(PassCounter.class); + when(passCounter.getCounts(any(), any())).thenReturn(counts); + STRootPassedEvaluator sut = new STRootPassedEvaluator(passCounter); + + Boolean passed = sut.getPassed(currentEvaluation, courseNode, scoreAccounting, null); + + assertThat(passed).isNull(); + } + + + private final static class CountsImpl implements Counts { + + private final int passable; + private final int passed; + private final int failed; + + public CountsImpl(int passable, int passed, int failed) { + super(); + this.passable = passable; + this.passed = passed; + this.failed = failed; + } + + @Override + public int getPassable() { + return passable; + } + + @Override + public int getPassed() { + return passed; + } + + @Override + public int getFailed() { + return failed; + } + + @Override + public boolean isAllAssessed() { + return passable == passed + failed; + } + + } + +} diff --git a/src/test/java/org/olat/modules/reminder/manager/ReminderRuleEngineTest.java b/src/test/java/org/olat/modules/reminder/manager/ReminderRuleEngineTest.java index 31ea995da86c870df832a2dc829f3655aaa46a73..0f30e28cb0527e09827b524aaeb57f1957b7adf3 100644 --- a/src/test/java/org/olat/modules/reminder/manager/ReminderRuleEngineTest.java +++ b/src/test/java/org/olat/modules/reminder/manager/ReminderRuleEngineTest.java @@ -43,6 +43,7 @@ import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.handler.AssessmentConfig; +import org.olat.course.assessment.handler.AssessmentConfig.Mode; import org.olat.course.assessment.manager.UserCourseInformationsManager; import org.olat.course.assessment.model.UserCourseInfosImpl; import org.olat.course.nodes.CourseNode; @@ -1088,7 +1089,7 @@ public class ReminderRuleEngineTest extends OlatTestCase { } Assert.assertNotNull(testNode); AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(testNode); - Assert.assertTrue(assessmentConfig.hasScore()); + Assert.assertTrue(Mode.none != assessmentConfig.getScoreMode()); IdentityEnvironment ienv = new IdentityEnvironment(); ienv.setIdentity(student); diff --git a/src/test/java/org/olat/selenium/page/course/CourseSettingsPage.java b/src/test/java/org/olat/selenium/page/course/CourseSettingsPage.java index 13c01de4254e05ac738c77a14b9060db9a5d55d5..b60fc1d6fce31c9cababd95e019812a22f6df938 100644 --- a/src/test/java/org/olat/selenium/page/course/CourseSettingsPage.java +++ b/src/test/java/org/olat/selenium/page/course/CourseSettingsPage.java @@ -49,7 +49,7 @@ public class CourseSettingsPage extends RepositorySettingsPage { } public EfficiencyStatementConfigurationPage efficiencyStatementConfiguration() { - By certificateSegmentBy = By.cssSelector("ul.o_tools_segments a.o_sel_certificates"); + By certificateSegmentBy = By.cssSelector("ul.o_tools_segments a.o_sel_results"); OOGraphene.waitElement(certificateSegmentBy, browser); browser.findElement(certificateSegmentBy).click(); diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index b0b4b39db45157831ff786c7cac501d549841a82..3f6013b245b892a64103e24049cb255bf61a7dee 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -482,11 +482,13 @@ import org.junit.runners.Suite; org.olat.course.learningpath.evaluation.DefaultStatusEvaluatorTest.class, org.olat.course.learningpath.evaluation.LinearAccessEvaluatorTest.class, org.olat.course.learningpath.manager.LearningPathNodeAccessProviderTest.class, + org.olat.course.nodes.st.assessment.PassCounterTest.class, org.olat.course.nodes.st.assessment.CumulatingDurationEvaluatorTest.class, org.olat.course.nodes.st.assessment.ConventionalSTCompletionEvaluatorTest.class, org.olat.course.nodes.st.assessment.MandatoryObligationEvaluatorTest.class, org.olat.course.nodes.st.assessment.STFullyAssessedEvaluatorTest.class, org.olat.course.nodes.st.assessment.STLastModificationsEvaluatorTest.class, + org.olat.course.nodes.st.assessment.STRootPassedEvaluatorTest.class, org.olat.course.nodes.st.assessment.STStatusEvaluatorTest.class, org.olat.course.run.scoring.AverageCompletionEvaluatorTest.class, org.olat.course.run.userview.UserCourseEnvironmentImplTest.class,