/** * <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.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import org.olat.basesecurity.GroupRoles; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.commons.services.notifications.Publisher; import org.olat.core.commons.services.notifications.Subscriber; import org.olat.core.commons.services.notifications.model.SubscriptionListItem; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.util.Util; import org.olat.core.util.io.SystemFileFilter; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.GTACourseNode; import org.olat.course.nodes.gta.GTAManager; import org.olat.course.nodes.gta.GTAType; import org.olat.course.nodes.gta.Task; import org.olat.course.nodes.gta.TaskList; import org.olat.course.nodes.gta.model.Membership; import org.olat.course.nodes.gta.ui.GTARunController; import org.olat.course.run.environment.CourseEnvironment; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.group.model.SearchBusinessGroupParams; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; import org.olat.user.UserManager; /** * * Initial date: 24.03.2015<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ class GTANotifications { private final Date compareDate; private final Subscriber subscriber; private final List<SubscriptionListItem> items = new ArrayList<>(); private TaskList taskList; private String displayName; private Calendar cal = Calendar.getInstance(); private final Translator translator; private final GTAManager gtaManager; private final UserManager userManager; private final RepositoryService repositoryService; private final BusinessGroupService businessGroupService; public GTANotifications(Subscriber subscriber, Locale locale, Date compareDate, RepositoryService repositoryService, GTAManager gtaManager, BusinessGroupService businessGroupService, UserManager userManager) { this.gtaManager = gtaManager; this.userManager = userManager; this.repositoryService = repositoryService; this.businessGroupService = businessGroupService; this.subscriber = subscriber; this.compareDate = compareDate; translator = Util.createPackageTranslator(GTARunController.class, locale); } public String getDisplayName() { return displayName; } public List<SubscriptionListItem> getItems() { Publisher p = subscriber.getPublisher(); ICourse course = CourseFactory.loadCourse(p.getResId()); CourseNode node = course.getRunStructure().getNode(p.getSubidentifier()); RepositoryEntry entry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); if(entry.getRepositoryEntryStatus().isClosed() || entry.getRepositoryEntryStatus().isUnpublished()) { return Collections.emptyList(); } if(entry != null && node instanceof GTACourseNode) { displayName = entry.getDisplayname(); GTACourseNode gtaNode = (GTACourseNode)node; taskList = gtaManager.getTaskList(entry, gtaNode); if(GTAType.group.name().equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) { createBusinessGroupsSubscriptionInfo(subscriber.getIdentity(), course.getCourseEnvironment(), gtaNode); } else { createIndividualSubscriptionInfo(subscriber.getIdentity(), course.getCourseEnvironment(), gtaNode); } //copy solutions if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SAMPLE_SOLUTION)) { File solutionDirectory = gtaManager.getSolutionsDirectory(course.getCourseEnvironment(), gtaNode); VFSContainer solutionContainer = gtaManager.getSolutionsContainer(course.getCourseEnvironment(), gtaNode); File[] solutions = solutionDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File solution:solutions) { String author = getAuthor(solution, solutionContainer); appendSubscriptionItem("notifications.solution", new String[] { solution.getName(), author }, solution); } } } return items; } private void createIndividualSubscriptionInfo(Identity subscriberIdentity, CourseEnvironment ce, GTACourseNode gtaNode) { RepositoryEntry entry = ce.getCourseGroupManager().getCourseEntry(); List<String> roles = repositoryService.getRoles(subscriberIdentity, entry); boolean owner = roles.contains(GroupRoles.owner.name()); boolean coach = roles.contains(GroupRoles.coach.name()); if(owner|| coach) { Set<Identity> duplicateKiller = new HashSet<>(); List<Identity> assessableIdentities = new ArrayList<>(); List<Identity> participants; List<BusinessGroup> coachedGroups = null; if(owner) { participants = businessGroupService.getMembersOf(entry, false, true); } else { SearchBusinessGroupParams params = new SearchBusinessGroupParams(subscriberIdentity, true, false); coachedGroups = businessGroupService.findBusinessGroups(params, entry, 0, -1); participants = businessGroupService.getMembers(coachedGroups, GroupRoles.participant.name()); } for(Identity participant:participants) { if(!duplicateKiller.contains(participant)) { assessableIdentities.add(participant); duplicateKiller.add(participant); } } boolean repoTutor = owner || (coachedGroups.isEmpty() && repositoryService.hasRole(subscriberIdentity, entry, GroupRoles.coach.name())); if(repoTutor) { List<Identity> courseParticipants = repositoryService.getMembers(entry, GroupRoles.participant.name()); for(Identity participant:courseParticipants) { if(!duplicateKiller.contains(participant)) { assessableIdentities.add(participant); duplicateKiller.add(participant); } } } for(Identity assessedIdentity: assessableIdentities) { createIndividualSubscriptionInfo(assessedIdentity, ce, gtaNode, true); } } if(roles.contains(GroupRoles.participant.name())) { createIndividualSubscriptionInfo(subscriberIdentity, ce, gtaNode, false); } } private void createIndividualSubscriptionInfo(Identity assessedIdentity, CourseEnvironment ce, GTACourseNode gtaNode, boolean coach) { String fullName = userManager.getUserDisplayName(assessedIdentity); if(coach && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) { File submitDirectory = gtaManager.getSubmitDirectory(ce, gtaNode, assessedIdentity); File[] solutions = submitDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File solution:solutions) { appendSubscriptionItem("notifications.submission.individual", new String[] { solution.getName(), fullName }, solution); } } if(!coach && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)) { File correctionDirectory = gtaManager.getCorrectionDirectory(ce, gtaNode, assessedIdentity); VFSContainer correctionContainer = gtaManager.getCorrectionContainer(ce, gtaNode, assessedIdentity); File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File correction:corrections) { String author = getAuthor(correction, correctionContainer); appendSubscriptionItem("notifications.correction", new String[] { correction.getName(), author }, correction); } } if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) { Task task = gtaManager.getTask(assessedIdentity, taskList); if(task != null) { int currentIteration = task.getRevisionLoop(); for(int i=1; i<=currentIteration; i++) { //revision if(coach) { //revision File revisionDirectory = gtaManager.getRevisedDocumentsDirectory(ce, gtaNode, i, assessedIdentity); File[] revisions = revisionDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File revision:revisions) { appendSubscriptionItem("notifications.revision.individual", new String[] { revision.getName(), fullName }, revision); } } else { //corrections File correctionDirectory = gtaManager.getRevisedDocumentsCorrectionsDirectory(ce, gtaNode, i, assessedIdentity); VFSContainer correctionContainer = gtaManager.getRevisedDocumentsCorrectionsContainer(ce, gtaNode, i, assessedIdentity); File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File correction:corrections) { String author = getAuthor(correction, correctionContainer); appendSubscriptionItem("notifications.correction", new String[] { correction.getName(), author }, correction); } } } } } } private void createBusinessGroupsSubscriptionInfo(Identity subscriberIdentity, CourseEnvironment ce, GTACourseNode gtaNode) { RepositoryEntry entry = ce.getCourseGroupManager().getCourseEntry(); Membership membership = gtaManager.getMembership(subscriberIdentity, entry, gtaNode); boolean owner = repositoryService.hasRole(subscriberIdentity, entry, GroupRoles.owner.name()); if(owner) { List<BusinessGroup> groups = gtaManager.getBusinessGroups(gtaNode); for(BusinessGroup group:groups) { createBusinessGroupsSubscriptionItems(group, ce, gtaNode, true); } } else if(membership.isCoach() ) { List<BusinessGroup> groups = gtaManager.getCoachedBusinessGroups(subscriberIdentity, gtaNode); for(BusinessGroup group:groups) { createBusinessGroupsSubscriptionItems(group, ce, gtaNode, true); } } if(membership.isParticipant()) { List<BusinessGroup> groups = gtaManager.getParticipatingBusinessGroups(subscriberIdentity, gtaNode); for(BusinessGroup group:groups) { createBusinessGroupsSubscriptionItems(group, ce, gtaNode, false); } } } private void createBusinessGroupsSubscriptionItems(BusinessGroup group, CourseEnvironment ce, GTACourseNode gtaNode, boolean coach) { if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) { File submitDirectory = gtaManager.getSubmitDirectory(ce, gtaNode, group); VFSContainer submitContainer = gtaManager.getSubmitContainer(ce, gtaNode, group); File[] documents = submitDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File document:documents) { String author = getAuthor(document, submitContainer); appendSubscriptionItem("notifications.submission.group", new String[] { document.getName(), group.getName(), author }, document); } } if(!coach && gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)) { File correctionDirectory = gtaManager.getCorrectionDirectory(ce, gtaNode, group); VFSContainer correctionContainer = gtaManager.getCorrectionContainer(ce, gtaNode, group); File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File correction:corrections) { String author = getAuthor(correction, correctionContainer); appendSubscriptionItem("notifications.correction", new String[] { correction.getName(), author }, correction); } } if(gtaNode.getModuleConfiguration().getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) { Task task = gtaManager.getTask(group, taskList); if(task != null) { int currentIteration = task.getRevisionLoop(); for(int i=1; i<=currentIteration; i++) { //revision File revisionDirectory = gtaManager.getRevisedDocumentsDirectory(ce, gtaNode, i, group); VFSContainer revisionContainer = gtaManager.getRevisedDocumentsContainer(ce, gtaNode, i, group); File[] revisions = revisionDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File revision:revisions) { String author = getAuthor(revision, revisionContainer); appendSubscriptionItem("notifications.revision.group", new String[] { revision.getName(), group.getName(), author }, revision); } //corrections if(!coach) { File correctionDirectory = gtaManager.getRevisedDocumentsCorrectionsDirectory(ce, gtaNode, i, group); VFSContainer correctionContainer = gtaManager.getRevisedDocumentsCorrectionsContainer(ce, gtaNode, i, group); File[] corrections = correctionDirectory.listFiles(SystemFileFilter.FILES_ONLY); for(File correction:corrections) { String author = getAuthor(correction, correctionContainer); appendSubscriptionItem("notifications.correction", new String[] { correction.getName(), author }, correction); } } } } } } private String getAuthor(File file, VFSContainer container) { String author = null; VFSItem item = container.resolve(file.getName()); if(item instanceof MetaTagged) { MetaInfo info = ((MetaTagged)item).getMetaInfo(); if(info != null) { String username = info.getAuthor(); if(username != null) { author = userManager.getUserDisplayName(username); } } } return author == null ? "" : author; } private void appendSubscriptionItem(String notificationKey, String[] params, File file) { cal.setTimeInMillis(file.lastModified()); Date modDate = cal.getTime(); if(modDate.compareTo(compareDate) >= 0) { String desc = translator.translate(notificationKey, params); String businessPath = subscriber.getPublisher().getBusinessPath(); String urlToSend = BusinessControlFactory.getInstance().getURLFromBusinessPathString(businessPath); String iconCssClass = GTANotificationsHandler.CSS_CLASS_ICON; SubscriptionListItem item = new SubscriptionListItem(desc, urlToSend, businessPath, modDate, iconCssClass); items.add(item); } } }