diff --git a/src/main/java/org/olat/course/nodes/_spring/buildingblockContext.xml b/src/main/java/org/olat/course/nodes/_spring/buildingblockContext.xml index ae60fe2af111c2b05917b3601c5301dfb7ea7863..0ec7c18fc0666c2779ac3a5f3b28f5247c17983c 100644 --- a/src/main/java/org/olat/course/nodes/_spring/buildingblockContext.xml +++ b/src/main/java/org/olat/course/nodes/_spring/buildingblockContext.xml @@ -8,7 +8,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - <context:component-scan base-package="org.olat.course.nodes.en,org.olat.course.nodes.cl,org.olat.course.nodes.projectbroker.service,org.olat.course.nodes.gta.manager" /> + <context:component-scan base-package="org.olat.course.nodes.en,org.olat.course.nodes.cl,org.olat.course.nodes.projectbroker.service,org.olat.course.nodes.gta" /> <!-- Course node spring config: Course Nodes are searched on the whole classpath, just place your CourceNodeConfiguration somewhere on the classpath best as a jar. The xml file with ending ...Context.xml has do to be outside of the jar to get automatically loaded --> diff --git a/src/main/java/org/olat/course/nodes/gta/GTAManager.java b/src/main/java/org/olat/course/nodes/gta/GTAManager.java index 64030eb3691751c5d90cee0b0c8e3423fa93acc8..5859a22a63e38fdaa63a9aacedf327f6e78cf7a7 100644 --- a/src/main/java/org/olat/course/nodes/gta/GTAManager.java +++ b/src/main/java/org/olat/course/nodes/gta/GTAManager.java @@ -157,6 +157,9 @@ public interface GTAManager { public Task nextStep(Task task, GTACourseNode cNode); + + public List<Task> getTasks(TaskList taskList); + /** * Return the tasks assigned to a person, individually or via a * business group. diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java index 741c76cd062d44cf0ebb04dfc81ce5dc6cd831fd..746a050be9df66ffb81a24b701fa8e77e3fc47c1 100644 --- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java +++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java @@ -443,6 +443,18 @@ public class GTAManagerImpl implements GTAManager { return tasks.isEmpty() ? null : tasks.get(0); } + @Override + public List<Task> getTasks(TaskList taskList) { + StringBuilder sb = new StringBuilder(); + sb.append("select task from gtatask task ") + .append(" inner join task.taskList tasklist ") + .append(" where tasklist.key=:taskListKey "); + + return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Task.class) + .setParameter("taskListKey", taskList.getKey()) + .getResultList(); + } + @Override public List<Task> getTasks(IdentityRef identity, RepositoryEntryRef entry, GTACourseNode cNode) { StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java b/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java new file mode 100644 index 0000000000000000000000000000000000000000..868517dbdc2759013df742280930d318b870a16b --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/rule/AbstractDueDateTaskRuleSPI.java @@ -0,0 +1,183 @@ +/** + * <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.gta.rule; + +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.olat.basesecurity.GroupRoles; +import org.olat.core.id.Identity; +import org.olat.course.CourseFactory; +import org.olat.course.ICourse; +import org.olat.course.nodes.CourseNode; +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.GTAType; +import org.olat.course.nodes.gta.Task; +import org.olat.course.nodes.gta.TaskList; +import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupService; +import org.olat.modules.ModuleConfiguration; +import org.olat.modules.reminder.IdentitiesProviderRuleSPI; +import org.olat.modules.reminder.ReminderRule; +import org.olat.modules.reminder.model.ReminderRuleImpl; +import org.olat.modules.reminder.rule.LaunchUnit; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryRelationType; +import org.olat.repository.manager.RepositoryEntryRelationDAO; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 10.04.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public abstract class AbstractDueDateTaskRuleSPI implements IdentitiesProviderRuleSPI { + + @Autowired + private GTAManager gtaManager; + @Autowired + private BusinessGroupService businessGroupService; + @Autowired + private RepositoryEntryRelationDAO repositoryEntryRelationDao; + + @Override + public List<Identity> evaluate(RepositoryEntry entry, ReminderRule rule) { + List<Identity> identities = null; + if(rule instanceof ReminderRuleImpl) { + ReminderRuleImpl r = (ReminderRuleImpl)rule; + String nodeIdent = r.getLeftOperand(); + + ICourse course = CourseFactory.loadCourse(entry.getOlatResource()); + CourseNode courseNode = course.getRunStructure().getNode(nodeIdent); + if(courseNode instanceof GTACourseNode) { + identities = evaluateRule(entry, (GTACourseNode)courseNode, r); + } + } + return identities == null ? Collections.<Identity>emptyList() : identities; + } + + protected List<Identity> evaluateRule(RepositoryEntry entry, GTACourseNode gtaNode, ReminderRuleImpl r) { + List<Identity> identities = null; + Date dueDate = getDueDate(gtaNode); + if(dueDate != null) { + int value = Integer.parseInt(r.getRightOperand()); + String unit = r.getRightUnit(); + Date now = new Date(); + if(near(dueDate, now, value, LaunchUnit.valueOf(unit))) { + identities = getPeopleToRemind(entry, gtaNode); + } + } + return identities == null ? Collections.<Identity>emptyList() : identities; + } + + protected abstract Date getDueDate(GTACourseNode gtaNode); + + protected List<Identity> getPeopleToRemind(RepositoryEntry entry, GTACourseNode gtaNode) { + ModuleConfiguration config = gtaNode.getModuleConfiguration(); + TaskList taskList = gtaManager.getTaskList(entry, gtaNode); + if(GTAType.group.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE))) { + return getGroupsToRemind(taskList, gtaNode); + } else { + return getIndividualsToRemind(taskList, entry); + } + } + + protected List<Identity> getGroupsToRemind(TaskList taskList, GTACourseNode gtaNode) { + List<Task> tasks = gtaManager.getTasks(taskList); + Set<BusinessGroup> doneTasks = new HashSet<BusinessGroup>(); + for(Task task:tasks) { + if(task.getBusinessGroup() != null) { + doneTasks.add(task.getBusinessGroup()); + } + } + + List<BusinessGroup> groups = gtaManager.getBusinessGroups(gtaNode); + for(Iterator<BusinessGroup> groupIt=groups.iterator(); groupIt.hasNext(); ) { + if(doneTasks.contains(groupIt.next())) { + groupIt.remove(); + } + } + + return businessGroupService.getMembers(groups, GroupRoles.participant.name()); + } + + protected List<Identity> getIndividualsToRemind(TaskList taskList, RepositoryEntry entry) { + List<Task> tasks = gtaManager.getTasks(taskList); + Set<Identity> doneTasks = new HashSet<Identity>(); + for(Task task:tasks) { + if(task.getIdentity() != null) { + doneTasks.add(task.getIdentity()); + } + } + + List<Identity> identities = repositoryEntryRelationDao.getMembers(entry, RepositoryEntryRelationType.both, GroupRoles.participant.name()); + for(Iterator<Identity> identityIt=identities.iterator(); identityIt.hasNext(); ) { + if(doneTasks.contains(identityIt.next())) { + identityIt.remove(); + } + } + + return identities; + } + + + private boolean near(Date date, Date now, int distance, LaunchUnit unit) { + double between = -1; + switch(unit) { + case day: + between = daysBetween(now, date); + break; + case week: + between = weeksBetween(now, date); + break; + case month: + between = monthsBetween(now, date); + break; + case year: + between = yearsBetween(now, date); + break; + } + return between <= distance || between < 0.0; + } + + private double daysBetween(Date d1, Date d2) { + return ((d2.getTime() - d1.getTime()) / (1000d * 60d * 60d * 24d)); + } + + private double weeksBetween(Date d1, Date d2) { + return ((d2.getTime() - d1.getTime()) / (1000d * 60d * 60d * 24d * 7d)); + } + + private double monthsBetween(Date d1, Date d2) { + return ((d2.getTime() - d1.getTime()) / (1000d * 60d * 60d * 24d * 30d)); + } + + private double yearsBetween(Date d1, Date d2) { + return ((d2.getTime() - d1.getTime()) / (1000d * 60d * 60d * 24d * 365d)); + } + + +} diff --git a/src/main/java/org/olat/course/nodes/gta/rule/AssignTaskRuleSPI.java b/src/main/java/org/olat/course/nodes/gta/rule/AssignTaskRuleSPI.java new file mode 100644 index 0000000000000000000000000000000000000000..d5ac5d5595776589fb81c92b3840b0433e8f85df --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/rule/AssignTaskRuleSPI.java @@ -0,0 +1,66 @@ +/** + * <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.gta.rule; + +import java.util.Date; + +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.ui.BeforeDateTaskRuleEditor; +import org.olat.modules.ModuleConfiguration; +import org.olat.modules.reminder.ReminderRule; +import org.olat.modules.reminder.RuleEditorFragment; +import org.olat.repository.RepositoryEntry; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 10.04.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class AssignTaskRuleSPI extends AbstractDueDateTaskRuleSPI { + + @Override + public String getLabelI18nKey() { + return "rule.assign.task"; + } + + @Override + public String getCategory() { + return "assessment"; + } + + @Override + public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) { + return new BeforeDateTaskRuleEditor(rule, entry, AssignTaskRuleSPI.class.getSimpleName()); + } + + @Override + protected Date getDueDate(GTACourseNode gtaNode) { + Date dueDate = null; + ModuleConfiguration config = gtaNode.getModuleConfiguration(); + boolean assignment = config.getBooleanSafe(GTACourseNode.GTASK_ASSIGNMENT); + if(assignment) { + dueDate = config.getDateValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE); + } + return dueDate; + } +} diff --git a/src/main/java/org/olat/course/nodes/gta/rule/SubmissionTaskRuleSPI.java b/src/main/java/org/olat/course/nodes/gta/rule/SubmissionTaskRuleSPI.java new file mode 100644 index 0000000000000000000000000000000000000000..a22e6eae58692835b78043362bc2a98d3b1de155 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/rule/SubmissionTaskRuleSPI.java @@ -0,0 +1,77 @@ +/** + * <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.gta.rule; + +import java.util.Date; + +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.ui.BeforeDateTaskRuleEditor; +import org.olat.group.BusinessGroupService; +import org.olat.modules.ModuleConfiguration; +import org.olat.modules.reminder.ReminderRule; +import org.olat.modules.reminder.RuleEditorFragment; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.manager.RepositoryEntryRelationDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 10.04.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class SubmissionTaskRuleSPI extends AbstractDueDateTaskRuleSPI { + + @Autowired + private GTAManager gtaManager; + @Autowired + private BusinessGroupService businessGroupService; + @Autowired + private RepositoryEntryRelationDAO repositoryEntryRelationDao; + + @Override + public String getLabelI18nKey() { + return "rule.submission.task"; + } + + @Override + public String getCategory() { + return "assessment"; + } + + @Override + public RuleEditorFragment getEditorFragment(ReminderRule rule, RepositoryEntry entry) { + return new BeforeDateTaskRuleEditor(rule, entry, SubmissionTaskRuleSPI.class.getSimpleName()); + } + + @Override + protected Date getDueDate(GTACourseNode gtaNode) { + Date dueDate = null; + ModuleConfiguration config = gtaNode.getModuleConfiguration(); + boolean submit = config.getBooleanSafe(GTACourseNode.GTASK_SUBMIT); + if(submit) { + dueDate = config.getDateValue(GTACourseNode.GTASK_SUBMIT_DEADLINE); + } + return dueDate; + } +} diff --git a/src/main/java/org/olat/course/nodes/gta/ui/BeforeDateTaskRuleEditor.java b/src/main/java/org/olat/course/nodes/gta/ui/BeforeDateTaskRuleEditor.java new file mode 100644 index 0000000000000000000000000000000000000000..81903de8019f2c85febf1b2b5c7689b29087bc3b --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/BeforeDateTaskRuleEditor.java @@ -0,0 +1,223 @@ +/** + * <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.gta.ui; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +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.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.CodeHelper; +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.nodes.CourseNode; +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.rule.AssignTaskRuleSPI; +import org.olat.course.nodes.gta.rule.SubmissionTaskRuleSPI; +import org.olat.modules.ModuleConfiguration; +import org.olat.modules.reminder.ReminderRule; +import org.olat.modules.reminder.RuleEditorFragment; +import org.olat.modules.reminder.model.ReminderRuleImpl; +import org.olat.modules.reminder.rule.LaunchUnit; +import org.olat.repository.RepositoryEntry; + +/** + * + * Initial date: 10.04.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class BeforeDateTaskRuleEditor extends RuleEditorFragment { + + private static final String[] unitKeys = new String[]{ + LaunchUnit.day.name(), LaunchUnit.week.name(), LaunchUnit.month.name(), LaunchUnit.year.name() + }; + + private TextElement valueEl; + private SingleSelection courseNodeEl, unitEl; + + private final String ruleType; + + private final RepositoryEntry entry; + + public BeforeDateTaskRuleEditor(ReminderRule rule, RepositoryEntry entry, String ruleType) { + super(rule); + this.entry = entry; + this.ruleType = ruleType; + } + + @Override + public FormItem initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + + String page = Util.getPackageVelocityRoot(this.getClass()) + "/date_rule.html"; + String id = Long.toString(CodeHelper.getRAMUniqueID()); + + Translator trans = Util + .createPackageTranslator(BeforeDateTaskRuleEditor.class, formLayout.getTranslator().getLocale(), formLayout.getTranslator()); + FormLayoutContainer ruleCont = FormLayoutContainer + .createCustomFormLayout("taks.".concat(id), formLayout.getTranslator(), page); + ruleCont.setRootForm(formLayout.getRootForm()); + ruleCont.setTranslator(trans); + formLayout.add(ruleCont); + + ICourse course = CourseFactory.loadCourse(entry.getOlatResource()); + + String currentValue = null; + String currentUnit = null; + String currentCourseNode = null; + + if(rule instanceof ReminderRuleImpl) { + ReminderRuleImpl r = (ReminderRuleImpl)rule; + currentUnit = r.getRightUnit(); + currentValue = r.getRightOperand(); + currentCourseNode = r.getLeftOperand(); + } + + List<CourseNode> attemptableNodes = new ArrayList<>(); + searchAttemptableNodes(course.getRunStructure().getRootNode(), attemptableNodes); + + String[] nodeKeys = new String[attemptableNodes.size()]; + String[] nodeValues = new String[attemptableNodes.size()]; + + for(int i=0; i<attemptableNodes.size(); i++) { + CourseNode attemptableNode = attemptableNodes.get(0); + nodeKeys[i] = attemptableNode.getIdent(); + nodeValues[i] = attemptableNode.getShortTitle() + " ( " + attemptableNode.getIdent() + " )"; + } + + courseNodeEl = uifactory.addDropdownSingleselect("coursenodes", null, ruleCont, nodeKeys, nodeValues, null); + courseNodeEl.setDomReplacementWrapperRequired(false); + boolean nodeSelected = false; + if(currentCourseNode != null) { + for(String nodeKey:nodeKeys) { + if(currentCourseNode.equals(nodeKey)) { + courseNodeEl.select(nodeKey, true); + nodeSelected = true; + } + } + } + if(!nodeSelected && nodeKeys.length > 0) { + courseNodeEl.select(nodeKeys[0], true); + } + if(StringHelper.containsNonWhitespace(currentCourseNode) && !nodeSelected) { + courseNodeEl.setErrorKey("error.course.node.found", null); + } + + valueEl = uifactory.addTextElement("value", null, 128, currentValue, ruleCont); + valueEl.setDomReplacementWrapperRequired(false); + valueEl.setDisplaySize(3); + + String[] unitValues = new String[] { + trans.translate(LaunchUnit.day.name()), trans.translate(LaunchUnit.week.name()), + trans.translate(LaunchUnit.month.name()), trans.translate(LaunchUnit.year.name()) + }; + + unitEl = uifactory.addDropdownSingleselect("unit", null, ruleCont, unitKeys, unitValues, null); + unitEl.setDomReplacementWrapperRequired(false); + boolean selected = false; + if(currentUnit != null) { + for(String unitKey:unitKeys) { + if(currentUnit.equals(unitKey)) { + unitEl.select(unitKey, true); + selected = true; + } + } + } + if(!selected) { + unitEl.select(unitKeys[1], true); + } + + return ruleCont; + } + + private void searchAttemptableNodes(CourseNode courseNode, List<CourseNode> nodes) { + if (courseNode instanceof GTACourseNode) { + GTACourseNode assessableCourseNode = (GTACourseNode) courseNode; + ModuleConfiguration config = assessableCourseNode.getModuleConfiguration(); + + if(AssignTaskRuleSPI.class.getSimpleName().equals(ruleType)) { + boolean assignment = config.getBooleanSafe(GTACourseNode.GTASK_ASSIGNMENT); + Date dueDate = config.getDateValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE); + if(assignment && dueDate != null) { + nodes.add(courseNode); + } + } else if(SubmissionTaskRuleSPI.class.getSimpleName().equals(ruleType)) { + boolean submit = config.getBooleanSafe(GTACourseNode.GTASK_SUBMIT); + Date dueDate = config.getDateValue(GTACourseNode.GTASK_SUBMIT_DEADLINE); + if(submit && dueDate != null) { + nodes.add(courseNode); + } + } + } + + for(int i=0; i<courseNode.getChildCount(); i++) { + CourseNode child = (CourseNode)courseNode.getChildAt(i); + searchAttemptableNodes(child, nodes); + } + } + + @Override + public boolean validateFormLogic(UserRequest ureq) { + boolean allOk = true; + + courseNodeEl.clearError(); + if(!courseNodeEl.isOneSelected()) { + courseNodeEl.setErrorKey("form.mandatory.hover", null); + allOk &= false; + } + + unitEl.clearError(); + if(!unitEl.isOneSelected()) { + unitEl.setErrorKey("form.mandatory.hover", null); + allOk &= false; + } + + valueEl.clearError(); + if(!StringHelper.containsNonWhitespace(valueEl.getValue())) { + valueEl.setErrorKey("form.mandatory.hover", null); + allOk &= false; + } + + return allOk; + } + + @Override + public ReminderRule getConfiguration() { + ReminderRuleImpl configuredRule = null; + if(courseNodeEl.isOneSelected() && unitEl.isOneSelected() && StringHelper.containsNonWhitespace(valueEl.getValue())) { + configuredRule = new ReminderRuleImpl(); + configuredRule.setType(ruleType); + configuredRule.setLeftOperand(courseNodeEl.getSelectedKey()); + configuredRule.setOperator("<"); + configuredRule.setRightOperand(valueEl.getValue()); + configuredRule.setRightUnit(unitEl.getSelectedKey()); + } + return configuredRule; + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/date_rule.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/date_rule.html new file mode 100644 index 0000000000000000000000000000000000000000..0ed17292af8490454e9fad32b7819360db7636a2 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/date_rule.html @@ -0,0 +1,9 @@ +<div class='form-inline'> + $r.render("coursenodes") $r.render("value") $r.render("unit") <span class="form-control-static">$r.translate("before")</span> + #if($f.hasError("value")) + <br/>$r.render("value_ERROR") + #end + #if($f.hasError("coursenodes")) + <br/>$r.render("coursenodes_ERROR") + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties index 8cf18bb2634bd73fdc370c8fbec7ced2082dd974..65ef7cf8a243d21015002def9d60d13a4ad7b2c3 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_de.properties @@ -4,6 +4,7 @@ add.task=Aufgaben hochladen assessment.group.tool=Gruppe bewerten assignment.config.title=Aufgabe zuweisen assignment.deadline=Zuweisungstermin +before=Vor bulk.review=Beurteilung herunterladen bulk.solutions=Musterl\u00F6sungen herunterladen bulk.submitted.documents=Abgegebene Dokumenten diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties index 62659e3c01a81e7b4bfedce02f4d46f838abcc96..dbb66927a8401f02284a3a4e1361c662892beb89 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_en.properties @@ -3,6 +3,7 @@ add.solution=Add solution add.task=Add task assignment.config.title=Task assignment configuration assignment.deadline=Assignment deadline +before=Before bulk.review=Download review bulk.solutions=Download solutions bulk.submitted.documents=Download submitted documents diff --git a/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java b/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java index 11c2561ebd01014fb0f8e50a9ea93004928e28b8..adb5c0cef05cab3f959538ebf526f3aa359e4967 100644 --- a/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java +++ b/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java @@ -155,7 +155,7 @@ public class CourseReminderListController extends FormBasicController implements String entryPoint = entry.getOLATResourceable().getResourceableTypeName(); if("SentReminders".equalsIgnoreCase(entryPoint)) { Long key = entry.getOLATResourceable().getResourceableId(); - System.out.println(key); + doSendReminderList(ureq, key); } } @@ -239,14 +239,14 @@ public class CourseReminderListController extends FormBasicController implements toolbarPanel.pushController(translate("new.reminder"), reminderEditCtrl); } - private void doSendReminderList(UserRequest ureq, ReminderRow row) { + private void doSendReminderList(UserRequest ureq, Long reminderKey) { removeAsListenerAndDispose(sendReminderListCtrl); - OLATResourceable ores = OresHelper.createOLATResourceableInstance("SentReminders", row.getKey()); + OLATResourceable ores = OresHelper.createOLATResourceableInstance("SentReminders", reminderKey); ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores)); WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl()); - Reminder reminder = reminderManager.loadByKey(row.getKey()); + Reminder reminder = reminderManager.loadByKey(reminderKey); sendReminderListCtrl = new CourseSendReminderListController(ureq, bwControl, reminder); listenTo(sendReminderListCtrl); addToHistory(ureq, sendReminderListCtrl); @@ -336,7 +336,7 @@ public class CourseReminderListController extends FormBasicController implements if("edit".equals(cmd)) { doEdit(ureq, row); } else if("show.sent".equals(cmd)) { - doSendReminderList(ureq, row); + doSendReminderList(ureq, row.getKey()); } else if("delete".equals(cmd)) { doConfirmDelete(ureq, row); } else if("duplicate".equals(cmd)) { diff --git a/src/main/java/org/olat/course/reminder/ui/InitialAttemptsRuleEditor.java b/src/main/java/org/olat/course/reminder/ui/InitialAttemptsRuleEditor.java index 5cbe91afeca3ee07525c55d187ed5afc3c5b1acd..55a3bf2e2f90c1a89c1e6f3dc989ab01f787fdf4 100644 --- a/src/main/java/org/olat/course/reminder/ui/InitialAttemptsRuleEditor.java +++ b/src/main/java/org/olat/course/reminder/ui/InitialAttemptsRuleEditor.java @@ -29,6 +29,7 @@ import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; +import org.olat.core.gui.translator.Translator; import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; @@ -72,6 +73,7 @@ public class InitialAttemptsRuleEditor extends RuleEditorFragment { String page = Util.getPackageVelocityRoot(this.getClass()) + "/initial_attempts.html"; String id = Long.toString(CodeHelper.getRAMUniqueID()); + Translator trans = formLayout.getTranslator(); FormLayoutContainer ruleCont = FormLayoutContainer .createCustomFormLayout("attempts.".concat(id), formLayout.getTranslator(), page); ruleCont.setRootForm(formLayout.getRootForm()); @@ -124,9 +126,10 @@ public class InitialAttemptsRuleEditor extends RuleEditorFragment { valueEl = uifactory.addTextElement("attemptvalue", null, 128, currentValue, ruleCont); valueEl.setDomReplacementWrapperRequired(false); valueEl.setDisplaySize(3); - + String[] unitValues = new String[] { - LaunchUnit.day.name(), LaunchUnit.week.name(), LaunchUnit.month.name(), LaunchUnit.year.name() + trans.translate(LaunchUnit.day.name()), trans.translate(LaunchUnit.week.name()), + trans.translate(LaunchUnit.month.name()), trans.translate(LaunchUnit.year.name()) }; unitEl = uifactory.addDropdownSingleselect("attemptunit", null, ruleCont, unitKeys, unitValues, null); diff --git a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties index 01b65c1fa9db499330a1c519910d91b1bd15046b..02208cb92f3a8e7836741e0085c7fe0b922e5bbb 100644 --- a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_de.properties @@ -7,6 +7,7 @@ course.role.owner=Besitzer course.role.ownerAndCoach=Besitzer und Coach course.role.participant=Teilnehmer course.role.participantAndCoach=Coach und Teilnehmer +day=Tagen delete.rule=- dialog.modal.delete.text=Wollen Sie wirklich diese Errinerung "{0}" l\u00F6schen? duplicate=Duplizieren @@ -15,6 +16,7 @@ email.content=E-Mail error.course.node.found=Kurs Element existiert nicht mehr failed=Failed logs=Logs +month=Monaten new.reminder=Neue Erinnerung passed=Passed points=Punkte @@ -23,10 +25,12 @@ reminder.id=ID reminder.resend=Errinerung wurde erfolgreisch geschickt. reminders=Errinerungen resend=Wieder schicken +rule.assign.task=Grupenaufgabe Zuweisung rule.attempts=Attempts rule.initial.attempts.date=Initial attempt date rule.passed=Passed rule.score=Score +rule.submission.task=Grupenaufgabe Dokumenten abgeben rules.description=When matching all of the following conditions send=Erinnerung jetzt schicken send.reminder=Geschickte Errinerungen @@ -43,3 +47,5 @@ table.header.sendTime=Send time table.header.status=Status table.header.username=Benutzername tools=Werkzeug +week=Wochen +year=Jahren diff --git a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties index 83d36ab2ec1bcb202dc87b85aff5255412fa3f7b..50e1dec8add84075c75ba4909575ec24957c21b1 100644 --- a/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/reminder/ui/_i18n/LocalStrings_en.properties @@ -7,6 +7,7 @@ course.role.owner=Owners course.role.ownerAndCoach=Owners and coachs course.role.participant=Participants course.role.participantAndCoach=Coachs and participants +day=Days delete.rule=- dialog.modal.delete.text=Do your really want to delete this reminder "{0}"? duplicate=Douplicate @@ -15,6 +16,7 @@ email.content=E-Mail error.course.node.found=The cours element doesn't exist failed=Failed logs=Logs +month=Months new.reminder=New reminder passed=Passed points=Points @@ -24,9 +26,11 @@ reminder.resend=Reminder was successfully sent. reminders=Errinerungen resend=Resend rule.attempts=Attempts +rule.assign.task=Group task assignment rule.initial.attempts.date=Initial attempt date rule.passed=Passed rule.score=Score +rule.submission.task=Group task documents submission rules.description=When matching all of the following conditions send=Send reminders now send.reminder=Send reminders @@ -43,3 +47,5 @@ table.header.sendTime=Send time table.header.status=Status table.header.username=Username tools=Tools +weeks=Weeks +year=Years diff --git a/src/main/java/org/olat/modules/reminder/IdentitiesProviderRuleSPI.java b/src/main/java/org/olat/modules/reminder/IdentitiesProviderRuleSPI.java new file mode 100644 index 0000000000000000000000000000000000000000..90853dc55bb80067bd7ed0673dfbbebc6e9bd911 --- /dev/null +++ b/src/main/java/org/olat/modules/reminder/IdentitiesProviderRuleSPI.java @@ -0,0 +1,39 @@ +/** + * <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.modules.reminder; + +import java.util.List; + +import org.olat.core.id.Identity; +import org.olat.repository.RepositoryEntry; + +/** + * + * Rules which deliver a list of identities to remind + * + * Initial date: 10.04.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface IdentitiesProviderRuleSPI extends RuleSPI { + + public List<Identity> evaluate(RepositoryEntry entry, ReminderRule rule); + +} diff --git a/src/main/java/org/olat/modules/reminder/manager/ReminderRuleEngine.java b/src/main/java/org/olat/modules/reminder/manager/ReminderRuleEngine.java index b7cd349daef872793ac0e2dc2f535818b4b3591a..b2d7592fb40a640b9d453233c23f0d2dfb8636a9 100644 --- a/src/main/java/org/olat/modules/reminder/manager/ReminderRuleEngine.java +++ b/src/main/java/org/olat/modules/reminder/manager/ReminderRuleEngine.java @@ -29,6 +29,7 @@ import java.util.Set; import org.olat.basesecurity.GroupRoles; import org.olat.core.id.Identity; import org.olat.modules.reminder.FilterRuleSPI; +import org.olat.modules.reminder.IdentitiesProviderRuleSPI; import org.olat.modules.reminder.Reminder; import org.olat.modules.reminder.ReminderModule; import org.olat.modules.reminder.ReminderRule; @@ -122,18 +123,19 @@ public class ReminderRuleEngine { } protected List<Identity> getIdentities(RepositoryEntry entry, Reminder reminder, List<ReminderRule> ruleList, boolean resend) { - List<ReminderRule> roleRules = new ArrayList<>(); + List<ReminderRule> identitiesProviderRules = new ArrayList<>(); for(Iterator<ReminderRule> ruleIt=ruleList.iterator(); ruleIt.hasNext(); ) { ReminderRule rule = ruleIt.next(); - if(REPO_ROLE_RULE_TYPE.equals(rule.getType()) || BUSINESSGROUP_ROLE_RULE_TYPE.equals(rule.getType())) { - roleRules.add(rule); + RuleSPI ruleSpi = reminderModule.getRuleSPIByType(rule.getType()); + if(ruleSpi instanceof IdentitiesProviderRuleSPI) { + identitiesProviderRules.add(rule); ruleIt.remove(); } } List<Identity> identities; - if(roleRules.isEmpty()) { + if(identitiesProviderRules.isEmpty()) { //all members of repository entry List<Identity> duplicatedIdentities = repositoryEntryRelationDao.getMembers(entry, RepositoryEntryRelationType.both, GroupRoles.owner.name(), GroupRoles.coach.name(), GroupRoles.participant.name()); @@ -141,14 +143,10 @@ public class ReminderRuleEngine { } else { identities = null; - for(ReminderRule rule:roleRules) { - List<Identity> members = null; - if(REPO_ROLE_RULE_TYPE.equals(rule.getType())) { - members = repoRoleRuleSpi.evaluate(entry, rule); - } else if(BUSINESSGROUP_ROLE_RULE_TYPE.equals(rule.getType())) { - members = groupRoleRuleSpi.evaluate(rule); - } - + for(ReminderRule rule:identitiesProviderRules) { + RuleSPI ruleSpi = reminderModule.getRuleSPIByType(rule.getType()); + IdentitiesProviderRuleSPI identitiesProviderRuleSpi = (IdentitiesProviderRuleSPI)ruleSpi; + List<Identity> members = identitiesProviderRuleSpi.evaluate(entry, rule); if(identities == null) { identities = members; } else { diff --git a/src/main/java/org/olat/modules/reminder/rule/AbstractLaunchDateRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/AbstractLaunchDateRuleSPI.java index 6bb057aa230632fc7798130f86a3414644b41707..0320968df7aaf95ae5e6f57981841237ad41a5e1 100644 --- a/src/main/java/org/olat/modules/reminder/rule/AbstractLaunchDateRuleSPI.java +++ b/src/main/java/org/olat/modules/reminder/rule/AbstractLaunchDateRuleSPI.java @@ -73,14 +73,14 @@ public abstract class AbstractLaunchDateRuleSPI implements FilterRuleSPI { Date initialLaunchDate = initialLaunchDates.get(identity.getKey()); if(initialLaunchDate == null) { identityIt.remove(); - } else if(!evaluate(initialLaunchDate, now, distance, unit)) { + } else if(!after(initialLaunchDate, now, distance, unit)) { identityIt.remove(); } } } } - private boolean evaluate(Date date, Date now, int distance, LaunchUnit unit) { + private boolean after(Date date, Date now, int distance, LaunchUnit unit) { double between = -1; switch(unit) { case day: diff --git a/src/main/java/org/olat/modules/reminder/rule/BusinessGroupRoleRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/BusinessGroupRoleRuleSPI.java index 8e360a466f8869368203e6d082b59bdb4c2b21a7..c869ec73b6a7c79904f614efac3a72a4d47043ea 100644 --- a/src/main/java/org/olat/modules/reminder/rule/BusinessGroupRoleRuleSPI.java +++ b/src/main/java/org/olat/modules/reminder/rule/BusinessGroupRoleRuleSPI.java @@ -28,9 +28,9 @@ import org.olat.core.util.StringHelper; import org.olat.group.BusinessGroupRef; import org.olat.group.manager.BusinessGroupRelationDAO; import org.olat.group.model.BusinessGroupRefImpl; +import org.olat.modules.reminder.IdentitiesProviderRuleSPI; import org.olat.modules.reminder.ReminderRule; import org.olat.modules.reminder.RuleEditorFragment; -import org.olat.modules.reminder.RuleSPI; import org.olat.modules.reminder.model.ReminderRuleImpl; import org.olat.modules.reminder.ui.BusinessGroupRoleEditor; import org.olat.repository.RepositoryEntry; @@ -44,7 +44,7 @@ import org.springframework.stereotype.Service; * */ @Service -public class BusinessGroupRoleRuleSPI implements RuleSPI { +public class BusinessGroupRoleRuleSPI implements IdentitiesProviderRuleSPI { @Autowired private BusinessGroupRelationDAO businessGroupRelationDao; @@ -64,7 +64,8 @@ public class BusinessGroupRoleRuleSPI implements RuleSPI { return new BusinessGroupRoleEditor(rule, entry); } - public List<Identity> evaluate(ReminderRule rule) { + @Override + public List<Identity> evaluate(RepositoryEntry entry, ReminderRule rule) { List<Identity> identities = null; if(rule instanceof ReminderRuleImpl) { diff --git a/src/main/java/org/olat/modules/reminder/rule/RepositoryEntryRoleRuleSPI.java b/src/main/java/org/olat/modules/reminder/rule/RepositoryEntryRoleRuleSPI.java index 81ed16fd6b40f60711f738deeafe650c06e8a78a..236ef2f3f0d1f0fbad62e20c472f577d7ee3f401 100644 --- a/src/main/java/org/olat/modules/reminder/rule/RepositoryEntryRoleRuleSPI.java +++ b/src/main/java/org/olat/modules/reminder/rule/RepositoryEntryRoleRuleSPI.java @@ -25,9 +25,9 @@ import java.util.List; import org.olat.basesecurity.GroupRoles; import org.olat.core.id.Identity; import org.olat.core.util.StringHelper; +import org.olat.modules.reminder.IdentitiesProviderRuleSPI; import org.olat.modules.reminder.ReminderRule; import org.olat.modules.reminder.RuleEditorFragment; -import org.olat.modules.reminder.RuleSPI; import org.olat.modules.reminder.model.ReminderRuleImpl; import org.olat.modules.reminder.ui.RepositoryEntryRoleEditor; import org.olat.repository.RepositoryEntry; @@ -43,7 +43,7 @@ import org.springframework.stereotype.Service; * */ @Service -public class RepositoryEntryRoleRuleSPI implements RuleSPI { +public class RepositoryEntryRoleRuleSPI implements IdentitiesProviderRuleSPI { @Autowired private RepositoryEntryRelationDAO repositoryEntryRelationDao; @@ -63,7 +63,7 @@ public class RepositoryEntryRoleRuleSPI implements RuleSPI { return new RepositoryEntryRoleEditor(rule); } - + @Override public List<Identity> evaluate(RepositoryEntry entry, ReminderRule rule) { List<Identity> identities = null; if(rule instanceof ReminderRuleImpl) { diff --git a/src/main/java/org/olat/modules/reminder/ui/CourseLaunchRuleEditor.java b/src/main/java/org/olat/modules/reminder/ui/CourseLaunchRuleEditor.java index 611f9e07a8bc5ab2e9d7c2126c684fa3d0eede8f..c4d916d77bbbf89ec6d473e7a00c544ff39fb0c4 100644 --- a/src/main/java/org/olat/modules/reminder/ui/CourseLaunchRuleEditor.java +++ b/src/main/java/org/olat/modules/reminder/ui/CourseLaunchRuleEditor.java @@ -26,6 +26,7 @@ import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; +import org.olat.core.gui.translator.Translator; import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; @@ -61,6 +62,7 @@ public class CourseLaunchRuleEditor extends RuleEditorFragment { String page = Util.getPackageVelocityRoot(this.getClass()) + "/course_launch.html"; String id = Long.toString(CodeHelper.getRAMUniqueID()); + Translator trans = formLayout.getTranslator(); FormLayoutContainer ruleCont = FormLayoutContainer .createCustomFormLayout("course.launch.".concat(id), formLayout.getTranslator(), page); ruleCont.setRootForm(formLayout.getRootForm()); @@ -79,10 +81,10 @@ public class CourseLaunchRuleEditor extends RuleEditorFragment { valueEl.setDisplaySize(3); String[] unitValues = new String[] { - LaunchUnit.day.name(), LaunchUnit.week.name(), LaunchUnit.month.name(), LaunchUnit.year.name() + trans.translate(LaunchUnit.day.name()), trans.translate(LaunchUnit.week.name()), + trans.translate(LaunchUnit.month.name()), trans.translate(LaunchUnit.year.name()) }; - unitEl = uifactory.addDropdownSingleselect("launchunit", null, ruleCont, unitKeys, unitValues, null); unitEl.setDomReplacementWrapperRequired(false); boolean selected = false; diff --git a/src/test/java/org/olat/course/nodes/gta/rule/GTAReminderRuleTest.java b/src/test/java/org/olat/course/nodes/gta/rule/GTAReminderRuleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..27de702b6b9fef27b7b3ffe6d32ae5af22075549 --- /dev/null +++ b/src/test/java/org/olat/course/nodes/gta/rule/GTAReminderRuleTest.java @@ -0,0 +1,308 @@ +/** + * <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.gta.rule; + +import java.io.File; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.olat.basesecurity.GroupRoles; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.course.nodes.GTACourseNode; +import org.olat.course.nodes.gta.AssignmentResponse; +import org.olat.course.nodes.gta.GTAType; +import org.olat.course.nodes.gta.TaskList; +import org.olat.course.nodes.gta.manager.GTAManagerImpl; +import org.olat.group.BusinessGroup; +import org.olat.group.manager.BusinessGroupDAO; +import org.olat.group.manager.BusinessGroupRelationDAO; +import org.olat.modules.reminder.model.ReminderRuleImpl; +import org.olat.modules.reminder.rule.LaunchUnit; +import org.olat.modules.vitero.model.GroupRole; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.manager.RepositoryEntryRelationDAO; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 10.04.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class GTAReminderRuleTest extends OlatTestCase { + + @Autowired + private DB dbInstance; + @Autowired + private GTAManagerImpl gtaManager; + @Autowired + private BusinessGroupDAO businessGroupDao; + @Autowired + private BusinessGroupRelationDAO businessGroupRelationDao; + @Autowired + private RepositoryEntryRelationDAO repositoryEntryRelationDao; + + + @Autowired + private AssignTaskRuleSPI assignTaskRuleSPI; + @Autowired + private SubmissionTaskRuleSPI submissionTaskRuleSPI; + + @Test + public void assignTask_individual() { + //prepare a course with a volatile task + Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-1"); + Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-2"); + RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); + repositoryEntryRelationDao.addRole(participant1, re, GroupRoles.participant.name()); + repositoryEntryRelationDao.addRole(participant2, re, GroupRoles.participant.name()); + dbInstance.commit(); + + GTACourseNode node = new GTACourseNode(); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); + + Calendar cal = Calendar.getInstance(); + cal.add(2, Calendar.MONTH); + node.getModuleConfiguration().setDateValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE, cal.getTime()); + TaskList tasks = gtaManager.createIfNotExists(re, node); + File taskFile = new File("solo.txt"); + Assert.assertNotNull(tasks); + dbInstance.commit(); + + //select a task + AssignmentResponse response = gtaManager.selectTask(participant1, tasks, node, taskFile); + dbInstance.commitAndCloseSession(); + Assert.assertEquals(AssignmentResponse.Status.ok, response.getStatus()); + + //only remind participant 2 + List<Identity> toRemind = assignTaskRuleSPI.getPeopleToRemind(re, node); + Assert.assertEquals(1, toRemind.size()); + Assert.assertTrue(toRemind.contains(participant2)); + + + { // check before 30 days + ReminderRuleImpl rule = getAssignedTaskRules(30, LaunchUnit.day); + List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(0, all.size()); + } + + { // check before 5 weeks + ReminderRuleImpl rule = getAssignedTaskRules(5, LaunchUnit.week); + List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(0, all.size()); + } + + { // check before 1 month + ReminderRuleImpl rule = getAssignedTaskRules(1, LaunchUnit.month); + List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(0, all.size()); + } + + { // check before 90 days + ReminderRuleImpl rule = getAssignedTaskRules(90, LaunchUnit.day); + List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(1, all.size()); + Assert.assertTrue(toRemind.contains(participant2)); + } + + { // check before 12 weeks + ReminderRuleImpl rule = getAssignedTaskRules(12, LaunchUnit.week); + List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(1, all.size()); + Assert.assertTrue(toRemind.contains(participant2)); + } + + { // check before 3 month + ReminderRuleImpl rule = getAssignedTaskRules(3, LaunchUnit.month); + List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(1, all.size()); + Assert.assertTrue(toRemind.contains(participant2)); + } + + { // check before 1 year + ReminderRuleImpl rule = getAssignedTaskRules(1, LaunchUnit.year); + List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(1, all.size()); + Assert.assertTrue(toRemind.contains(participant2)); + } + } + + private ReminderRuleImpl getAssignedTaskRules(int amount, LaunchUnit unit) { + ReminderRuleImpl rule = new ReminderRuleImpl(); + rule.setType(AssignTaskRuleSPI.class.getSimpleName()); + rule.setOperator("<"); + rule.setRightOperand(Integer.toString(amount)); + rule.setRightUnit(unit.name()); + return rule; + } + + @Test + public void assignTask_businessGroup() { + //prepare + Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-2"); + Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-3"); + Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-4"); + Identity participant3 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-5"); + Identity participant4 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-6"); + + BusinessGroup businessGroup1 = businessGroupDao.createAndPersist(coach, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); + BusinessGroup businessGroup2 = businessGroupDao.createAndPersist(coach, "gdao", "gdao-desc", -1, -1, false, false, false, false, false); + + businessGroupRelationDao.addRole(participant1, businessGroup1, GroupRole.participant.name()); + businessGroupRelationDao.addRole(participant2, businessGroup1, GroupRole.participant.name()); + businessGroupRelationDao.addRole(participant3, businessGroup2, GroupRole.participant.name()); + businessGroupRelationDao.addRole(participant4, businessGroup2, GroupRole.participant.name()); + dbInstance.commit(); + + RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); + businessGroupRelationDao.addRelationToResource(businessGroup1, re); + businessGroupRelationDao.addRelationToResource(businessGroup2, re); + + GTACourseNode node = new GTACourseNode(); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.group.name()); + List<Long> groupKeys = new ArrayList<>(2); + groupKeys.add(businessGroup1.getKey()); + groupKeys.add(businessGroup2.getKey()); + node.getModuleConfiguration().setList(GTACourseNode.GTASK_GROUPS, groupKeys); + TaskList tasks = gtaManager.createIfNotExists(re, node); + File taskFile = new File("bg.txt"); + Assert.assertNotNull(tasks); + dbInstance.commit(); + + // group 1 select a task + AssignmentResponse response = gtaManager.selectTask(businessGroup1, tasks, node, taskFile); + dbInstance.commitAndCloseSession(); + Assert.assertEquals(AssignmentResponse.Status.ok, response.getStatus()); + + // only remind group 2 + List<Identity> toRemind = assignTaskRuleSPI.getPeopleToRemind(re, node); + Assert.assertEquals(2, toRemind.size()); + Assert.assertTrue(toRemind.contains(participant3)); + Assert.assertTrue(toRemind.contains(participant4)); + } + + @Test + public void submitTask_individual() { + //prepare a course with a volatile task + Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-1"); + Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("gta-user-2"); + RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry("", false); + repositoryEntryRelationDao.addRole(participant1, re, GroupRoles.participant.name()); + repositoryEntryRelationDao.addRole(participant2, re, GroupRoles.participant.name()); + dbInstance.commit(); + + GTACourseNode node = new GTACourseNode(); + node.getModuleConfiguration().setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); + + Calendar cal = Calendar.getInstance(); + cal.add(2, Calendar.MONTH); + node.getModuleConfiguration().setDateValue(GTACourseNode.GTASK_SUBMIT_DEADLINE, cal.getTime()); + TaskList tasks = gtaManager.createIfNotExists(re, node); + File taskFile = new File("solo.txt"); + Assert.assertNotNull(tasks); + dbInstance.commit(); + + //select a task + AssignmentResponse response = gtaManager.selectTask(participant1, tasks, node, taskFile); + dbInstance.commitAndCloseSession(); + Assert.assertEquals(AssignmentResponse.Status.ok, response.getStatus()); + + //only remind participant 2 + List<Identity> toRemind = submissionTaskRuleSPI.getPeopleToRemind(re, node); + Assert.assertEquals(1, toRemind.size()); + Assert.assertTrue(toRemind.contains(participant2)); + + + { // check before 30 days + ReminderRuleImpl rule = getSubmitTaskRules(30, LaunchUnit.day); + List<Identity> all = submissionTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(0, all.size()); + } + + { // check before 5 weeks + ReminderRuleImpl rule = getSubmitTaskRules(5, LaunchUnit.week); + List<Identity> all = submissionTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(0, all.size()); + } + + { // check before 1 month + ReminderRuleImpl rule = getSubmitTaskRules(1, LaunchUnit.month); + List<Identity> all = submissionTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(0, all.size()); + } + + { // check before 90 days + ReminderRuleImpl rule = getSubmitTaskRules(90, LaunchUnit.day); + List<Identity> all = submissionTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(1, all.size()); + Assert.assertTrue(toRemind.contains(participant2)); + } + + { // check before 12 weeks + ReminderRuleImpl rule = getSubmitTaskRules(12, LaunchUnit.week); + List<Identity> all = submissionTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(1, all.size()); + Assert.assertTrue(toRemind.contains(participant2)); + } + + { // check before 3 month + ReminderRuleImpl rule = getSubmitTaskRules(3, LaunchUnit.month); + List<Identity> all = submissionTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(1, all.size()); + Assert.assertTrue(toRemind.contains(participant2)); + } + + { // check before 1 year + ReminderRuleImpl rule = getSubmitTaskRules(1, LaunchUnit.year); + List<Identity> all = submissionTaskRuleSPI.evaluateRule(re, node, rule); + + Assert.assertEquals(1, all.size()); + Assert.assertTrue(toRemind.contains(participant2)); + } + } + + private ReminderRuleImpl getSubmitTaskRules(int amount, LaunchUnit unit) { + ReminderRuleImpl rule = new ReminderRuleImpl(); + rule.setType(SubmissionTaskRuleSPI.class.getSimpleName()); + rule.setOperator("<"); + rule.setRightOperand(Integer.toString(amount)); + rule.setRightUnit(unit.name()); + return rule; + } +} diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index a1e9b9d34f8aafe89dc76c69045bf10f2e4de9ef..22ba3c1efe2b803bddf8251d919ffe2caae20f74 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -125,6 +125,7 @@ import org.junit.runners.Suite; org.olat.course.nodes.en.EnrollmentManagerSerialTest.class, org.olat.course.nodes.en.EnrollmentManagerConcurrentTest.class, org.olat.course.nodes.gta.manager.GTAManagerTest.class, + org.olat.course.nodes.gta.rule.GTAReminderRuleTest.class, org.olat.course.assessment.AssessmentManagerTest.class, org.olat.course.assessment.manager.UserCourseInformationsManagerTest.class, org.olat.course.assessment.manager.AssessmentModeManagerTest.class,