/**
* <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.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import org.olat.basesecurity.GroupRoles;
import org.olat.basesecurity.IdentityRef;
import org.olat.core.commons.modules.bc.FolderConfig;
import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.services.notifications.PublisherData;
import org.olat.core.commons.services.notifications.SubscriptionContext;
import org.olat.core.id.Identity;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.StringHelper;
import org.olat.core.util.io.SystemFilenameFilter;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSManager;
import org.olat.core.util.xml.XStreamHelper;
import org.olat.course.nodes.GTACourseNode;
import org.olat.course.nodes.gta.AssignmentResponse;
import org.olat.course.nodes.gta.AssignmentResponse.Status;
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.TaskLight;
import org.olat.course.nodes.gta.TaskList;
import org.olat.course.nodes.gta.TaskProcess;
import org.olat.course.nodes.gta.model.Membership;
import org.olat.course.nodes.gta.model.Solution;
import org.olat.course.nodes.gta.model.SolutionList;
import org.olat.course.nodes.gta.model.TaskDefinition;
import org.olat.course.nodes.gta.model.TaskDefinitionList;
import org.olat.course.nodes.gta.model.TaskImpl;
import org.olat.course.nodes.gta.model.TaskListImpl;
import org.olat.course.nodes.gta.ui.events.SubmitEvent;
import org.olat.course.run.environment.CourseEnvironment;
import org.olat.group.BusinessGroup;
import org.olat.group.BusinessGroupRef;
import org.olat.group.BusinessGroupService;
import org.olat.group.DeletableGroupData;
import org.olat.group.area.BGAreaManager;
import org.olat.group.manager.BusinessGroupRelationDAO;
import org.olat.group.model.BusinessGroupRefImpl;
import org.olat.modules.ModuleConfiguration;
import org.olat.modules.assessment.AssessmentService;
import org.olat.modules.assessment.model.AssessmentEntryStatus;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryEntryRef;
import org.olat.repository.manager.RepositoryEntryRelationDAO;
import org.olat.resource.OLATResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.thoughtworks.xstream.XStream;
/**
*
* Initial date: 24.02.2015<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
@Service
public class GTAManagerImpl implements GTAManager, DeletableGroupData {
private static final OLog log = Tracing.createLoggerFor(GTAManagerImpl.class);
private static final XStream taskDefinitionsXstream = XStreamHelper.createXStreamInstance();
@Autowired
private DB dbInstance;
@Autowired
private BGAreaManager areaManager;
@Autowired
private AssessmentService assessmentService;
@Autowired
private BusinessGroupService businessGroupService;
@Autowired
private BusinessGroupRelationDAO businessGroupRelationDao;
@Autowired
private RepositoryEntryRelationDAO repositoryEntryRelationDao;
/**
* Get the task folder path relative to the folder root for a specific node.
*
* @param courseEnv
* @param cNode
* @return the task folder path relative to the folder root.
*/
@Override
public VFSContainer getTasksContainer(CourseEnvironment courseEnv, GTACourseNode cNode) {
return getContainer(courseEnv, "tasks", cNode);
}
@Override
public File getTasksDirectory(CourseEnvironment courseEnv, GTACourseNode cNode) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "tasks");
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public List<TaskDefinition> getTaskDefinitions(CourseEnvironment courseEnv, GTACourseNode cNode) {
Path taskDefinitionsPath = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), TASKS_DEFINITIONS);
List<TaskDefinition> taskDefinitions = new ArrayList<>();
if(Files.exists(taskDefinitionsPath)) {
TaskDefinitionList taskDefinitionsList = (TaskDefinitionList)taskDefinitionsXstream.fromXML(taskDefinitionsPath.toFile());
if(taskDefinitionsList != null && taskDefinitionsList.getTasks() != null) {
taskDefinitions.addAll(taskDefinitionsList.getTasks());
}
} else {
syncWithTaskList(courseEnv, cNode, new TaskListSynched() {
@Override
public void sync() {
ModuleConfiguration config = cNode.getModuleConfiguration();
TaskDefinitionList tasks = (TaskDefinitionList)config.get(GTACourseNode.GTASK_TASKS);
if(tasks != null) {
taskDefinitions.addAll(tasks.getTasks());
}
storeTaskDefinitions(taskDefinitions, courseEnv, cNode);
}
});
}
return taskDefinitions;
}
@Override
public void addTaskDefinition(TaskDefinition newTask, CourseEnvironment courseEnv, GTACourseNode cNode) {
syncWithTaskList( courseEnv, cNode, new TaskListSynched() {
@Override
public void sync() {
List<TaskDefinition> taskDefinitions = getTaskDefinitions(courseEnv, cNode);
taskDefinitions.add(newTask);
storeTaskDefinitions(taskDefinitions, courseEnv, cNode);
}
});
}
@Override
public void removeTaskDefinition(TaskDefinition removedTask, CourseEnvironment courseEnv, GTACourseNode cNode) {
syncWithTaskList( courseEnv, cNode, new TaskListSynched() {
@Override
public void sync() {
List<TaskDefinition> taskDefinitions = getTaskDefinitions(courseEnv, cNode);
boolean deleteFile = true;
for(int i=taskDefinitions.size(); i-->0; ) {
if(taskDefinitions.get(i).getTitle().equals(removedTask.getTitle())) {
taskDefinitions.remove(i);
} else if(taskDefinitions.get(i).getFilename().equals(removedTask.getFilename())) {
deleteFile = false;
}
}
if(deleteFile) {
VFSContainer tasksContainer = getTasksContainer(courseEnv, cNode);
VFSItem item = tasksContainer.resolve(removedTask.getFilename());
if(item != null) {
item.delete();
}
}
storeTaskDefinitions(taskDefinitions, courseEnv, cNode);
}
});
}
@Override
public void updateTaskDefinition(String currentFilename, TaskDefinition task, CourseEnvironment courseEnv, GTACourseNode cNode) {
syncWithTaskList( courseEnv, cNode, new TaskListSynched() {
@Override
public void sync() {
String filename = currentFilename == null ? task.getFilename() : currentFilename;
List<TaskDefinition> taskDefinitions = getTaskDefinitions(courseEnv, cNode);
for(int i=taskDefinitions.size(); i-->0; ) {
if(taskDefinitions.get(i).getFilename().equals(filename)) {
taskDefinitions.set(i, task);
break;
}
}
storeTaskDefinitions(taskDefinitions, courseEnv, cNode);
}
});
}
private void storeTaskDefinitions(List<TaskDefinition> taskDefinitions, CourseEnvironment courseEnv, GTACourseNode cNode) {
TaskDefinitionList list = new TaskDefinitionList();
list.setTasks(taskDefinitions);
Path taskDefinitionsPath = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), TASKS_DEFINITIONS);
XStreamHelper.writeObject(taskDefinitionsXstream, taskDefinitionsPath.toFile(), list);
}
@Override
public File getSolutionsDirectory(CourseEnvironment courseEnv, GTACourseNode cNode) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "solutions");
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public VFSContainer getSolutionsContainer(CourseEnvironment courseEnv, GTACourseNode cNode) {
return getContainer(courseEnv, "solutions", cNode);
}
@Override
public List<Solution> getSolutions(CourseEnvironment courseEnv, GTACourseNode cNode) {
Path solutionDefinitionsPath = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), SOLUTIONS_DEFINITIONS);
List<Solution> solutionsDefinitions = new ArrayList<>();
if(Files.exists(solutionDefinitionsPath)) {
SolutionList solutionDefinitionsList = (SolutionList)taskDefinitionsXstream.fromXML(solutionDefinitionsPath.toFile());
if(solutionDefinitionsList != null && solutionDefinitionsList.getSolutions() != null) {
solutionsDefinitions.addAll(solutionDefinitionsList.getSolutions());
}
} else {
syncWithTaskList( courseEnv, cNode, new TaskListSynched() {
@Override
public void sync() {
ModuleConfiguration config = cNode.getModuleConfiguration();
SolutionList solutions = (SolutionList)config.get(GTACourseNode.GTASK_SOLUTIONS);
if(solutions != null && solutions.getSolutions() != null) {
solutionsDefinitions.addAll(solutions.getSolutions());
}
storeSolutions(solutionsDefinitions, courseEnv, cNode);
}
});
}
return solutionsDefinitions;
}
@Override
public void addSolution(Solution newSolution, CourseEnvironment courseEnv, GTACourseNode cNode) {
syncWithTaskList( courseEnv, cNode, new TaskListSynched() {
@Override
public void sync() {
List<Solution> solutions = getSolutions(courseEnv, cNode);
solutions.add(newSolution);
storeSolutions(solutions, courseEnv, cNode);
}
});
}
@Override
public void removeSolution(Solution removedSolution, CourseEnvironment courseEnv, GTACourseNode cNode) {
syncWithTaskList( courseEnv, cNode, new TaskListSynched() {
@Override
public void sync() {
List<Solution> solutions = getSolutions(courseEnv, cNode);
for(int i=solutions.size(); i-->0; ) {
if(solutions.get(i).getFilename().equals(removedSolution.getFilename())) {
solutions.remove(i);
break;
}
}
storeSolutions(solutions, courseEnv, cNode);
}
});
}
@Override
public void updateSolution(String currentFilename, Solution solution, CourseEnvironment courseEnv, GTACourseNode cNode) {
syncWithTaskList( courseEnv, cNode, new TaskListSynched() {
@Override
public void sync() {
String filename = currentFilename == null ? solution.getFilename() : currentFilename;
List<Solution> solutions = getSolutions(courseEnv, cNode);
for(int i=solutions.size(); i-->0; ) {
if(solutions.get(i).getFilename().equals(filename)) {
solutions.set(i, solution);
break;
}
}
storeSolutions(solutions, courseEnv, cNode);
}
});
}
private void storeSolutions(List<Solution> solutions, CourseEnvironment courseEnv, GTACourseNode cNode) {
SolutionList list = new SolutionList();
list.setSolutions(solutions);
Path solutionsPath = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), SOLUTIONS_DEFINITIONS);
XStreamHelper.writeObject(taskDefinitionsXstream, solutionsPath.toFile(), list);
}
private void syncWithTaskList(CourseEnvironment courseEnv, GTACourseNode cNode, TaskListSynched synched) {
TaskList tasks = getTaskList(courseEnv.getCourseGroupManager().getCourseEntry(), cNode);
if(tasks != null) {
loadForUpdate(tasks);
synched.sync();
dbInstance.commit();
} else {
synched.sync();
}
}
@Override
public File getSubmitDirectory(CourseEnvironment courseEnv, GTACourseNode cNode, IdentityRef person) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "dropboxes", "person_" + person.getKey());
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public File getSubmitDirectory(CourseEnvironment courseEnv, GTACourseNode cNode, BusinessGroupRef group) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "dropboxes", "bgroup_" + group.getKey());
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public VFSContainer getSubmitContainer(CourseEnvironment courseEnv, GTACourseNode cNode, IdentityRef person) {
VFSContainer container = getContainer(courseEnv, "dropboxes", cNode);
String subFolder = "person_" + person.getKey();
return VFSManager.getOrCreateContainer(container, subFolder);
}
@Override
public VFSContainer getSubmitContainer(CourseEnvironment courseEnv, GTACourseNode cNode, BusinessGroupRef group) {
VFSContainer container = getContainer(courseEnv, "dropboxes", cNode);
String subFolder = "bgroup_" + group.getKey();
return VFSManager.getOrCreateContainer(container, subFolder);
}
@Override
public File getCorrectionDirectory(CourseEnvironment courseEnv, GTACourseNode cNode, IdentityRef person) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "corrections", "person_" + person.getKey());
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public VFSContainer getCorrectionContainer(CourseEnvironment courseEnv, GTACourseNode cNode, IdentityRef person) {
VFSContainer container = getContainer(courseEnv, "corrections", cNode);
String subFolder = "person_" + person.getKey();
return VFSManager.getOrCreateContainer(container, subFolder);
}
@Override
public File getCorrectionDirectory(CourseEnvironment courseEnv, GTACourseNode cNode, BusinessGroupRef group) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "corrections", "bgroup_" + group.getKey());
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public VFSContainer getCorrectionContainer(CourseEnvironment courseEnv, GTACourseNode cNode, BusinessGroupRef group) {
VFSContainer container = getContainer(courseEnv, "corrections", cNode);
String subFolder = "bgroup_" + group.getKey();
return VFSManager.getOrCreateContainer(container, subFolder);
}
@Override
public File getRevisedDocumentsDirectory(CourseEnvironment courseEnv, GTACourseNode cNode, int iteration, IdentityRef person) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "revisions_" + iteration, "person_" + person.getKey());
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public VFSContainer getRevisedDocumentsContainer(CourseEnvironment courseEnv, GTACourseNode cNode, int iteration, IdentityRef person) {
VFSContainer container = getContainer(courseEnv, "revisions_" + iteration, cNode);
return VFSManager.getOrCreateContainer(container, "person_" + person.getKey());
}
@Override
public File getRevisedDocumentsDirectory(CourseEnvironment courseEnv, GTACourseNode cNode, int iteration, BusinessGroupRef group) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "revisions_" + iteration, "bgroup_" + group.getKey());
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public VFSContainer getRevisedDocumentsContainer(CourseEnvironment courseEnv, GTACourseNode cNode, int iteration, BusinessGroupRef group) {
VFSContainer container = getContainer(courseEnv, "revisions_" + iteration, cNode);
return VFSManager.getOrCreateContainer(container, "bgroup_" + group.getKey());
}
@Override
public File getRevisedDocumentsCorrectionsDirectory(CourseEnvironment courseEnv, GTACourseNode cNode, int iteration, IdentityRef person) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "corrections_" + iteration, "person_" + person.getKey());
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public VFSContainer getRevisedDocumentsCorrectionsContainer(CourseEnvironment courseEnv, GTACourseNode cNode, int iteration, IdentityRef person) {
VFSContainer container = getContainer(courseEnv, "corrections_" + iteration, cNode);
return VFSManager.getOrCreateContainer(container, "person_" + person.getKey());
}
@Override
public File getRevisedDocumentsCorrectionsDirectory(CourseEnvironment courseEnv, GTACourseNode cNode, int iteration, BusinessGroupRef group) {
Path path = Paths.get(FolderConfig.getCanonicalRoot(), courseEnv.getCourseBaseContainer().getRelPath(),
"gtasks", cNode.getIdent(), "corrections_" + iteration, "bgroup_" + group.getKey());
File file = path.toFile();
if(!file.exists()) {
file.mkdirs();
}
return file;
}
@Override
public VFSContainer getRevisedDocumentsCorrectionsContainer(CourseEnvironment courseEnv, GTACourseNode cNode, int iteration, BusinessGroupRef group) {
VFSContainer container = getContainer(courseEnv, "corrections_" + iteration, cNode);
return VFSManager.getOrCreateContainer(container, "bgroup_" + group.getKey());
}
private VFSContainer getContainer(CourseEnvironment courseEnv, String folderName, GTACourseNode cNode) {
OlatRootFolderImpl courseContainer = courseEnv.getCourseBaseContainer();
VFSContainer nodesContainer = VFSManager.getOrCreateContainer(courseContainer, "gtasks");
VFSContainer nodeContainer = VFSManager.getOrCreateContainer(nodesContainer, cNode.getIdent());
return VFSManager.getOrCreateContainer(nodeContainer, folderName);
}
@Override
public PublisherData getPublisherData(CourseEnvironment courseEnv, GTACourseNode cNode) {
RepositoryEntry re = courseEnv.getCourseGroupManager().getCourseEntry();
String businessPath = "[RepositoryEntry:" + re.getKey() + "][CourseNode:" + cNode.getIdent() + "]";
return new PublisherData("GroupTask", "", businessPath);
}
@Override
public SubscriptionContext getSubscriptionContext(CourseEnvironment courseEnv, GTACourseNode cNode) {
return new SubscriptionContext("CourseModule", courseEnv.getCourseResourceableId(), cNode.getIdent());
}
@Override
public SubscriptionContext getSubscriptionContext(OLATResource courseResource, GTACourseNode cNode) {
Long courseResourceableId = courseResource.getResourceableId();
return new SubscriptionContext("CourseModule", courseResourceableId, cNode.getIdent());
}
@Override
public List<BusinessGroup> filterBusinessGroups(List<BusinessGroup> groups, GTACourseNode cNode) {
if(groups == null || groups.isEmpty()) return new ArrayList<>(1);
List<BusinessGroup> filteredGroups = new ArrayList<>();
ModuleConfiguration config = cNode.getModuleConfiguration();
List<Long> groupKeys = config.getList(GTACourseNode.GTASK_GROUPS, Long.class);
for(BusinessGroup group:groups) {
if(groupKeys.contains(group.getKey())) {
filteredGroups.add(group);
}
}
if(filteredGroups.size() < groups.size()) {
List<Long> areaKeys = config.getList(GTACourseNode.GTASK_AREAS, Long.class);
List<Long> groupKeysOfAreas = areaManager.findBusinessGroupKeysOfAreaKeys(areaKeys);
for(BusinessGroup group:groups) {
//don't add 2x
if(!groupKeys.contains(group.getKey()) && groupKeysOfAreas.contains(group.getKey())) {
filteredGroups.add(group);
}
}
}
return filteredGroups;
}
@Override
public List<BusinessGroup> getParticipatingBusinessGroups(IdentityRef identity, GTACourseNode cNode) {
ModuleConfiguration config = cNode.getModuleConfiguration();
List<Long> groupKeys = config.getList(GTACourseNode.GTASK_GROUPS, Long.class);
List<Long> areaKeys = config.getList(GTACourseNode.GTASK_AREAS, Long.class);
return getBusinessGroups(identity, groupKeys, areaKeys, GroupRoles.participant);
}
@Override
public List<BusinessGroup> getCoachedBusinessGroups(IdentityRef identity, GTACourseNode cNode) {
ModuleConfiguration config = cNode.getModuleConfiguration();
List<Long> groupKeys = config.getList(GTACourseNode.GTASK_GROUPS, Long.class);
List<Long> areaKeys = config.getList(GTACourseNode.GTASK_AREAS, Long.class);
return getBusinessGroups(identity, groupKeys, areaKeys, GroupRoles.coach);
}
private List<BusinessGroup> getBusinessGroups(IdentityRef identity, List<Long> groupKeys, List<Long> areaKeys, GroupRoles role) {
List<Long> consolidatedGroupKeys = new ArrayList<>();
if(groupKeys != null && groupKeys.size() > 0) {
consolidatedGroupKeys.addAll(groupKeys);
}
consolidatedGroupKeys.addAll(areaManager.findBusinessGroupKeysOfAreaKeys(areaKeys));
List<BusinessGroupRef> businessGroups = BusinessGroupRefImpl.toRefs(consolidatedGroupKeys);
return businessGroupRelationDao.filterMembership(businessGroups, identity, role.name());
}
@Override
public List<BusinessGroup> getBusinessGroups(GTACourseNode cNode) {
List<BusinessGroup> groups;
ModuleConfiguration config = cNode.getModuleConfiguration();
if(GTAType.group.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE))) {
List<Long> groupKeys = config.getList(GTACourseNode.GTASK_GROUPS, Long.class);
List<Long> areaKeys = config.getList(GTACourseNode.GTASK_AREAS, Long.class);
List<Long> consolidatedGroupKeys = new ArrayList<>();
if(groupKeys != null && groupKeys.size() > 0) {
consolidatedGroupKeys.addAll(groupKeys);
}
consolidatedGroupKeys.addAll(areaManager.findBusinessGroupKeysOfAreaKeys(areaKeys));
groups = businessGroupService.loadBusinessGroups(consolidatedGroupKeys);
} else {
groups = Collections.emptyList();
}
return groups;
}
@Override
public List<IdentityRef> getDuplicatedMemberships(GTACourseNode cNode) {
List<IdentityRef> duplicates;
ModuleConfiguration config = cNode.getModuleConfiguration();
if(GTAType.group.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE))) {
List<Long> groupKeys = config.getList(GTACourseNode.GTASK_GROUPS, Long.class);
List<Long> areaKeys = config.getList(GTACourseNode.GTASK_AREAS, Long.class);
List<Long> consolidatedGroupKeys = new ArrayList<>();
if(groupKeys != null && groupKeys.size() > 0) {
consolidatedGroupKeys.addAll(groupKeys);
}
consolidatedGroupKeys.addAll(areaManager.findBusinessGroupKeysOfAreaKeys(areaKeys));
List<BusinessGroupRef> businessGroups = BusinessGroupRefImpl.toRefs(consolidatedGroupKeys);
duplicates = businessGroupRelationDao.getDuplicateMemberships(businessGroups);
} else {
duplicates = Collections.emptyList();
}
return duplicates;
}
@Override
public Membership getMembership(IdentityRef identity, RepositoryEntryRef entry, GTACourseNode cNode) {
List<String> roles;
ModuleConfiguration config = cNode.getModuleConfiguration();
if(GTAType.group.name().equals(config.getStringValue(GTACourseNode.GTASK_TYPE))) {
List<Long> groupKeys = config.getList(GTACourseNode.GTASK_GROUPS, Long.class);
List<Long> areaKeys = config.getList(GTACourseNode.GTASK_AREAS, Long.class);
List<Long> consolidatedGroupKeys = new ArrayList<>();
if(groupKeys != null && groupKeys.size() > 0) {
consolidatedGroupKeys.addAll(groupKeys);
}
consolidatedGroupKeys.addAll(areaManager.findBusinessGroupKeysOfAreaKeys(areaKeys));
List<BusinessGroupRef> businessGroups = BusinessGroupRefImpl.toRefs(consolidatedGroupKeys);
roles = businessGroupRelationDao.getRoles(identity, businessGroups);
} else {
roles = repositoryEntryRelationDao.getRoles(identity, entry);
}
boolean coach = roles.contains(GroupRoles.coach.name()) || roles.contains(GroupRoles.owner.name());
boolean participant = roles.contains(GroupRoles.participant.name());
return new Membership(coach, participant);
}
@Override
public String getDetails(Identity assessedIdentity, RepositoryEntryRef entry, GTACourseNode cNode) {
String details;
if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_ASSIGNMENT)) {
List<Task> tasks = getTasks(assessedIdentity, entry, cNode);
if(tasks == null || tasks.isEmpty()) {
details = null;
} else {
StringBuilder sb = new StringBuilder();
for(Task task:tasks) {
if(sb.length() > 0) sb.append(", ");
if(sb.length() > 64) {
sb.append("...");
break;
}
String taskName = task.getTaskName();
if(StringHelper.containsNonWhitespace(taskName)) {
sb.append(StringHelper.escapeHtml(taskName));
}
}
details = sb.length() == 0 ? null : sb.toString();
}
} else {
details = null;
}
return details;
}
@Override
public boolean isTasksInProcess(RepositoryEntryRef entry, GTACourseNode cNode) {
List<Number> numOfTasks = dbInstance.getCurrentEntityManager()
.createNamedQuery("isTasksInProcess", Number.class)
.setParameter("entryKey", entry.getKey())
.setParameter("courseNodeIdent", cNode.getIdent())
.getResultList();
return numOfTasks != null && !numOfTasks.isEmpty() && numOfTasks.get(0) != null && numOfTasks.get(0).intValue() > 0;
}
@Override
public boolean isTaskInProcess(RepositoryEntryRef entry, GTACourseNode cNode, String taskName) {
List<Number> numOfTasks = dbInstance.getCurrentEntityManager()
.createNamedQuery("isTaskInProcess", Number.class)
.setParameter("entryKey", entry.getKey())
.setParameter("courseNodeIdent", cNode.getIdent())
.setParameter("taskName", taskName)
.getResultList();
return numOfTasks != null && !numOfTasks.isEmpty() && numOfTasks.get(0) != null && numOfTasks.get(0).intValue() > 0;
}
@Override
public TaskList createIfNotExists(RepositoryEntry entry, GTACourseNode cNode) {
TaskList tasks = getTaskList(entry, cNode);
if(tasks == null) {
TaskListImpl tasksImpl = new TaskListImpl();
Date creationDate = new Date();
tasksImpl.setCreationDate(creationDate);
tasksImpl.setLastModified(creationDate);
tasksImpl.setEntry(entry);
tasksImpl.setCourseNodeIdent(cNode.getIdent());
dbInstance.getCurrentEntityManager().persist(tasksImpl);
tasks = tasksImpl;
}
return tasks;
}
@Override
public TaskList getTaskList(RepositoryEntryRef entry, GTACourseNode cNode) {
String q = "select tasks from gtatasklist tasks where tasks.entry.key=:entryKey and tasks.courseNodeIdent=:courseNodeIdent";
List<TaskList> tasks = dbInstance.getCurrentEntityManager().createQuery(q, TaskList.class)
.setParameter("entryKey", entry.getKey())
.setParameter("courseNodeIdent", cNode.getIdent())
.getResultList();
return tasks.isEmpty() ? null : tasks.get(0);
}
@Override
public boolean deleteGroupDataFor(BusinessGroup group) {
log.audit("Delete tasks of business group: " + group.getKey());
String deleteTasks = "delete from gtatask as task where task.businessGroup.key=:groupKey";
dbInstance.getCurrentEntityManager()
.createQuery(deleteTasks)
.setParameter("groupKey", group.getKey())
.executeUpdate();
return true;
}
@Override
public int deleteTaskList(RepositoryEntryRef entry, GTACourseNode cNode) {
TaskList taskList = getTaskList(entry, cNode);
int numOfDeletedObjects;
if(taskList != null) {
String deleteTasks = "delete from gtatask as task where task.taskList.key=:taskListKey";
int numOfTasks = dbInstance.getCurrentEntityManager().createQuery(deleteTasks)
.setParameter("taskListKey", taskList.getKey())
.executeUpdate();
dbInstance.getCurrentEntityManager().remove(taskList);
numOfDeletedObjects = numOfTasks + 1;
} else {
numOfDeletedObjects = 0;
}
return numOfDeletedObjects;
}
@Override
public int deleteAllTaskLists(RepositoryEntryRef entry) {
String q = "select tasks from gtatasklist tasks where tasks.entry.key=:entryKey";
List<TaskList> taskLists = dbInstance.getCurrentEntityManager().createQuery(q, TaskList.class)
.setParameter("entryKey", entry.getKey())
.getResultList();
String deleteTasks = "delete from gtatask as task where task.taskList.key=:taskListKey";
Query deleteTaskQuery = dbInstance.getCurrentEntityManager().createQuery(deleteTasks);
int numOfDeletedObjects = 0;
for(TaskList taskList:taskLists) {
int numOfTasks = deleteTaskQuery.setParameter("taskListKey", taskList.getKey()).executeUpdate();
numOfDeletedObjects += numOfTasks;
}
String deleteTaskLists = "delete from gtatasklist as tasks where tasks.entry.key=:entryKey";
numOfDeletedObjects += dbInstance.getCurrentEntityManager()
.createQuery(deleteTaskLists)
.setParameter("entryKey", entry.getKey())
.executeUpdate();
return numOfDeletedObjects;
}
@Override
public List<Task> getTasks(TaskList taskList, GTACourseNode cNode) {
StringBuilder sb = new StringBuilder();
sb.append("select task from gtatask task ")
.append(" inner join task.taskList tasklist ");
if(GTAType.group.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
sb.append(" inner join fetch task.businessGroup bGroup ");
} else {
sb.append(" inner join fetch task.identity identity ");
}
sb.append(" where tasklist.key=:taskListKey");
return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Task.class)
.setParameter("taskListKey", taskList.getKey())
.getResultList();
}
@Override
public List<TaskLight> getTasksLight(RepositoryEntryRef entry, GTACourseNode gtaNode) {
StringBuilder sb = new StringBuilder();
sb.append("select task from gtatasklight task ")
.append(" inner join task.taskList tasklist ")
.append(" where tasklist.entry.key=:entryKey and tasklist.courseNodeIdent=:courseNodeIdent");
return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), TaskLight.class)
.setParameter("entryKey", entry.getKey())
.setParameter("courseNodeIdent", gtaNode.getIdent())
.getResultList();
}
@Override
public List<Task> getTasks(IdentityRef identity, RepositoryEntryRef entry, GTACourseNode cNode) {
StringBuilder sb = new StringBuilder();
sb.append("select task from gtatask task ")
.append(" inner join task.taskList tasklist ")
.append(" inner join tasklist.entry rentry ")
.append(" where tasklist.entry.key=:entryKey and tasklist.courseNodeIdent=:courseNodeIdent and (task.identity.key=:identityKey ")
.append(" or task.businessGroup.key in (")
.append(" select bgroup.key from businessgroup as bgroup ")
.append(" inner join bgroup.baseGroup as baseGroup")
.append(" inner join baseGroup.members as membership")
.append(" where membership.identity.key=:identityKey and membership.role='").append(GroupRoles.participant.name()).append("'")
.append(" ))");
return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Task.class)
.setParameter("entryKey", entry.getKey())
.setParameter("courseNodeIdent", cNode.getIdent())
.setParameter("identityKey", identity.getKey())
.getResultList();
}
@Override
public Task getTask(IdentityRef identity, TaskList taskList) {
String q = "select task from gtatask task where task.taskList.key=:taskListKey and task.identity.key=:identityKey";
List<Task> tasks = dbInstance.getCurrentEntityManager().createQuery(q, Task.class)
.setParameter("taskListKey", taskList.getKey())
.setParameter("identityKey", identity.getKey())
.getResultList();
return tasks.isEmpty() ? null : tasks.get(0);
}
@Override
public Task getTask(BusinessGroupRef businessGroup, TaskList taskList) {
String q = "select task from gtatask task where task.taskList.key=:taskListKey and task.businessGroup.key=:businessGroupKey";
List<Task> tasks = dbInstance.getCurrentEntityManager().createQuery(q, Task.class)
.setParameter("taskListKey", taskList.getKey())
.setParameter("businessGroupKey", businessGroup.getKey())
.getResultList();
return tasks.isEmpty() ? null : tasks.get(0);
}
@Override
public AssignmentResponse assignTaskAutomatically(TaskList taskList, BusinessGroup assessedGroup, CourseEnvironment courseEnv, GTACourseNode cNode) {
return assignTaskAutomatically(taskList, assessedGroup, null, courseEnv, cNode);
}
@Override
public AssignmentResponse assignTaskAutomatically(TaskList taskList, Identity assessedIdentity, CourseEnvironment courseEnv, GTACourseNode cNode) {
return assignTaskAutomatically(taskList, null, assessedIdentity, courseEnv, cNode);
}
private AssignmentResponse assignTaskAutomatically(TaskList tasks, BusinessGroup businessGroup, Identity identity,
CourseEnvironment courseEnv, GTACourseNode cNode) {
Task currentTask;
if(businessGroup != null) {
currentTask = getTask(businessGroup, tasks);
} else {
currentTask = getTask(identity, tasks);
}
AssignmentResponse response;
if(currentTask == null) {
TaskList reloadedTasks = loadForUpdate(tasks);
File tasksFolder = getTasksDirectory(courseEnv, cNode);
String[] taskFiles = tasksFolder.list(SystemFilenameFilter.FILES_ONLY);
List<String> assignedFilenames = getAssignedTasks(reloadedTasks);
String taskName;
if(GTACourseNode.GTASK_SAMPLING_UNIQUE.equals(cNode.getModuleConfiguration().get(GTACourseNode.GTASK_SAMPLING))) {
taskName = nextUnique(taskFiles, assignedFilenames);
} else {
taskName = nextSlotRoundRobin(taskFiles, assignedFilenames);
}
if(taskName == null) {
response = AssignmentResponse.NO_MORE_TASKS;
} else {
TaskProcess nextStep = nextStep(TaskProcess.assignment, cNode);
TaskImpl task = createTask(taskName, reloadedTasks, nextStep, businessGroup, identity, cNode);
task.setAssignmentDate(new Date());
dbInstance.getCurrentEntityManager().persist(task);
dbInstance.commit();
syncAssessmentEntry((TaskImpl)currentTask, cNode);
response = new AssignmentResponse(task, Status.ok);
}
} else {
if(currentTask.getTaskStatus() == TaskProcess.assignment) {
((TaskImpl)currentTask).setTaskStatus(TaskProcess.submit);
}
currentTask = dbInstance.getCurrentEntityManager().merge(currentTask);
syncAssessmentEntry((TaskImpl)currentTask, cNode);
response = new AssignmentResponse(currentTask, Status.ok);
}
return response;
}
protected String nextUnique(String[] slots, List<String> usedSlots) {
String nextSlot = null;
for(String slot:slots) {
if(!usedSlots.contains(slot)) {
nextSlot = slot;
break;
}
}
return nextSlot;
}
protected String nextSlotRoundRobin(String[] slots, List<String> usedSlots) {
String nextSlot = null;
for(String slot:slots) {
if(!usedSlots.contains(slot)) {
nextSlot = slot;
break;
}
}
//not found an used slot
if(nextSlot == null) {
//statistics
Map<String,AtomicInteger> usages = new HashMap<>();
for(String usedSlot:usedSlots) {
if(usages.containsKey(usedSlot)) {
usages.get(usedSlot).incrementAndGet();
} else {
usages.put(usedSlot, new AtomicInteger(1));
}
}
int minimum = Integer.MAX_VALUE;
for(AtomicInteger slotUsage:usages.values()) {
minimum = Math.min(minimum, slotUsage.get());
}
Set<String> slotsWithMinimalUsage = new HashSet<>();
for(Map.Entry<String, AtomicInteger> slotUsage:usages.entrySet()) {
if(slotUsage.getValue().get() == minimum) {
slotsWithMinimalUsage.add(slotUsage.getKey());
}
}
//found the next slot with minimal usage
for(String slot:slots) {
if(slotsWithMinimalUsage.contains(slot)) {
nextSlot = slot;
break;
}
}
}
//security
if(nextSlot == null && slots.length > 0) {
nextSlot = slots[0];
}
return nextSlot;
}
@Override
public boolean isTaskAssigned(TaskList taskList, String taskName) {
List<Number> tasks = dbInstance.getCurrentEntityManager()
.createNamedQuery("countTaskByNameAndTaskList", Number.class)
.setParameter("taskListKey", taskList.getKey())
.setParameter("taskName", taskName)
.getResultList();
return tasks.isEmpty() ? false : tasks.get(0).intValue() > 0;
}
@Override
public List<String> getAssignedTasks(TaskList taskList) {
return dbInstance.getCurrentEntityManager()
.createNamedQuery("tasksByTaskList", String.class)
.setParameter("taskListKey", taskList.getKey())
.getResultList();
}
@Override
public AssignmentResponse selectTask(Identity identity, TaskList tasks, GTACourseNode cNode, File taskFile) {
if(!GTAType.individual.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
return AssignmentResponse.ERROR;
}
return selectTask(identity, null, tasks, cNode, taskFile);
}
@Override
public AssignmentResponse selectTask(BusinessGroup businessGroup, TaskList tasks, GTACourseNode cNode, File taskFile) {
if(!GTAType.group.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
return AssignmentResponse.ERROR;
}
return selectTask(null, businessGroup, tasks, cNode, taskFile);
}
private AssignmentResponse selectTask(Identity identity, BusinessGroup businessGroup, TaskList tasks, GTACourseNode cNode, File taskFile) {
Task currentTask;
if(businessGroup != null) {
currentTask = getTask(businessGroup, tasks);
} else {
currentTask = getTask(identity, tasks);
}
AssignmentResponse response;
if(currentTask == null) {
String taskName = taskFile.getName();
TaskList reloadedTasks = loadForUpdate(tasks);
String sampling = cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_SAMPLING);
if(GTACourseNode.GTASK_SAMPLING_UNIQUE.equals(sampling) && isTaskAssigned(reloadedTasks, taskName)) {
response = new AssignmentResponse(null, Status.alreadyAssigned);
} else {
TaskProcess nextStep = nextStep(TaskProcess.assignment, cNode);
TaskImpl task = createTask(taskName, reloadedTasks, nextStep, businessGroup, identity, cNode);
task.setAssignmentDate(new Date());
dbInstance.getCurrentEntityManager().persist(task);
response = new AssignmentResponse(task, Status.ok);
}
dbInstance.commit();
} else {
if(currentTask.getTaskStatus() == TaskProcess.assignment) {
TaskProcess nextStep = nextStep(currentTask.getTaskStatus(), cNode);
((TaskImpl)currentTask).setTaskStatus(nextStep);
}
currentTask = dbInstance.getCurrentEntityManager().merge(currentTask);
syncAssessmentEntry((TaskImpl)currentTask, cNode);
response = new AssignmentResponse(currentTask, Status.ok);
}
return response;
}
@Override
public TaskImpl createTask(String taskName, TaskList taskList, TaskProcess status, BusinessGroup assessedGroup, Identity assessedIdentity, GTACourseNode cNode) {
TaskImpl task = new TaskImpl();
Date creationDate = new Date();
task.setCreationDate(creationDate);
task.setLastModified(creationDate);
task.setTaskList(taskList);
task.setTaskName(taskName);
task.setTaskStatus(status);//assignment is ok -> go to submit step
task.setRevisionLoop(0);
if(GTAType.group.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
task.setBusinessGroup(assessedGroup);
} else {
task.setIdentity(assessedIdentity);
}
return task;
}
@Override
public Task nextStep(Task task, GTACourseNode cNode) {
TaskImpl taskImpl = (TaskImpl)task;
TaskProcess currentStep = taskImpl.getTaskStatus();
//cascade through the possible steps
TaskProcess nextStep = nextStep(currentStep, cNode);
taskImpl.setTaskStatus(nextStep);
TaskImpl mergedTask = dbInstance.getCurrentEntityManager().merge(taskImpl);
dbInstance.commit();//make the thing definitiv
syncAssessmentEntry(mergedTask, cNode);
return mergedTask;
}
@Override
public TaskProcess firstStep(GTACourseNode cNode) {
TaskProcess firstStep = null;
if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_ASSIGNMENT)) {
firstStep = TaskProcess.assignment;
} else if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) {
firstStep = TaskProcess.submit;
} else if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)) {
firstStep = TaskProcess.review;
} else if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) {
firstStep = TaskProcess.revision;
} else if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) {
firstStep = TaskProcess.correction;
} else if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)) {
firstStep = TaskProcess.solution;
} else if(cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_GRADING)) {
firstStep = TaskProcess.grading;
}
return firstStep;
}
@Override
public TaskProcess previousStep(TaskProcess currentStep, GTACourseNode cNode) {
TaskProcess previousStep = null;
switch(currentStep) {
case graded:
case grading: {
if(currentStep != TaskProcess.grading && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_GRADING)) {
previousStep = TaskProcess.grading;
break;
}
}
case solution: {
if(currentStep != TaskProcess.solution && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)) {
previousStep = TaskProcess.solution;
break;
}
}
case correction: {
if(currentStep != TaskProcess.correction && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) {
previousStep = TaskProcess.correction;
break;
}
}
case revision: {
if(currentStep != TaskProcess.revision && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) {
previousStep = TaskProcess.revision;
break;
}
}
case review: {
if(currentStep != TaskProcess.review && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)) {
previousStep = TaskProcess.review;
break;
}
}
case submit: {
if(currentStep != TaskProcess.submit && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) {
previousStep = TaskProcess.submit;
break;
}
}
case assignment: {
if(currentStep != TaskProcess.assignment && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_ASSIGNMENT)) {
previousStep = TaskProcess.assignment;
break;
}
}
default: {
previousStep = TaskProcess.assignment;
break;
}
}
return previousStep;
}
@Override
public TaskProcess nextStep(TaskProcess currentStep, GTACourseNode cNode) {
TaskProcess nextStep = null;
switch(currentStep) {
case assignment:
case submit: {
if(currentStep != TaskProcess.submit && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) {
nextStep = TaskProcess.submit;
break;
}
}
case review: {
if(currentStep != TaskProcess.review && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)) {
nextStep = TaskProcess.review;
break;
}
}
case revision: {
if(currentStep != TaskProcess.revision && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) {
nextStep = TaskProcess.revision;
break;
}
}
case correction: {
if(currentStep != TaskProcess.correction && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) {
nextStep = TaskProcess.correction;
break;
}
}
case solution: {
if(currentStep != TaskProcess.solution && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)) {
nextStep = TaskProcess.solution;
break;
}
}
case grading: {
if(currentStep != TaskProcess.grading && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_GRADING)) {
nextStep = TaskProcess.grading;
break;
}
}
case graded: {
if(currentStep != TaskProcess.graded && cNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_GRADING)) {
nextStep = TaskProcess.graded;
break;
}
}
default: {
nextStep = TaskProcess.graded;
break;
}
}
return nextStep;
}
@Override
public int updateTaskName(TaskList taskList, String currentTaskName, String newTaskName) {
String q = "update gtatask set taskName=:newTaskName where taskList.key=:taskListKey and taskName=:oldTaskName";
return dbInstance.getCurrentEntityManager()
.createQuery(q)
.setParameter("taskListKey", taskList.getKey())
.setParameter("oldTaskName", currentTaskName)
.setParameter("newTaskName", newTaskName)
.executeUpdate();
}
@Override
public Task updateTask(Task task, TaskProcess newStatus, GTACourseNode cNode) {
TaskImpl taskImpl = (TaskImpl)task;
taskImpl.setTaskStatus(newStatus);
taskImpl = dbInstance.getCurrentEntityManager().merge(taskImpl);
syncAssessmentEntry(taskImpl, cNode);
return taskImpl;
}
@Override
public Task updateTask(Task task, TaskProcess newStatus, int iteration, GTACourseNode cNode) {
TaskImpl taskImpl = (TaskImpl)task;
taskImpl.setTaskStatus(newStatus);
taskImpl.setRevisionLoop(iteration);
taskImpl = dbInstance.getCurrentEntityManager().merge(taskImpl);
syncAssessmentEntry(taskImpl, cNode);
return taskImpl;
}
@Override
public AssessmentEntryStatus convertToAssessmentEntrystatus(Task task, GTACourseNode cNode) {
TaskProcess status = task.getTaskStatus();
TaskProcess firstStep = firstStep(cNode);
AssessmentEntryStatus assessmentStatus;
if(status == firstStep) {
assessmentStatus = AssessmentEntryStatus.notStarted;
} else if(status == TaskProcess.review || status == TaskProcess.correction || status == TaskProcess.grading) {
assessmentStatus = AssessmentEntryStatus.inReview;
} else if(status == TaskProcess.graded) {
assessmentStatus = AssessmentEntryStatus.done;
} else {
assessmentStatus = AssessmentEntryStatus.inProgress;
}
return assessmentStatus;
}
private void syncAssessmentEntry(TaskImpl taskImpl, GTACourseNode cNode) {
if(taskImpl == null || taskImpl.getTaskStatus() == null || cNode == null) return;
RepositoryEntry courseRepoEntry = taskImpl.getTaskList().getEntry();
AssessmentEntryStatus assessmentStatus = convertToAssessmentEntrystatus(taskImpl, cNode);
if(GTAType.group.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
//update whole group
assessmentService.updateAssessmentEntries(taskImpl.getBusinessGroup(), courseRepoEntry, cNode.getIdent(), null, assessmentStatus);
} else {
assessmentService.updateAssessmentEntry(taskImpl.getIdentity(), courseRepoEntry, cNode.getIdent(), null, assessmentStatus);
}
}
private TaskList loadForUpdate(TaskList tasks) {
dbInstance.getCurrentEntityManager().detach(tasks);
String q = "select tasks from gtatasklist tasks where tasks.key=:taskListKey";
return dbInstance.getCurrentEntityManager()
.createQuery(q, TaskList.class)
.setParameter("taskListKey", tasks.getKey())
.setLockMode(LockModeType.PESSIMISTIC_WRITE)
.getSingleResult();
}
@Override
public void log(String step, String operation, Task assignedTask, Identity actor, Identity assessedIdentity, BusinessGroup assessedGroup,
CourseEnvironment courseEnv, GTACourseNode cNode) {
//log
String msg = step + " of " + assignedTask.getTaskName() + ": " + operation;
if(GTAType.group.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
log.audit(msg + " to business group: " + assessedGroup.getName(), null);
courseEnv.getAuditManager()
.appendToUserNodeLog(cNode, actor, assessedGroup, msg);
} else {
log.audit(msg, null);
courseEnv.getAuditManager()
.appendToUserNodeLog(cNode, actor, assessedIdentity, msg);
}
}
@Override
public void log(String step, SubmitEvent event, Task assignedTask, Identity actor, Identity assessedIdentity, BusinessGroup assessedGroup,
CourseEnvironment courseEnv, GTACourseNode cNode) {
String operation = event.getLogMessage();
String file = event.getFilename();
//log
String msg = step + " of " + assignedTask.getTaskName() + ": " + operation + " " + file;
if(GTAType.group.name().equals(cNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
log.audit(msg + " to business group: " + assessedGroup.getName(), null);
courseEnv.getAuditManager()
.appendToUserNodeLog(cNode, actor, assessedGroup, msg);
} else {
log.audit(msg, null);
courseEnv.getAuditManager()
.appendToUserNodeLog(cNode, actor, assessedIdentity, msg);
}
}
private interface TaskListSynched {
public void sync();
}
}