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 eebc0e9c90591dc9da9d7e1b3de8805363d343b6..11581dedcef8a08672b91e2bf9a9c3f253e62dea 100644 --- a/src/main/java/org/olat/course/nodes/gta/GTAManager.java +++ b/src/main/java/org/olat/course/nodes/gta/GTAManager.java @@ -353,6 +353,10 @@ public interface GTAManager { public Task resetTaskRefused(Task task, GTACourseNode cNode); + public boolean toggleMark(RepositoryEntry entry, GTACourseNode gtaNode, Identity marker, Identity participant); + + public List<IdentityMark> getMarks(RepositoryEntry entry, GTACourseNode gtaNode, Identity marker); + public void log(String step, String operation, Task assignedTask, Identity actor, Identity assessedIdentity, BusinessGroup assessedGroup, CourseEnvironment courseEnv, GTACourseNode cNode); diff --git a/src/main/java/org/olat/course/nodes/gta/IdentityMark.java b/src/main/java/org/olat/course/nodes/gta/IdentityMark.java new file mode 100644 index 0000000000000000000000000000000000000000..13eabed3f4fc483043ec5b59cba4928ae255a1cf --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/IdentityMark.java @@ -0,0 +1,49 @@ +/** + * <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; + +import org.olat.core.id.CreateInfo; +import org.olat.core.id.Identity; +import org.olat.core.id.ModifiedInfo; + +/** + * + * Initial date: 02.10.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public interface IdentityMark extends CreateInfo, ModifiedInfo { + + public TaskList getTaskList(); + + public void setTaskList(TaskList taskList); + + /** + * The marker is the identity how has set the mark. + */ + public Identity getMarker(); + + public void setMarker(Identity marker); + + public Identity getParticipant(); + + public void setParticipant(Identity participant); + +} diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAIdentityMarkDAO.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAIdentityMarkDAO.java new file mode 100644 index 0000000000000000000000000000000000000000..3c0042b897b3f6c9587fb5d54bd88293e642a591 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAIdentityMarkDAO.java @@ -0,0 +1,108 @@ +/** + * <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.manager; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.course.nodes.gta.IdentityMark; +import org.olat.course.nodes.gta.TaskList; +import org.olat.course.nodes.gta.model.IdentityMarkImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 03.10.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Service +public class GTAIdentityMarkDAO { + + @Autowired + private DB dbInstance; + + public IdentityMark createAndPersisitMark(TaskList taskList, Identity marker, Identity participant) { + IdentityMarkImpl mark = new IdentityMarkImpl(); + Date creationDate = new Date(); + mark.setCreationDate(creationDate); + mark.setLastModified(creationDate); + mark.setTaskList(taskList); + mark.setMarker(marker); + mark.setParticipant(participant); + dbInstance.getCurrentEntityManager().persist(mark); + return mark; + } + + public List<IdentityMark> loadMarks(TaskList taskList, Identity marker) { + if (taskList == null || taskList.getKey() == null || marker == null || marker.getKey() == null) + return new ArrayList<>(); + + return dbInstance.getCurrentEntityManager() + .createNamedQuery("loadByMarker", IdentityMark.class) + .setParameter("taskListKey", taskList.getKey()) + .setParameter("markerKey", marker.getKey()) + .getResultList(); + } + + public boolean isMarked(TaskList taskList, Identity marker, Identity participant) { + if (taskList == null || taskList.getKey() == null || marker == null || marker.getKey() == null + || participant == null || participant.getKey() == null) { + return false; + } + + List<IdentityMark> marks = dbInstance.getCurrentEntityManager() + .createNamedQuery("loadByMarkerAndParticipant", IdentityMark.class) + .setParameter("taskListKey", taskList.getKey()) + .setParameter("markerKey", marker.getKey()) + .setParameter("participantKey", participant.getKey()) + .getResultList(); + + return !marks.isEmpty(); + } + + public void deleteMark(TaskList taskList, Identity marker, Identity participant) { + if (taskList == null || taskList.getKey() == null || marker == null || marker.getKey() == null + || participant == null || participant.getKey() == null) { + return; + } + + dbInstance.getCurrentEntityManager() + .createNamedQuery("deleteByMarker") + .setParameter("taskListKey", taskList.getKey()) + .setParameter("markerKey", marker.getKey()) + .setParameter("participantKey", participant.getKey()) + .executeUpdate(); + } + + public int deleteMark(TaskList taskList) { + if (taskList == null || taskList.getKey() == null) return 0; + + return dbInstance.getCurrentEntityManager() + .createNamedQuery("deleteByTaskList") + .setParameter("taskListKey", taskList.getKey()) + .executeUpdate(); + } + +} 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 d5ec967011298193ffed8b3c51387ca877a72599..e2dea18abe5766e7f92070b96dca56ee0bb2f70d 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 @@ -65,6 +65,7 @@ import org.olat.course.nodes.gta.AssignmentResponse.Status; import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.GTARelativeToDates; import org.olat.course.nodes.gta.GTAType; +import org.olat.course.nodes.gta.IdentityMark; import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskDueDate; import org.olat.course.nodes.gta.TaskLight; @@ -123,6 +124,8 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { @Autowired private DB dbInstance; @Autowired + private GTAIdentityMarkDAO gtaMarkDao; + @Autowired private BGAreaManager areaManager; @Autowired private AssessmentService assessmentService; @@ -751,8 +754,11 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { int numOfTasks = dbInstance.getCurrentEntityManager().createQuery(deleteTasks) .setParameter("taskListKey", taskList.getKey()) .executeUpdate(); + numOfDeletedObjects = numOfTasks; + int numOfMarks = gtaMarkDao.deleteMark(taskList); + numOfDeletedObjects += numOfMarks; dbInstance.getCurrentEntityManager().remove(taskList); - numOfDeletedObjects = numOfTasks + 1; + numOfDeletedObjects++; } else { numOfDeletedObjects = 0; } @@ -773,6 +779,8 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { for(TaskList taskList:taskLists) { int numOfTasks = deleteTaskQuery.setParameter("taskListKey", taskList.getKey()).executeUpdate(); numOfDeletedObjects += numOfTasks; + int numOfMarks = gtaMarkDao.deleteMark(taskList); + numOfDeletedObjects += numOfMarks; } String deleteTaskLists = "delete from gtatasklist as tasks where tasks.entry.key=:entryKey"; @@ -1560,6 +1568,27 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData { return taskImpl; } + @Override + public boolean toggleMark(RepositoryEntry entry, GTACourseNode gtaNode, Identity marker, Identity participant) { + if (entry == null || gtaNode == null || marker == null || participant == null) return false; + + TaskList taskList = getTaskList(entry, gtaNode); + boolean isMarked = gtaMarkDao.isMarked(taskList, marker, participant); + if (isMarked) { + gtaMarkDao.deleteMark(taskList, marker, participant); + } else { + gtaMarkDao.createAndPersisitMark(taskList, marker, participant); + } + return !isMarked; + + } + + @Override + public List<IdentityMark> getMarks(RepositoryEntry entry, GTACourseNode gtaNode, Identity marker) { + TaskList taskList = getTaskList(entry, gtaNode); + return gtaMarkDao.loadMarks(taskList, marker); + } + @Override public AssessmentEntryStatus convertToAssessmentEntrystatus(Task task, GTACourseNode cNode) { TaskProcess status = task.getTaskStatus(); diff --git a/src/main/java/org/olat/course/nodes/gta/model/IdentityMarkImpl.java b/src/main/java/org/olat/course/nodes/gta/model/IdentityMarkImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..d5b60bff09e4b74cc88de090cc2e0d8c3050b752 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/gta/model/IdentityMarkImpl.java @@ -0,0 +1,178 @@ +/** + * <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.model; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.olat.basesecurity.IdentityImpl; +import org.olat.core.id.Identity; +import org.olat.core.id.Persistable; +import org.olat.course.nodes.gta.IdentityMark; +import org.olat.course.nodes.gta.TaskList; + +/** + * + * Initial date: 02.10.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +@Entity(name="gtaMark") +@Table(name="o_gta_mark") +@NamedQueries({ + @NamedQuery(name="loadByMarker", query= + "select mark" + + " from gtaMark mark" + + " where mark.taskList.key=:taskListKey" + + " and mark.marker.key=:markerKey"), + @NamedQuery(name="loadByMarkerAndParticipant", query= + "select mark" + + " from gtaMark mark" + + " where mark.taskList.key=:taskListKey" + + " and mark.marker.key=:markerKey" + + " and mark.participant.key=:participantKey"), + @NamedQuery(name="deleteByMarker", query = + "delete from gtaMark mark" + + " where mark.taskList.key=:taskListKey" + + " and mark.marker.key=:markerKey" + + " and mark.participant.key=:participantKey"), + @NamedQuery(name="deleteByTaskList", query = + "delete from gtaMark mark" + + " where mark.taskList.key=:taskListKey") +}) +public class IdentityMarkImpl implements IdentityMark, Persistable { + + private static final long serialVersionUID = 5984891452227836907L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id", nullable=false, unique=true, insertable=true, updatable=false) + private Long key; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="creationdate", nullable=false, insertable=true, updatable=false) + private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name="lastmodified", nullable=false, insertable=true, updatable=true) + private Date lastModified; + + @ManyToOne(targetEntity=TaskListImpl.class,fetch=FetchType.LAZY,optional=false) + @JoinColumn(name="fk_tasklist_id", nullable=false, insertable=true, updatable=false) + private TaskList taskList; + + @ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_marker_identity_id", nullable=true, insertable=true, updatable=false) + private Identity marker; + @ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true) + @JoinColumn(name="fk_participant_identity_id", nullable=true, insertable=true, updatable=false) + private Identity participant; + + @Override + public Long getKey() { + return key; + } + + @Override + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public Date getLastModified() { + return lastModified; + } + + @Override + public void setLastModified(Date lastModified) { + this.lastModified = lastModified; + } + + @Override + public TaskList getTaskList() { + return taskList; + } + + @Override + public void setTaskList(TaskList taskList) { + this.taskList = taskList; + } + + @Override + public Identity getMarker() { + return marker; + } + + @Override + public void setMarker(Identity marker) { + this.marker = marker; + } + + @Override + public Identity getParticipant() { + return participant; + } + + @Override + public void setParticipant(Identity participant) { + this.participant = participant; + } + + @Override + public boolean equalsByPersistableKey(Persistable persistable) { + return equals(persistable); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } else if(obj instanceof IdentityMarkImpl) { + IdentityMarkImpl other = (IdentityMarkImpl)obj; + return getKey() != null && getKey().equals(other.getKey()); + } + return false; + } + +} diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java index d633a795238980dfe5977c1af921ce6a7f2ebe99..4dd3b3882cb4d6ff0380ca2d4afe0d08c18f2ec5 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachParticipantsTableModel.java @@ -68,7 +68,9 @@ public class CoachParticipantsTableModel extends DefaultFlexiTableDataModel<Coac @Override public Object getValueAt(CoachedIdentityRow row, int col) { - if(col == CGCols.username.ordinal()) { + if(col == CGCols.mark.ordinal()) { + return row.getMarkLink(); + } else if(col == CGCols.username.ordinal()) { return row.getIdentity().getIdentityName(); } else if(col == CGCols.taskStatus.ordinal()) { return row.getTaskStatus(); @@ -84,6 +86,7 @@ public class CoachParticipantsTableModel extends DefaultFlexiTableDataModel<Coac } public enum CGCols { + mark("table.header.mark"), username("username"), taskName("table.header.group.taskName"), taskStatus("table.header.group.step"), diff --git a/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java b/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java index 5d8cea03f80f53fec68a994082c92018d9ada9ec..de4a80bad9f2e2d0d0e96e8c9937f95f4abc92fa 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/CoachedIdentityRow.java @@ -21,6 +21,7 @@ package org.olat.course.nodes.gta.ui; import java.util.Date; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.course.nodes.gta.TaskLight; import org.olat.course.nodes.gta.TaskProcess; import org.olat.user.UserPropertiesRow; @@ -33,6 +34,8 @@ import org.olat.user.UserPropertiesRow; */ public class CoachedIdentityRow implements CoachedElementRow { + private FormLink markLink; + private final TaskLight task; private final Date submissionDueDate; private final Date syntheticSubmissionDate; @@ -40,12 +43,13 @@ public class CoachedIdentityRow implements CoachedElementRow { private final UserPropertiesRow identity; public CoachedIdentityRow(UserPropertiesRow identity, TaskLight task, Date submissionDueDate, - Date syntheticSubmissionDate, boolean hasSubmittedDocuments) { + Date syntheticSubmissionDate, boolean hasSubmittedDocuments, FormLink markLink) { this.identity = identity; this.task = task; this.submissionDueDate = submissionDueDate; this.hasSubmittedDocuments = hasSubmittedDocuments; this.syntheticSubmissionDate = syntheticSubmissionDate; + this.markLink = markLink; } @Override @@ -96,4 +100,10 @@ public class CoachedIdentityRow implements CoachedElementRow { public UserPropertiesRow getIdentity() { return identity; } + + public FormLink getMarkLink() { + return markLink; + } + + } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java index ca06397e1a290a0d4647c54fdc6cb7a003c02361..07c9cb1641028233b8235283fdfa2613de40201b 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachSelectionController.java @@ -23,6 +23,7 @@ package org.olat.course.nodes.gta.ui; import java.io.File; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import org.olat.basesecurity.BaseSecurity; import org.olat.core.commons.services.notifications.PublisherData; @@ -58,6 +59,7 @@ import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.group.BusinessGroup; import org.olat.modules.ModuleConfiguration; +import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; import org.springframework.beans.factory.annotation.Autowired; @@ -82,9 +84,11 @@ public class GTACoachSelectionController extends BasicController implements Acti private final GTACourseNode gtaNode; private final CourseEnvironment courseEnv; private final UserCourseEnvironment coachCourseEnv; + private final boolean markedOnly; + + protected PublisherData publisherData; + protected SubscriptionContext subsContext; - protected final PublisherData publisherData; - protected final SubscriptionContext subsContext; @Autowired private GTAManager gtaManager; @@ -92,11 +96,12 @@ public class GTACoachSelectionController extends BasicController implements Acti private BaseSecurity securityManager; public GTACoachSelectionController(UserRequest ureq, WindowControl wControl, - UserCourseEnvironment coachCourseEnv, GTACourseNode gtaNode) { + UserCourseEnvironment coachCourseEnv, GTACourseNode gtaNode, boolean markedOnly) { super(ureq, wControl); this.gtaNode = gtaNode; this.coachCourseEnv = coachCourseEnv; this.courseEnv = coachCourseEnv.getCourseEnvironment(); + this.markedOnly = markedOnly; mainVC = createVelocityContainer("coach_selection"); backLink = LinkFactory.createLinkBack(mainVC, this); @@ -109,12 +114,14 @@ public class GTACoachSelectionController extends BasicController implements Acti downloadButton = LinkFactory.createButton("bulk.download.title", mainVC, this); downloadButton.setTranslator(getTranslator()); - publisherData = gtaManager.getPublisherData(courseEnv, gtaNode); - subsContext = gtaManager.getSubscriptionContext(courseEnv, gtaNode); - if (subsContext != null) { - ContextualSubscriptionController contextualSubscriptionCtr = new ContextualSubscriptionController(ureq, getWindowControl(), subsContext, publisherData); - listenTo(contextualSubscriptionCtr); - mainVC.put("contextualSubscription", contextualSubscriptionCtr.getInitialComponent()); + if (!markedOnly) { + publisherData = gtaManager.getPublisherData(courseEnv, gtaNode); + subsContext = gtaManager.getSubscriptionContext(courseEnv, gtaNode); + if (subsContext != null) { + ContextualSubscriptionController contextualSubscriptionCtr = new ContextualSubscriptionController(ureq, getWindowControl(), subsContext, publisherData); + listenTo(contextualSubscriptionCtr); + mainVC.put("contextualSubscription", contextualSubscriptionCtr.getInitialComponent()); + } } ModuleConfiguration config = gtaNode.getModuleConfiguration(); @@ -139,7 +146,7 @@ public class GTACoachSelectionController extends BasicController implements Acti mainVC.put("list", groupListCtrl.getInitialComponent()); } } else { - participantListCtrl = new GTACoachedParticipantListController(ureq, getWindowControl(), coachCourseEnv, gtaNode); + participantListCtrl = new GTACoachedParticipantListController(ureq, getWindowControl(), coachCourseEnv, gtaNode, markedOnly); listenTo(participantListCtrl); mainVC.put("list", participantListCtrl.getInitialComponent()); } @@ -203,13 +210,17 @@ public class GTACoachSelectionController extends BasicController implements Acti @Override protected void event(UserRequest ureq, Component source, Event event) { if(backLink == source) { - back(); + back(ureq); } else if(downloadButton == source) { doBulkDownload(ureq); } } - private void back() { + public void reload(UserRequest ureq) { + participantListCtrl.updateModel(ureq); + } + + private void back(UserRequest ureq) { if(coachingCtrl != null) { mainVC.remove(coachingCtrl.getInitialComponent()); removeAsListenerAndDispose(coachingCtrl); @@ -217,7 +228,7 @@ public class GTACoachSelectionController extends BasicController implements Acti } backLink.setVisible(false); if (participantListCtrl != null) { - participantListCtrl.updateModel(); + participantListCtrl.updateModel(ureq); } if (groupListCtrl != null) { groupListCtrl.updateModel(); @@ -227,7 +238,7 @@ public class GTACoachSelectionController extends BasicController implements Acti private void doBulkDownload(UserRequest ureq) { if (participantListCtrl != null) { ArchiveOptions asOptions = new ArchiveOptions(); - asOptions.setIdentities(participantListCtrl.getAssessableIdentities()); + asOptions.setIdentities(getIdentitesForBulkDownload(ureq)); OLATResource ores = courseEnv.getCourseGroupManager().getCourseResource(); ArchiveResource resource = new ArchiveResource(gtaNode, ores, asOptions, getLocale()); ureq.getDispatchResult().setResultingMediaResource(resource); @@ -237,6 +248,19 @@ public class GTACoachSelectionController extends BasicController implements Acti ureq.getDispatchResult().setResultingMediaResource(resource); } } + + private List<Identity> getIdentitesForBulkDownload(UserRequest ureq) { + List<Identity> identities = participantListCtrl.getAssessableIdentities(); + if (markedOnly) { + RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry(); + List<Identity> markedIdentities = + gtaManager.getMarks(entry, gtaNode, ureq.getIdentity()).stream() + .map(mark -> mark.getParticipant()) + .collect(Collectors.toList()); + identities.retainAll(markedIdentities); + } + return identities; + } private Activateable2 doSelectBusinessGroup(UserRequest ureq, BusinessGroup group) { removeAsListenerAndDispose(coachingCtrl); diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java index 2f17f92779ff14b23de047cf616bda1463ee2cbb..ed3f4b5c44488ecb495ba321b194bf1b61a9b4d9 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java @@ -33,10 +33,12 @@ import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.model.IdentityRefImpl; +import org.olat.core.commons.services.mark.Mark; 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.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel; @@ -45,6 +47,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer; +import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; @@ -56,6 +59,7 @@ import org.olat.core.util.StringHelper; import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; +import org.olat.course.nodes.gta.IdentityMark; import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskLight; import org.olat.course.nodes.gta.TaskList; @@ -92,6 +96,7 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle private final boolean isAdministrativeUser; private final List<UserPropertyHandler> userPropertyHandlers; + private final boolean markedOnly; private CloseableModalController cmc; private EditDueDatesController editDueDatesCtrl; @@ -110,7 +115,7 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle private BusinessGroupService businessGroupService; public GTACoachedParticipantListController(UserRequest ureq, WindowControl wControl, - UserCourseEnvironment userCourseEnv, GTACourseNode gtaNode) { + UserCourseEnvironment userCourseEnv, GTACourseNode gtaNode, boolean markedOnly) { super(ureq, wControl, userCourseEnv.getCourseEnvironment(), gtaNode); Roles roles = ureq.getUserSession().getRoles(); @@ -118,6 +123,7 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle userPropertyHandlers = userManager.getUserPropertyHandlersFor(GTACoachedGroupGradingController.USER_PROPS_ID, isAdministrativeUser); setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); coachCourseEnv = (UserCourseEnvironmentImpl)userCourseEnv; + this.markedOnly = markedOnly; assessableIdentities = new ArrayList<>(); collectIdentities(new Consumer<Identity>() { @@ -128,7 +134,7 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle }); initForm(ureq); - updateModel(); + updateModel(ureq); } public boolean hasIdentityKey(Long identityKey) { @@ -185,6 +191,9 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle super.initForm(formLayout, listener, ureq); FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.mark.i18nKey(), CGCols.mark.ordinal(), + true, CGCols.mark.name())); + if(isAdministrativeUser) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.username.i18nKey(), CGCols.username.ordinal(), true, CGCols.username.name())); @@ -230,18 +239,32 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle tableEl.setAndLoadPersistedPreferences(ureq, "gta-coached-participants"); } - protected void updateModel() { + protected void updateModel(UserRequest ureq) { RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry(); List<TaskLight> tasks = gtaManager.getTasksLight(entry, gtaNode); - Map<Long,TaskLight> identityToTasks = new HashMap<>(); + Map<Long,TaskLight> identityToTasks = new HashMap<>(tasks.size()); for(TaskLight task:tasks) { if(task.getIdentityKey() != null) { identityToTasks.put(task.getIdentityKey(), task); } } + List<IdentityMark> marks = gtaManager.getMarks(entry, gtaNode, ureq.getIdentity()); + Map<Long,IdentityMark> identityToMarks= new HashMap<>(marks.size()); + for(IdentityMark mark:marks) { + if(mark.getParticipant() != null) { + identityToMarks.put(mark.getParticipant().getKey(), mark); + } + } List<CoachedIdentityRow> rows = new ArrayList<>(assessableIdentities.size()); for(UserPropertiesRow assessableIdentity:assessableIdentities) { + IdentityMark mark = identityToMarks.get(assessableIdentity.getIdentityKey()); + if (markedOnly && mark == null) continue; + + FormLink markLink = uifactory.addFormLink("mark_" + assessableIdentity.getIdentityKey(), "mark", "", null, null, Link.NONTRANSLATED); + markLink.setIconLeftCSS(mark != null ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE); + markLink.setUserObject(assessableIdentity.getIdentityKey()); + TaskLight task = identityToTasks.get(assessableIdentity.getIdentityKey()); Date submissionDueDate = null; if(task == null || task.getTaskStatus() == null || task.getTaskStatus() == TaskProcess.assignment) { @@ -260,7 +283,8 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle hasSubmittedDocument = hasSubmittedDocument(task); } } - rows.add(new CoachedIdentityRow(assessableIdentity, task, submissionDueDate, syntheticSubmissionDate, hasSubmittedDocument)); + + rows.add(new CoachedIdentityRow(assessableIdentity, task, submissionDueDate, syntheticSubmissionDate, hasSubmittedDocument, markLink)); } tableModel.setObjects(rows); @@ -276,7 +300,7 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle public void event(UserRequest ureq, Controller source, Event event) { if(editDueDatesCtrl == source) { if(event == Event.DONE_EVENT) { - updateModel(); + updateModel(ureq); } cmc.deactivate(); cleanUp(); @@ -306,6 +330,15 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle fireEvent(ureq, new SelectIdentityEvent(row.getIdentity().getIdentityKey())); } } + } else if(source instanceof FormLink) { + FormLink link = (FormLink)source; + String cmd = link.getCmd(); + if("mark".equals(cmd)) { + Long assessableIdentityKey = (Long)link.getUserObject(); + boolean marked = doToogleMark(ureq, assessableIdentityKey); + link.setIconLeftCSS(marked ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE); + link.getComponent().setDirty(true); + } } super.formInnerEvent(ureq, source, event); } @@ -338,4 +371,11 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle listenTo(cmc); cmc.activate(); } + + private boolean doToogleMark(UserRequest ureq, Long particiantKey) { + RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry(); + Identity participant = securityManager.loadIdentityByKey(particiantKey); + boolean isMarked = gtaManager.toggleMark(entry, gtaNode, ureq.getIdentity(), participant); + return isMarked; + } } \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java index 8b5297d6d3efd5b3f596abd38d71f9e2b858c5c0..5efc2db387ca0041583a0ff0e032bc501bdf87bd 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java +++ b/src/main/java/org/olat/course/nodes/gta/ui/GTARunController.java @@ -56,9 +56,10 @@ public class GTARunController extends BasicController implements Activateable2 { private GTAParticipantController runCtrl; private GTACoachSelectionController coachCtrl; + private GTACoachSelectionController markedCtrl; private GTACoachManagementController manageCtrl; - private Link runLink, coachLink, manageLink; + private Link runLink, coachLink, markedLink, manageLink; private VelocityContainer mainVC; private SegmentViewComponent segmentView; @@ -84,7 +85,9 @@ public class GTARunController extends BasicController implements Activateable2 { segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); runLink = LinkFactory.createLink("run.run", mainVC, this); segmentView.addSegment(runLink, false); - coachLink = LinkFactory.createLink("run.coach", mainVC, this); + markedLink = LinkFactory.createLink("run.coach.marked", mainVC, this); + segmentView.addSegment(markedLink, false); + coachLink = LinkFactory.createLink("run.coach.all", mainVC, this); segmentView.addSegment(coachLink, true); if(isManagementTabAvalaible(config)) { manageLink = LinkFactory.createLink("run.manage.coach", mainVC, this); @@ -97,7 +100,9 @@ public class GTARunController extends BasicController implements Activateable2 { mainVC = createVelocityContainer("run_segments"); segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); - coachLink = LinkFactory.createLink("run.coach", mainVC, this); + markedLink = LinkFactory.createLink("run.coach.marked", mainVC, this); + segmentView.addSegment(markedLink, false); + coachLink = LinkFactory.createLink("run.coach.all", mainVC, this); segmentView.addSegment(coachLink, true); manageLink = LinkFactory.createLink("run.manage.coach", mainVC, this); segmentView.addSegment(manageLink, false); @@ -106,8 +111,17 @@ public class GTARunController extends BasicController implements Activateable2 { mainVC.put("segments", segmentView); putInitialPanel(mainVC); } else if(membership.isCoach() || userCourseEnv.isAdmin()) { - createCoach(ureq); - putInitialPanel(coachCtrl.getInitialComponent()); + mainVC = createVelocityContainer("run_segments"); + + segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); + markedLink = LinkFactory.createLink("run.coach.marked", mainVC, this); + segmentView.addSegment(markedLink, false); + coachLink = LinkFactory.createLink("run.coach.all", mainVC, this); + segmentView.addSegment(coachLink, true); + + doOpenCoach(ureq); + mainVC.put("segments", segmentView); + putInitialPanel(mainVC); } else if(membership.isParticipant()) { createRun(ureq); putInitialPanel(runCtrl.getInitialComponent()); @@ -139,6 +153,13 @@ public class GTARunController extends BasicController implements Activateable2 { segmentView.select(coachLink); } } + } else if("marked".equalsIgnoreCase(type)) { + if(markedLink != null) { + doOpenMarked(ureq); + if(segmentView != null) { + segmentView.select(markedLink); + } + } } else if("management".equalsIgnoreCase(type)) { if(manageLink != null) { doManage(ureq); @@ -168,6 +189,8 @@ public class GTARunController extends BasicController implements Activateable2 { doOpenRun(ureq); } else if (clickedLink == coachLink) { doOpenCoach(ureq); + } else if (clickedLink == markedLink) { + doOpenMarked(ureq); } else if(clickedLink == manageLink) { doManage(ureq); } @@ -191,11 +214,25 @@ public class GTARunController extends BasicController implements Activateable2 { } return runCtrl; } - + + private Activateable2 doOpenMarked(UserRequest ureq) { + if(markedCtrl == null) { + createMarked(ureq); + } else { + markedCtrl.reload(ureq); + addToHistory(ureq, markedCtrl); + } + if(mainVC != null) { + mainVC.put("segmentCmp", markedCtrl.getInitialComponent()); + } + return markedCtrl; + } + private Activateable2 doOpenCoach(UserRequest ureq) { if(coachCtrl == null) { createCoach(ureq); } else { + coachCtrl.reload(ureq); addToHistory(ureq, coachCtrl); } if(mainVC != null) { @@ -223,11 +260,20 @@ public class GTARunController extends BasicController implements Activateable2 { return runCtrl; } + private GTACoachSelectionController createMarked(UserRequest ureq) { + removeAsListenerAndDispose(markedCtrl); + + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("marked"), null); + markedCtrl = new GTACoachSelectionController(ureq, swControl, userCourseEnv, gtaNode, true); + listenTo(markedCtrl); + return coachCtrl; + } + private GTACoachSelectionController createCoach(UserRequest ureq) { removeAsListenerAndDispose(coachCtrl); WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("coach"), null); - coachCtrl = new GTACoachSelectionController(ureq, swControl, userCourseEnv, gtaNode); + coachCtrl = new GTACoachSelectionController(ureq, swControl, userCourseEnv, gtaNode, false); listenTo(coachCtrl); return coachCtrl; } diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_content/coach_selection.html b/src/main/java/org/olat/course/nodes/gta/ui/_content/coach_selection.html index 391b4852ad52177d707d7b0245040c6f77a66702..b1b042b01dc36bcb6f04b9a69e7d7758071d0995 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_content/coach_selection.html +++ b/src/main/java/org/olat/course/nodes/gta/ui/_content/coach_selection.html @@ -16,10 +16,10 @@ $r.render("selection") #elseif($r.available("list")) - #if($r.available("contextualSubscription")) - <div class="o_button_group o_button_group_right"> - $r.render("bulk.download.title") + <div class="o_button_group o_button_group_right"> + $r.render("bulk.download.title") + #if($r.available("contextualSubscription")) <div style="display:inline-block;"> $r.render("contextualSubscription") </div> 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 4395fde0308e20dac82fb93cee11f93d96c20a0f..ee9f65173847a73e4723a6fa44ba8449d206b7d8 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 @@ -205,8 +205,9 @@ revision.period=\u00DCberarbeitung revisions.duedate=\u00DCberarbeitung bis... run.assignment.due.date=Zuweisung Termin\: {0} run.assignment.title=Zuweisung Aufgabenstellung -run.coach=Korrigieren +run.coach.all=Alle Teilnehmer run.coach.corrections.description=Sie haben die folgende Korrekturanforderung erstellt. +run.coach.marked=Favoriten run.corrections.description=Ihr Betreuer hat folgende Dokumente f\u00FCr Sie hinzugef\u00FCgt\: run.corrections.rejected=$\:coach.corrections.rejected run.documents.successfully.submitted=Ihr(e) Dokument(e) wurden erfolgreich eingereicht. @@ -279,6 +280,7 @@ table.header.edit=Aktion table.header.group.name=Gruppe table.header.group.step=Schritt table.header.group.taskName=Aufgabe +table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Favorit"> </i> table.header.passed=Bestanden table.header.score=Punkte table.header.submissionDate=Abgabedatum 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 436e44a116c606e2e80c3c3cff99bd88d11600e4..30c85a6ff3f710c25c59f0bc9af1d0c718d1efda 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 @@ -205,8 +205,9 @@ revision.period=Revision revisions.duedate=Revision until... run.assignment.due.date=Deadline\: {0} run.assignment.title=Task assignment -run.coach=Submissions +run.coach.all=All participants run.coach.corrections.description=You have set the following correction request. +run.coach.marked=Favorites run.corrections.description=Your coach attached the following files for you\: run.corrections.rejected=Your submission has been rejected. run.documents.successfully.submitted=Your document(s) have been successfully submitted. @@ -279,6 +280,7 @@ table.header.edit=Action table.header.group.name=Group table.header.group.step=Step table.header.group.taskName=Task +table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Bookmark"> </i> table.header.passed=Passed table.header.score=Points table.header.submissionDate=Submission date diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties index 9f24e8fe1474ff7ec14c5364d8f0ce33cbe62e27..66335c2ea68910e64d92d28718951222898721de 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties @@ -205,7 +205,6 @@ revision.period=P\u00E9riode de r\u00E9\u00E9criture revisions.duedate=Date d'\u00E9ch\u00E9ance de r\u00E9vision run.assignment.due.date=D\u00E9lai pour l'affectation\: {0} run.assignment.title=Affectation d'un devoir -run.coach=Corriger run.coach.corrections.description=Vous avez retourner les demandes de corrections suivantes. run.corrections.description=Votre coach a ajout\u00E9 les documents suivants \u00E0 votre intention\: run.corrections.rejected=$\:coach.corrections.rejected @@ -279,6 +278,7 @@ table.header.edit=Action table.header.group.name=Groupe table.header.group.step=Etape table.header.group.taskName=Devoir +table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Favori"> </i> table.header.passed=R\u00E9ussi table.header.score=Points table.header.submissionDate=Date de remise diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_it.properties index fb6f1a00a44ca3414d7ba9a82be0d6f0df1d150f..88baefa419a13b5cb63a02242546e3363dd9794d 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_it.properties @@ -163,7 +163,6 @@ revision.enabled=Abilita la cartella per le revisioni dei partecipanti, pu\u00F2 revision.period=Periodo di revisione run.assignment.due.date=Data di scadenza\: {0} run.assignment.title=Assegnazione del compito -run.coach=Correzione run.coach.corrections.description=Hai impostato le seguenti richieste di correzione. run.corrections.description=Il tutore ha allegato i seguenti file per te\: run.corrections.rejected=$\:coach.corrections.rejected @@ -232,6 +231,7 @@ table.header.edit=Azione table.header.group.name=Gruppo table.header.group.step=Passo table.header.group.taskName=Compito +table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Preferito"> </i> table.header.passed=Superato table.header.score=Punti table.header.uploaded.by=Caricato da diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pl.properties index 3be48f06b752cd72df9f69829c36fa9a9b679e78..9f09c19f1bfc66c34b0aabfbd7d704573ee850a5 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pl.properties @@ -157,7 +157,6 @@ revision.enabled=Enable drop box for revisions by participants, can be set by co revision.period=Revision phase run.assignment.due.date=Due date\: {0} run.assignment.title=Przypisanie zada\u0144 -run.coach=Correct run.coach.corrections.description=You have set the following correction request. run.corrections.description=Your coach attached the following files for you\: run.corrections.rejected=$\:coach.corrections.rejected @@ -226,6 +225,7 @@ table.header.edit=Akcja table.header.group.name=Grupa table.header.group.step=Krok table.header.group.taskName=Zadanie +table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Ulubione"> </i> table.header.passed=Passed table.header.score=Punkty table.header.uploaded.by=Przes\u0142ane przez diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pt_BR.properties index c4bc05d538b0b2a37a305bb73ce2c7a409147982..0bc2cfb2ef17e4f332189dad243c7f83956a3850 100644 --- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_pt_BR.properties @@ -205,7 +205,6 @@ revision.period=Fase de revis\u00E3o revisions.duedate=Revis\u00E3o at\u00E9... run.assignment.due.date=Data de vencimento\: {0} run.assignment.title=Atribui\u00E7\u00E3o de tarefas -run.coach=Correto run.coach.corrections.description=Voc\u00EA definiu a seguinte solicita\u00E7\u00E3o de corre\u00E7\u00E3o. run.corrections.description=Seu treinador anexou os seguintes arquivos para voc\u00EA\: run.corrections.rejected=$\:coach.corrections.rejected @@ -279,6 +278,7 @@ table.header.edit=A\u00E7\u00E3o table.header.group.name=Grupo table.header.group.step=Passo table.header.group.taskName=Tarefa +table.header.mark=<i class\="o_icon o_icon_bookmark_header o_icon-lg" title\="Favorito"> </i>s table.header.passed=Passou table.header.score=Pontos table.header.submissionDate=Data para envio diff --git a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml index 062ee483753f8e0c4a087a9de77e0bcc3c8ddd5e..d1437dceb8b005dc2b96cb9a7c0b522f604994de 100644 --- a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml +++ b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml @@ -160,6 +160,10 @@ <constructor-arg index="0" value="OLAT_12.1.1" /> <property name="alterDbStatements" value="alter_12_1_0_to_12_1_1.sql" /> </bean> + <bean id="database_upgrade_12_1_x" class="org.olat.upgrade.DatabaseUpgrade"> + <constructor-arg index="0" value="OLAT_12.2.0" /> + <property name="alterDbStatements" value="alter_12_1_x_to_12_2_0.sql" /> + </bean> </list> </property> </bean> diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index b82a337e9e482d855fb4a93274a0b39cd4f8cf9e..c2bb7561ccb1707ae4a6921eaf91c888fa93a9ae 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -91,6 +91,7 @@ <class>org.olat.course.assessment.model.UserEfficiencyStatementRepoImpl</class> <class>org.olat.course.nodes.cl.model.DBCheckbox</class> <class>org.olat.course.nodes.cl.model.DBCheck</class> + <class>org.olat.course.nodes.gta.model.IdentityMarkImpl</class> <class>org.olat.course.nodes.gta.model.TaskImpl</class> <class>org.olat.course.nodes.gta.model.TaskLightImpl</class> <class>org.olat.course.nodes.gta.model.TaskDueDateImpl</class> diff --git a/src/main/resources/database/mysql/alter_12_1_x_to_12_2_0.sql b/src/main/resources/database/mysql/alter_12_1_x_to_12_2_0.sql new file mode 100644 index 0000000000000000000000000000000000000000..10781511f6c75a955ffcf1527630a08bfe907aca --- /dev/null +++ b/src/main/resources/database/mysql/alter_12_1_x_to_12_2_0.sql @@ -0,0 +1,14 @@ +create table o_gta_mark ( + id bigint not null auto_increment, + creationdate datetime not null, + lastmodified datetime not null, + fk_tasklist_id int8 not null, + fk_marker_identity_id int8 not null, + fk_participant_identity_id int8 not null, + primary key (id) +); + +alter table o_gta_mark ENGINE = InnoDB; + +alter table o_gta_mark add constraint gtamark_tasklist_idx foreign key (fk_tasklist) references o_gta_task_list (id); +create index idx_gtamark_tasklist_idx on o_gta_task (fk_tasklist); diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql index 5ee96a2de5ee2ed348560ea28f26ea5d55144ad4..07fde0ee7e2835c410c5fd95a0971f6d794fc3ab 100644 --- a/src/main/resources/database/mysql/setupDatabase.sql +++ b/src/main/resources/database/mysql/setupDatabase.sql @@ -1905,6 +1905,16 @@ create table o_gta_task_revision_date ( primary key (id) ); +create table o_gta_mark ( + id bigint not null auto_increment, + creationdate datetime not null, + lastmodified datetime not null, + fk_tasklist_id int8 not null, + fk_marker_identity_id int8 not null, + fk_participant_identity_id int8 not null, + primary key (id) +); + create table o_rem_reminder ( id bigint not null, creationdate datetime not null, @@ -2439,6 +2449,7 @@ alter table o_cl_check ENGINE = InnoDB; alter table o_gta_task_list ENGINE = InnoDB; alter table o_gta_task ENGINE = InnoDB; alter table o_gta_task_revision_date ENGINE = InnoDB; +alter table o_gta_mark ENGINE = InnoDB; alter table o_cer_template ENGINE = InnoDB; alter table o_cer_certificate ENGINE = InnoDB; alter table o_rem_reminder ENGINE = InnoDB; @@ -2669,6 +2680,8 @@ alter table o_gta_task_list add constraint gta_list_to_repo_entry_idx foreign ke alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); +alter table o_gta_mark add constraint gtamark_tasklist_idx foreign key (fk_tasklist) references o_gta_task_list (id); + -- reminders alter table o_rem_reminder add constraint rem_reminder_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); alter table o_rem_reminder add constraint rem_reminder_to_creator_idx foreign key (fk_creator) references o_bs_identity (id); diff --git a/src/main/resources/database/oracle/alter_12_1_x_to_12_2_0.sql b/src/main/resources/database/oracle/alter_12_1_x_to_12_2_0.sql new file mode 100644 index 0000000000000000000000000000000000000000..7c26181fffff3e98a5b427b59851ab0e9a78aed2 --- /dev/null +++ b/src/main/resources/database/oracle/alter_12_1_x_to_12_2_0.sql @@ -0,0 +1,12 @@ +create table o_gta_mark ( + id number(20) generated always as identity, + creationdate date not null, + lastmodified date not null, + fk_tasklist_id number(20) not null, + fk_marker_identity_id number(20) not null, + fk_participant_identity_id number(20) not null, + primary key (id) +); + +alter table o_gta_mark add constraint gtamark_tasklist_idx foreign key (fk_tasklist) references o_gta_task_list (id); +create index idx_gtamark_tasklist_idx on o_gta_task (fk_tasklist); diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql index eb454ee83988a38aa3636d501dbee5203f0acc10..681ec404d17f210fd3f5b6ebc530767541e77de9 100644 --- a/src/main/resources/database/oracle/setupDatabase.sql +++ b/src/main/resources/database/oracle/setupDatabase.sql @@ -1928,6 +1928,16 @@ create table o_gta_task_revision_date ( primary key (id) ); +create table o_gta_mark ( + id number(20) generated always as identity, + creationdate date not null, + lastmodified date not null, + fk_tasklist_id number(20) not null, + fk_marker_identity_id number(20) not null, + fk_participant_identity_id number(20) not null, + primary key (id) +); + create table o_rem_reminder ( id number(20) not null, creationdate date not null, @@ -2740,6 +2750,9 @@ create index idx_gta_list_to_repo_entry_idx on o_gta_task_list (fk_entry); alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); create index idx_gtaskrev_to_task_idx on o_gta_task_revision_date (fk_task); +alter table o_gta_mark add constraint gtamark_tasklist_idx foreign key (fk_tasklist) references o_gta_task_list (id); +create index idx_gtamark_tasklist_idx on o_gta_task (fk_tasklist); + -- reminders alter table o_rem_reminder add constraint rem_reminder_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); create index idx_reminder_to_repo_entry_idx on o_rem_reminder (fk_entry); diff --git a/src/main/resources/database/postgresql/alter_12_1_x_to_12_2_0.sql b/src/main/resources/database/postgresql/alter_12_1_x_to_12_2_0.sql new file mode 100644 index 0000000000000000000000000000000000000000..1576e8461a6b5aa027e87a7264541d2e05f8d4f4 --- /dev/null +++ b/src/main/resources/database/postgresql/alter_12_1_x_to_12_2_0.sql @@ -0,0 +1,12 @@ +create table o_gta_mark ( + id bigserial not null, + creationdate timestamp not null, + lastmodified timestamp not null, + fk_tasklist_id int8 not null, + fk_marker_identity_id int8 not null, + fk_participant_identity_id int8 not null, + primary key (id) +); + +alter table o_gta_mark add constraint gtamark_tasklist_idx foreign key (fk_tasklist) references o_gta_task_list (id); +create index idx_gtamark_tasklist_idx on o_gta_task (fk_tasklist); diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql index 8c833977cafe0177d2270b636ad588bdad20b0af..0c4643019f109683300ef7878359d915b9679f0e 100644 --- a/src/main/resources/database/postgresql/setupDatabase.sql +++ b/src/main/resources/database/postgresql/setupDatabase.sql @@ -1902,6 +1902,16 @@ create table o_gta_task_revision_date ( primary key (id) ); +create table o_gta_mark ( + id bigserial not null, + creationdate timestamp not null, + lastmodified timestamp not null, + fk_tasklist_id int8 not null, + fk_marker_identity_id int8 not null, + fk_participant_identity_id int8 not null, + primary key (id) +); + create table o_rem_reminder ( id int8 not null, creationdate timestamp not null, @@ -2589,6 +2599,9 @@ create index idx_gta_list_to_repo_entry_idx on o_gta_task_list (fk_entry); alter table o_gta_task_revision_date add constraint gtaskrev_to_task_idx foreign key (fk_task) references o_gta_task (id); create index idx_gtaskrev_to_task_idx on o_gta_task_revision_date (fk_task); +alter table o_gta_mark add constraint gtamark_tasklist_idx foreign key (fk_tasklist) references o_gta_task_list (id); +create index idx_gtamark_tasklist_idx on o_gta_task (fk_tasklist) + -- reminders alter table o_rem_reminder add constraint rem_reminder_to_repo_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id); create index idx_reminder_to_repo_entry_idx on o_rem_reminder (fk_entry); diff --git a/src/test/java/org/olat/course/nodes/gta/manager/GTAIdentityMarkDAOTest.java b/src/test/java/org/olat/course/nodes/gta/manager/GTAIdentityMarkDAOTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e30953d7e1548a5a1f2c16110a759956c91f850a --- /dev/null +++ b/src/test/java/org/olat/course/nodes/gta/manager/GTAIdentityMarkDAOTest.java @@ -0,0 +1,190 @@ +/** + * <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.manager; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.junit.Before; +import org.junit.Test; +import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.course.nodes.gta.IdentityMark; +import org.olat.course.nodes.gta.TaskList; +import org.olat.course.nodes.gta.model.TaskListImpl; +import org.olat.test.JunitTestHelper; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 03.10.2017<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class GTAIdentityMarkDAOTest extends OlatTestCase { + + @Autowired + private DB dbInstance; + + @Autowired + private GTAIdentityMarkDAO sut; + + @Before + public void emptyTable() { + String statement = "delete from gtaMark"; + dbInstance.getCurrentEntityManager().createQuery(statement).executeUpdate(); + } + + + @Test + public void shouldCreateAndPersistMark() { + TaskList taskList = createTaskList(); + Identity marker = JunitTestHelper.createAndPersistIdentityAsAuthor("coach"); + Identity participant = JunitTestHelper.createAndPersistIdentityAsUser("participant"); + dbInstance.commitAndCloseSession(); + + sut.createAndPersisitMark(taskList, marker, participant); + dbInstance.commitAndCloseSession(); + + IdentityMark reloadedMark = sut.loadMarks(taskList, marker).get(0); + assertThat(reloadedMark).isNotNull(); + assertThat(reloadedMark.getCreationDate()).isNotNull(); + assertThat(reloadedMark.getLastModified()).isNotNull(); + assertThat(reloadedMark.getTaskList()).isEqualTo(taskList); + assertThat(reloadedMark.getMarker()).isEqualTo(marker); + assertThat(reloadedMark.getParticipant()).isEqualTo(participant); + } + + @Test + public void shouldLoadAllMarksOfAMarker() { + TaskList taskList = createTaskList(); + TaskList otherTaskList = createTaskList(); + Identity marker = JunitTestHelper.createAndPersistIdentityAsAuthor("coach"); + Identity otherMarker = JunitTestHelper.createAndPersistIdentityAsAuthor("otherCoach"); + Identity participant1 = JunitTestHelper.createAndPersistIdentityAsUser("participant1"); + Identity participant2 = JunitTestHelper.createAndPersistIdentityAsUser("participant2"); + Identity participant3 = JunitTestHelper.createAndPersistIdentityAsUser("participant3"); + IdentityMark mark1 = sut.createAndPersisitMark(taskList, marker, participant1); + IdentityMark mark2 = sut.createAndPersisitMark(taskList, marker, participant2); + sut.createAndPersisitMark(otherTaskList, marker, participant3); + sut.createAndPersisitMark(taskList, otherMarker, participant3); + IdentityMark mark3 = sut.createAndPersisitMark(taskList, marker, participant3); + dbInstance.commitAndCloseSession(); + + List<IdentityMark> marks = sut.loadMarks(taskList, marker); + + assertThat(marks).hasSize(3); + assertThat(marks).containsExactly(mark1, mark2, mark3); + } + + @Test + public void shouldCheckIfMarked() { + TaskList taskList = createTaskList(); + Identity marker = JunitTestHelper.createAndPersistIdentityAsAuthor("coach"); + Identity participant = JunitTestHelper.createAndPersistIdentityAsUser("participant"); + sut.createAndPersisitMark(taskList, marker, participant); + dbInstance.commitAndCloseSession(); + + boolean isMarked = sut.isMarked(taskList, marker, participant); + + assertThat(isMarked).isTrue(); + } + + @Test + public void shouldCheckIfNotMarked() { + TaskList taskList = createTaskList(); + Identity marker = JunitTestHelper.createAndPersistIdentityAsAuthor("coach"); + Identity participant = JunitTestHelper.createAndPersistIdentityAsUser("participant"); + sut.createAndPersisitMark(taskList, marker, participant); + Identity participantNotMarked = JunitTestHelper.createAndPersistIdentityAsUser("participantNotMarked"); + dbInstance.commitAndCloseSession(); + + boolean isMarked = sut.isMarked(taskList, marker, participantNotMarked); + + assertThat(isMarked).isFalse(); + } + + @Test + public void shouldDeleteMarkOfAMarker() { + TaskList taskList = createTaskList(); + TaskList otherTaskList = createTaskList(); + Identity marker = JunitTestHelper.createAndPersistIdentityAsAuthor("coach"); + Identity otherMarker = JunitTestHelper.createAndPersistIdentityAsAuthor("otherCoach"); + Identity participant1 = JunitTestHelper.createAndPersistIdentityAsUser("participant1"); + Identity participant2 = JunitTestHelper.createAndPersistIdentityAsUser("participant2"); + Identity participant3 = JunitTestHelper.createAndPersistIdentityAsUser("participant3"); + IdentityMark mark1 = sut.createAndPersisitMark(taskList, marker, participant1); + sut.createAndPersisitMark(taskList, marker, participant2); + sut.createAndPersisitMark(otherTaskList, marker, participant3); + sut.createAndPersisitMark(taskList, otherMarker, participant3); + IdentityMark mark3 = sut.createAndPersisitMark(taskList, marker, participant3); + dbInstance.commitAndCloseSession(); + + sut.deleteMark(taskList, marker, participant2); + dbInstance.commitAndCloseSession(); + + List<IdentityMark> marks = sut.loadMarks(taskList, marker); + assertThat(marks).hasSize(2); + assertThat(marks).containsExactly(mark1, mark3); + } + + @Test + public void shouldDeleteMarkOfATaskList() { + TaskList taskList = createTaskList(); + TaskList otherTaskList = createTaskList(); + Identity marker = JunitTestHelper.createAndPersistIdentityAsAuthor("coach"); + Identity otherMarker = JunitTestHelper.createAndPersistIdentityAsAuthor("otherCoach"); + Identity participant1 = JunitTestHelper.createAndPersistIdentityAsUser("participant1"); + Identity participant2 = JunitTestHelper.createAndPersistIdentityAsUser("participant2"); + Identity participant3 = JunitTestHelper.createAndPersistIdentityAsUser("participant3"); + sut.createAndPersisitMark(taskList, marker, participant1); + sut.createAndPersisitMark(taskList, marker, participant2); + sut.createAndPersisitMark(otherTaskList, marker, participant3); + sut.createAndPersisitMark(taskList, otherMarker, participant3); + sut.createAndPersisitMark(taskList, marker, participant3); + dbInstance.commitAndCloseSession(); + + int numberDeleted = sut.deleteMark(taskList); + dbInstance.commitAndCloseSession(); + + assertThat(numberDeleted).isSameAs(4); + List<IdentityMark> marksOfDeletedTaskList = sut.loadMarks(taskList, marker); + assertThat(marksOfDeletedTaskList).hasSize(0); + List<IdentityMark> marksOfExistinTaskList = sut.loadMarks(otherTaskList, marker); + assertThat(marksOfExistinTaskList).hasSize(1); + } + + + private TaskList createTaskList() { + TaskListImpl tasksImpl = new TaskListImpl(); + Date creationDate = new Date(); + tasksImpl.setCreationDate(creationDate); + tasksImpl.setLastModified(creationDate); + tasksImpl.setEntry(JunitTestHelper.createAndPersistRepositoryEntry()); + tasksImpl.setCourseNodeIdent(UUID.randomUUID().toString()); + dbInstance.getCurrentEntityManager().persist(tasksImpl); + return tasksImpl; + } + +} diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index 787bc6b3cfa2a1d4c8c040b3012d082387e2b9cb..3f477fd5ef136e25bcde3cd8651a59d2b950f1a0 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -137,6 +137,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.manager.GTAIdentityMarkDAOTest.class, org.olat.course.nodes.gta.rule.GTAReminderRuleTest.class, org.olat.course.nodes.pf.manager.PFManagerTest.class, org.olat.course.assessment.AssessmentManagerTest.class,