/**
* <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;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.Locale;
import java.util.zip.ZipOutputStream;
import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
import org.olat.core.commons.services.notifications.NotificationsManager;
import org.olat.core.commons.services.notifications.SubscriptionContext;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.stack.BreadcrumbPanel;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.generic.tabbable.TabbableController;
import org.olat.core.gui.translator.Translator;
import org.olat.core.id.Identity;
import org.olat.core.util.FileUtils;
import org.olat.core.util.Util;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.course.CourseModule;
import org.olat.course.ICourse;
import org.olat.course.editor.CourseEditorEnv;
import org.olat.course.editor.NodeEditController;
import org.olat.course.editor.StatusDescription;
import org.olat.course.nodes.pf.manager.FileSystemExport;
import org.olat.course.nodes.pf.manager.PFManager;
import org.olat.course.nodes.pf.ui.PFEditController;
import org.olat.course.nodes.pf.ui.PFPeekviewController;
import org.olat.course.nodes.pf.ui.PFPreviewController;
import org.olat.course.nodes.pf.ui.PFRunController;
import org.olat.course.run.environment.CourseEnvironment;
import org.olat.course.run.navigation.NodeRunConstructionResult;
import org.olat.course.run.userview.NodeEvaluation;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.modules.ModuleConfiguration;
import org.olat.repository.RepositoryEntry;
public class PFCourseNode extends AbstractAccessableCourseNode {
public static final String TYPE = "pf";
public static final String CONFIG_KEY_PARTICIPANTBOX = "participantbox";
public static final String CONFIG_KEY_COACHBOX = "coachbox";
public static final String CONFIG_KEY_ALTERFILE = "alterfile";
public static final String CONFIG_KEY_LIMITCOUNT = "limitcount";
public static final String CONFIG_KEY_FILECOUNT = "filecount";
public static final String CONFIG_KEY_TIMEFRAME = "timeframe";
public static final String CONFIG_KEY_DATESTART = "datestart";
public static final String CONFIG_KEY_DATEEND = "dateend";
/**
*
*/
public static final long serialVersionUID = 1L;
public PFCourseNode() {
super(TYPE);
updateModuleConfigDefaults(true);
}
/**
* @see org.olat.course.nodes.GenericCourseNode#updateModuleConfigDefaults(boolean)
*/
@Override
public void updateModuleConfigDefaults(boolean isNewNode) {
if (isNewNode) {
// default is to enable both boxes without restrictions
updateModuleConfig(true,true,true, false, 0, false, null, null);
}
}
@Override
public RepositoryEntry getReferencedRepositoryEntry() {
return null;
}
@Override
public boolean needsReferenceToARepositoryEntry() {
return false;
}
public void updateModuleConfig(boolean participantbox, boolean coachbox, boolean alterfile,
boolean limitcount, int filecount, boolean timeframe, Date start, Date end) {
ModuleConfiguration config = getModuleConfiguration();
config.setBooleanEntry(CONFIG_KEY_PARTICIPANTBOX, participantbox);
config.setBooleanEntry(CONFIG_KEY_COACHBOX, coachbox);
config.setBooleanEntry(CONFIG_KEY_ALTERFILE, alterfile);
config.setBooleanEntry(CONFIG_KEY_LIMITCOUNT, limitcount);
if (limitcount){
config.set(CONFIG_KEY_FILECOUNT, filecount);
}
config.setBooleanEntry(CONFIG_KEY_TIMEFRAME, timeframe);
if (timeframe){
config.set(CONFIG_KEY_DATESTART, start);
config.set(CONFIG_KEY_DATEEND, end);
}
}
public boolean hasParticipantBoxConfigured() {
boolean hasStundentBox = getModuleConfiguration().getBooleanSafe(CONFIG_KEY_PARTICIPANTBOX);
return hasStundentBox;
}
public boolean hasCoachBoxConfigured() {
boolean hasTeacherBox = getModuleConfiguration().getBooleanSafe(CONFIG_KEY_COACHBOX);
return hasTeacherBox;
}
public boolean hasAlterFileConfigured() {
boolean hasStundentBox = getModuleConfiguration().getBooleanSafe(CONFIG_KEY_PARTICIPANTBOX);
if (hasStundentBox) {
boolean hasAlterFile = getModuleConfiguration().getBooleanSafe(CONFIG_KEY_ALTERFILE);
return hasAlterFile;
}
return false;
}
public boolean hasLimitCountConfigured() {
boolean hasStundentBox = getModuleConfiguration().getBooleanSafe(CONFIG_KEY_PARTICIPANTBOX);
if (hasStundentBox) {
boolean hasLimitCount = getModuleConfiguration().getBooleanSafe(CONFIG_KEY_LIMITCOUNT);
return hasLimitCount;
}
return false;
}
public boolean isGreaterOrEqualToLimit (int count) {
ModuleConfiguration config = getModuleConfiguration();
int limit = config.getBooleanEntry(CONFIG_KEY_FILECOUNT) != null ?
(int) config.get(CONFIG_KEY_FILECOUNT) : 0;
return count >= limit;
}
public boolean hasDropboxTimeFrameConfigured() {
boolean hasStundentBox = getModuleConfiguration().getBooleanSafe(CONFIG_KEY_PARTICIPANTBOX);
if (hasStundentBox) {
boolean hasTimeFrame = getModuleConfiguration().getBooleanSafe(CONFIG_KEY_TIMEFRAME);
return hasTimeFrame;
}
return false;
}
public boolean isInDropboxTimeFrame () {
ModuleConfiguration config = getModuleConfiguration();
Date start = config.getBooleanEntry(CONFIG_KEY_DATESTART) != null ?
(Date) config.getDateValue(CONFIG_KEY_DATESTART) : new Date();
Date end = config.getBooleanEntry(CONFIG_KEY_DATEEND) != null ?
(Date) config.getDateValue(CONFIG_KEY_DATEEND) : new Date();
Date current = new Date();
return start.before(current) && end.after(current);
}
public int getLimitCount() {
ModuleConfiguration config = getModuleConfiguration();
return config.getBooleanEntry(CONFIG_KEY_FILECOUNT) != null ?
(int) config.get(CONFIG_KEY_FILECOUNT) : 0;
}
public Date getDateStart() {
ModuleConfiguration config = getModuleConfiguration();
return config.getBooleanEntry(CONFIG_KEY_DATESTART) != null ?
(Date) config.getDateValue(CONFIG_KEY_DATESTART) : new Date();
}
public Date getDateEnd() {
ModuleConfiguration config = getModuleConfiguration();
return config.getBooleanEntry(CONFIG_KEY_DATEEND) != null ?
(Date) config.getDateValue(CONFIG_KEY_DATEEND) : new Date();
}
@Override
public StatusDescription isConfigValid() {
StatusDescription sd = StatusDescription.NOERROR;
boolean isValid = hasCoachBoxConfigured() || hasParticipantBoxConfigured();
if (!isValid) {
String shortKey = "error.noreference.short";
String longKey = "error.noreference.long";
String[] params = new String[] { this.getShortTitle() };
@SuppressWarnings("deprecation")
String translPackage = Util.getPackageName(PFEditController.class);
sd = new StatusDescription(StatusDescription.ERROR, shortKey, longKey, params, translPackage);
sd.setDescriptionForUnit(getIdent());
// set which pane is affected by error
sd.setActivateableViewIdentifier(CONFIG_KEY_PARTICIPANTBOX);
}
return sd;
}
@Override
public TabbableController createEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel,
ICourse course, UserCourseEnvironment euce) {
PFEditController ordnerCtr = new PFEditController(ureq, wControl, this, course, euce);
CourseNode chosenNode = course.getEditorTreeModel().getCourseNode(euce.getCourseEditorEnv().getCurrentCourseNodeId());
return new NodeEditController(ureq, wControl, course.getEditorTreeModel(), course, chosenNode, euce, ordnerCtr);
}
@Override
public NodeRunConstructionResult createNodeRunConstructionResult(UserRequest ureq, WindowControl wControl,
UserCourseEnvironment userCourseEnv, NodeEvaluation ne, String nodecmd) {
PFRunController runController = new PFRunController(ureq, wControl, this, userCourseEnv);
return runController.createNodeRunConstructionResult(ureq);
}
@Override
public Controller createPeekViewRunController(UserRequest ureq, WindowControl wControl,
UserCourseEnvironment userCourseEnv, NodeEvaluation ne) {
VFSContainer rootFolder = null;
CourseEnvironment courseEnv = userCourseEnv.getCourseEnvironment();
Identity identity = userCourseEnv.getIdentityEnvironment().getIdentity();
Path folderRelPath = null;
OlatRootFolderImpl baseContainer = courseEnv.getCourseBaseContainer();
PFManager pfManager = CoreSpringFactory.getImpl(PFManager.class);
if (userCourseEnv.isCoach() || userCourseEnv.isAdmin()) {
folderRelPath = Paths.get(baseContainer.getBasefile().toPath().toString(),
PFManager.FILENAME_PARTICIPANTFOLDER, getIdent());
rootFolder = new LocalFolderImpl(folderRelPath.toFile());
} else if (userCourseEnv.isParticipant()) {
folderRelPath = Paths.get(baseContainer.getBasefile().toPath().toString(),
PFManager.FILENAME_PARTICIPANTFOLDER, getIdent(),
pfManager.getIdFolderName(identity));
rootFolder = new LocalFolderImpl(folderRelPath.toFile());
}
if (rootFolder == null) {
return super.createPeekViewRunController(ureq, wControl, userCourseEnv, ne);
} else {
return new PFPeekviewController(ureq, wControl, rootFolder, getIdent(), 4);
}
}
@Override
public Controller createPreviewController(UserRequest ureq, WindowControl wControl,
UserCourseEnvironment userCourseEnv, NodeEvaluation ne) {
return new PFPreviewController(ureq, wControl, this, userCourseEnv);
}
@Override
public void cleanupOnDelete(ICourse course) {
// mark the subscription to this node as deleted
SubscriptionContext folderSubContext = CourseModule.createTechnicalSubscriptionContext(course.getCourseEnvironment(), this);
NotificationsManager.getInstance().delete(folderSubContext);
// delete filesystem
CourseEnvironment courseEnv = course.getCourseEnvironment();
File root = Paths.get(courseEnv.getCourseBaseContainer().getRelPath(),
PFManager.FILENAME_PARTICIPANTFOLDER, getIdent()).toFile();
if (root.exists()){
FileUtils.deleteDirsAndFiles(root, true, true);
}
}
@Override
public boolean archiveNodeData(Locale locale, ICourse course, ArchiveOptions options, ZipOutputStream exportStream,
String charset) {
CourseEnvironment courseEnv = course.getCourseEnvironment();
Path sourceFolder = Paths.get(courseEnv.getCourseBaseContainer().getBasefile().getAbsolutePath(),
PFManager.FILENAME_PARTICIPANTFOLDER, getIdent());
Translator translator = Util.createPackageTranslator(PFRunController.class, locale);
return FileSystemExport.fsToZip(exportStream, sourceFolder, this, null, translator);
}
@Override
public StatusDescription[] isConfigValid(CourseEditorEnv cev) {
return new StatusDescription[]{StatusDescription.NOERROR};
}
}