diff --git a/src/main/java/org/olat/core/commons/controllers/linkchooser/FileLinkChooserController.java b/src/main/java/org/olat/core/commons/controllers/linkchooser/FileLinkChooserController.java index d3c3ba4abf7f02e0a0ef3319d8e9495255b14b1f..64cf8755bf5eb75d862d3af5a551203f2abd5123 100644 --- a/src/main/java/org/olat/core/commons/controllers/linkchooser/FileLinkChooserController.java +++ b/src/main/java/org/olat/core/commons/controllers/linkchooser/FileLinkChooserController.java @@ -48,6 +48,7 @@ import org.olat.core.util.FileUtils; import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; import org.olat.core.util.vfs.Quota; +import org.olat.core.util.vfs.VFSConstants; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; @@ -127,8 +128,7 @@ public class FileLinkChooserController extends BasicController { VFSItemFilter customFilter = null; VFSItemFilter dirFilter = new VFSItemExcludePrefixFilter(dirFilters); if (suffixes != null) { - VFSItemFileTypeFilter typeFilter = new VFSItemFileTypeFilter( - suffixes); + VFSItemFileTypeFilter typeFilter = new VFSItemFileTypeFilter(suffixes); typeFilter.setCompositeFilter(dirFilter); customFilter = typeFilter; } else { @@ -144,7 +144,7 @@ public class FileLinkChooserController extends BasicController { // convert file endings to mime types as needed by file upload controller Set<String> mimeTypes = null; if (suffixes != null) { - mimeTypes = new HashSet<String>(); + mimeTypes = new HashSet<>(); for (String suffix : suffixes) { String mimeType = WebappHelper.getMimeType("dummy." + suffix); if (mimeType != null) { @@ -152,27 +152,28 @@ public class FileLinkChooserController extends BasicController { } } } - - long remainingSpace = Quota.UNLIMITED; - long uploadLimit = FolderConfig.getLimitULKB(); - if( fileUploadBase.getLocalSecurityCallback() != null && fileUploadBase.getLocalSecurityCallback().getQuota() != null) { - Long space = fileUploadBase.getLocalSecurityCallback().getQuota().getRemainingSpace(); - if(space != null) { - remainingSpace = space.longValue(); - } - Long limit = fileUploadBase.getLocalSecurityCallback().getQuota().getUlLimitKB(); - if(limit != null) { - uploadLimit = limit.longValue(); + + if(fileUploadBase.canWrite() == VFSConstants.YES) { + long remainingSpace = Quota.UNLIMITED; + long uploadLimit = FolderConfig.getLimitULKB(); + if( fileUploadBase.getLocalSecurityCallback() != null && fileUploadBase.getLocalSecurityCallback().getQuota() != null) { + Long space = fileUploadBase.getLocalSecurityCallback().getQuota().getRemainingSpace(); + if(space != null) { + remainingSpace = space.longValue(); + } + Long limit = fileUploadBase.getLocalSecurityCallback().getQuota().getUlLimitKB(); + if(limit != null) { + uploadLimit = limit.longValue(); + } } + + uploadCtr = new FileUploadController(wControl, fileUploadBase, ureq, uploadLimit, remainingSpace, mimeTypes, + true, false, true, true, false); + listenTo(uploadCtr); + // set specific upload path + uploadCtr.setUploadRelPath(uploadRelPath); + mainVC.put("uploader", uploadCtr.getInitialComponent()); } - uploadCtr = new FileUploadController(wControl, fileUploadBase, ureq, uploadLimit, remainingSpace, mimeTypes, - true, false, true, true, false); - - listenTo(uploadCtr); - // set specific upload path - uploadCtr.setUploadRelPath(uploadRelPath); - - mainVC.put("uploader", uploadCtr.getInitialComponent()); putInitialPanel(mainVC); } @@ -264,7 +265,7 @@ public class FileLinkChooserController extends BasicController { // no defined suffixes => all allowed return true; } else { - // check if siffix one of allowed suffixes + // check if suffix one of allowed suffixes String suffix = getSuffix(filename); for (String allowedSuffix : suffixes) { if (allowedSuffix.equals(suffix)) { @@ -282,12 +283,9 @@ public class FileLinkChooserController extends BasicController { allowedSuffixes.append(allowedSuffix); } String suffix = getSuffix(fileName); - getWindowControl().setError( - getTranslator() - .translate( - "upload.error.incorrect.filetype", - new String[] { "." + suffix, - allowedSuffixes.toString() })); + getWindowControl().setError(getTranslator() + .translate("upload.error.incorrect.filetype", + new String[] { "." + suffix,allowedSuffixes.toString() })); } private String getSuffix(String filename) { diff --git a/src/main/java/org/olat/core/commons/controllers/linkchooser/_content/filechooser.html b/src/main/java/org/olat/core/commons/controllers/linkchooser/_content/filechooser.html index dc7781de0908228465b6d9519465190c4a952a07..55dbaf00c04a483aaa8e3890dcc6b8cc799c3fd5 100644 --- a/src/main/java/org/olat/core/commons/controllers/linkchooser/_content/filechooser.html +++ b/src/main/java/org/olat/core/commons/controllers/linkchooser/_content/filechooser.html @@ -1,12 +1,16 @@ <div id="o_fc_select" class="clearfix" > - <a href="#o_top" class="btn btn-default pull-right" onclick="jQuery('#o_fc_select').fadeOut(300, function(){ jQuery('#o_fc_upload').fadeIn(300); });"> - <span>$r.translate("filechooser.upload.title")</span></a> - <h3>$r.translate("filechooser.select.title")</h3> + #if($r.available("uploader")) + <a href="#o_top" class="btn btn-default pull-right" onclick="jQuery('#o_fc_select').fadeOut(300, function(){ jQuery('#o_fc_upload').fadeIn(300); });"> + <span>$r.translate("filechooser.upload.title")</span></a> + <h3>$r.translate("filechooser.select.title")</h3> + #end $r.render("stTree") </div> +#if($r.available("uploader")) <div id="o_fc_upload" class="clearfix" style="display: none"> <a href="#o_top" class="btn btn-default pull-right" onclick="jQuery('#o_fc_upload').fadeOut(300, function() { jQuery('#o_fc_select').fadeIn(300); });"> <span>$r.translate("filechooser.select.title")</span></a> <h3>$r.translate("filechooser.upload.title")</h3> $r.render("uploader") -</div> \ No newline at end of file +</div> +#end \ No newline at end of file diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java b/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java index 8cc58b77b91c756cae58f2baecf8d338d2e2e69d..e44be4aef6e4c0b0d30aa0bff805b6c34f6a7331 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java +++ b/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java @@ -364,11 +364,11 @@ public class FileCopyController extends LinkChooserController { String description = translate("ul.tooManyRevisions.description", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())}); removeAsListenerAndDispose(revisionListCtr); - revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, title, description, false); + revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, null, description, false); listenTo(revisionListCtr); removeAsListenerAndDispose(revisionListDialogBox); - revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent()); + revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent(), true, title); listenTo(revisionListDialogBox); revisionListDialogBox.activate(); diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileSelection.java b/src/main/java/org/olat/core/commons/modules/bc/FileSelection.java index 604a4c6c8313b17d8fa1923f920671a111f4fdc0..88f5aec34f12b43f1791b5045b9bbf6aabaa5f23 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/FileSelection.java +++ b/src/main/java/org/olat/core/commons/modules/bc/FileSelection.java @@ -28,11 +28,11 @@ package org.olat.core.commons.modules.bc; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import org.olat.core.gui.UserRequest; import org.olat.core.util.FileUtils; +import org.olat.core.util.StringHelper; public class FileSelection { @@ -86,12 +86,12 @@ public class FileSelection { * @return HTML Fragment. */ public String renderAsHtml() { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(255); sb.append("<ul>"); - for (Iterator<String> iter = files.iterator(); iter.hasNext();) { - sb.append("<li>"); - sb.append(currentContainerRelPath + "/" + iter.next()); - sb.append("</li>"); + for (String filename:files) { + sb.append("<li>") + .append(currentContainerRelPath).append("/").append(StringHelper.escapeHtml(filename)) + .append("</li>"); } sb.append("</ul>"); return sb.toString(); diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java index 0a361a0dd2c5df13749420b7505f9c33e3eb7e1b..7597003e4e80ef71b629495084949777f45a0bd5 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java +++ b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java @@ -30,14 +30,12 @@ import static java.util.Arrays.asList; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Set; import java.util.regex.Pattern; -import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.commands.FolderCommandStatus; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.MetaInfoFactory; @@ -47,6 +45,7 @@ import org.olat.core.commons.modules.bc.version.VersionCommentController; import org.olat.core.commons.modules.bc.vfs.OlatRootFileImpl; import org.olat.core.commons.services.image.ImageService; 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.FileElement; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; @@ -54,6 +53,7 @@ import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; @@ -78,6 +78,7 @@ import org.olat.core.util.vfs.VFSLockManager; import org.olat.core.util.vfs.VFSManager; import org.olat.core.util.vfs.version.Versionable; import org.olat.core.util.vfs.version.Versions; +import org.springframework.beans.factory.annotation.Autowired; /** * <h3>Description</h3> @@ -113,12 +114,11 @@ public class FileUploadController extends FormBasicController { private VersionCommentController unlockCtr; private DialogBoxController overwriteDialog; private DialogBoxController lockedFileDialog; - private VFSLeaf newFile = null; - private VFSItem existingVFSItem = null; + private VFSLeaf newFile; + private VFSItem existingVFSItem; private long uploadLimitKB; private long remainingQuotKB; private Set<String> mimeTypes; - private FilesInfoMBean fileInfoMBean; // // Form elements private FileElement fileEl; @@ -139,9 +139,15 @@ public class FileUploadController extends FormBasicController { private static Pattern imageExtPattern = Pattern.compile("\\b.(jpg|jpeg|png)\\b"); private static final Pattern validSubPathPattern = Pattern.compile("[\\p{Alnum}-_\\./]*"); - - private final VFSLockManager vfsLockManager; + @Autowired + private ImageService imageHelper; + @Autowired + private FilesInfoMBean fileInfoMBean; + @Autowired + private VFSLockManager vfsLockManager; + @Autowired + private MetaInfoFactory metaInfoFactory; private String subfolderPath; private TextElement targetSubPath ; @@ -176,17 +182,13 @@ public class FileUploadController extends FormBasicController { public FileUploadController(WindowControl wControl, VFSContainer curContainer, UserRequest ureq, long upLimitKB, long remainingQuotKB, Set<String> mimeTypesRestriction, boolean showTargetPath, boolean showMetadata, boolean resizeImg, boolean showCancel, boolean showTitle, String subfolderPath) { super(ureq, wControl, "file_upload"); - vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class); setVariables(curContainer, upLimitKB, remainingQuotKB, mimeTypesRestriction, showTargetPath, showMetadata, resizeImg, showCancel, showTitle, subfolderPath); initForm(ureq); } - - private void setVariables(VFSContainer curContainer, long upLimitKB, long remainingQuotKB, Set<String> mimeTypesRestriction, boolean showTargetPath, boolean showMetadata, boolean resizeImg, boolean showCancel, boolean showTitle, String subfolderPath) { this.currentContainer = curContainer; - this.fileInfoMBean = (FilesInfoMBean) CoreSpringFactory.getBean(FilesInfoMBean.class.getCanonicalName()); this.mimeTypes = mimeTypesRestriction; this.showTitle = showTitle; this.showTargetPath = showTargetPath; @@ -239,8 +241,8 @@ public class FileUploadController extends FormBasicController { } } - fileEl = uifactory.addFileElement(getWindowControl(), "fileEl", "ul.file", fileUpload); + fileEl.addActionListener(FormEvent.ONCHANGE); setMaxUploadSizeKB((uploadLimitKB < remainingQuotKB ? uploadLimitKB : remainingQuotKB)); fileEl.setMandatory(true, "NoFileChoosen"); @@ -296,161 +298,35 @@ public class FileUploadController extends FormBasicController { } @Override - protected void formOK(UserRequest ureq) { - if(targetSubPath != null) setUploadRelPath(targetSubPath.getValue()); - if ( fileEl.isUploadSuccess()) { - // check for available space - if (remainingQuotKB != -1) { - if (fileEl.getUploadFile().length() / 1024 > remainingQuotKB) { - fileEl.setErrorKey("QuotaExceeded", null); - fileEl.getUploadFile().delete(); - return; - } - } - String fileName = fileEl.getUploadFileName(); - - File uploadedFile = fileEl.getUploadFile(); - if(resizeImg && fileName != null && imageExtPattern.matcher(fileName.toLowerCase()).find() - && resizeEl.isSelected(0)) { - String extension = FileUtils.getFileSuffix(fileName); - File imageScaled = new File(uploadedFile.getParentFile(), "scaled_" + uploadedFile.getName() + "." + extension); - ImageService imageHelper = CoreSpringFactory.getImpl(ImageService.class); - if(imageHelper.scaleImage(uploadedFile, extension, imageScaled, 1280, 1280, false) != null) { - //problem happen, special GIF's (see bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6358674) - //don't try to scale if not all ok - uploadedFile = imageScaled; - } - } - - // check if such a filename does already exist - existingVFSItem = uploadVFSContainer.resolve(fileName); - if (existingVFSItem == null) { - // save file and finish - newFile = uploadVFSContainer.createChildLeaf(fileName); - - boolean success = true; - if(newFile == null) { - // FXOLAT-409 somehow "createChildLeaf" did not succeed... - // if so, there is alread a error-msg in log (vfsContainer.createChildLeaf) - success = false; - } else { - try(InputStream in = new FileInputStream(uploadedFile); - OutputStream out = newFile.getOutputStream(false)) { - FileUtils.bcopy(in, out, "uploadTmpFileToDestFile"); - uploadedFile.delete(); - } catch (IOException e) { - success = false; - } - } - - if (success) { - String filePath = (uploadRelPath == null ? "" : uploadRelPath + "/") + newFile.getName(); - finishSuccessfullUpload(filePath, newFile, ureq); - fileInfoMBean.logUpload(newFile.getSize()); - fireEvent(ureq, Event.DONE_EVENT); - } else { - showError("failed"); - status = FolderCommandStatus.STATUS_FAILED; - fireEvent(ureq, Event.FAILED_EVENT); - } - } else { - // file already exists... upload anyway with new filename and - // in the folder manager status. - // rename file and ask user what to do - if ( ! (existingVFSItem instanceof LocalImpl)) { - throw new AssertException("Can only LocalImpl VFS items, don't know what to do with file of type::" + existingVFSItem.getClass().getCanonicalName()); - } - - String renamedFilename = VFSManager.rename(uploadVFSContainer, existingVFSItem.getName()); - newFile = uploadVFSContainer.createChildLeaf(renamedFilename); - - // Copy content to tmp file - InputStream in = null; - BufferedOutputStream out = null; - boolean success = false; - try { - in = new FileInputStream(uploadedFile); - out = new BufferedOutputStream(newFile.getOutputStream(false)); - if (in != null) { - success = FileUtils.copy(in, out); + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(fileEl == source) { + if(metaDataCtr != null) { + String filename = fileEl.getUploadFileName(); + if(!FileUtils.validateFilename(filename)) { + String suffix = FileUtils.getFileSuffix(filename); + if(suffix != null && suffix.length() > 0) { + filename = filename.substring(0, filename.length() - suffix.length() - 1); } - uploadedFile.delete(); - } catch (FileNotFoundException e) { - success = false; - } finally { - FileUtils.closeSafely(in); - FileUtils.closeSafely(out); - } - - if (success) { - boolean locked = vfsLockManager.isLockedForMe(existingVFSItem, getIdentity(), ureq.getUserSession().getRoles()); - if (locked) { - //the file is locked and cannot be overwritten - removeAsListenerAndDispose(lockedFileDialog); - lockedFileDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.lockedFile.title"), translate("ul.lockedFile.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); - listenTo(lockedFileDialog); - - lockedFileDialog.activate(); - } - else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { - Versionable versionable = (Versionable)existingVFSItem; - Versions versions = versionable.getVersions(); - String relPath = null; - if(existingVFSItem instanceof OlatRootFileImpl) { - relPath = ((OlatRootFileImpl)existingVFSItem).getRelPath(); - } - int maxNumOfRevisions = FolderConfig.versionsAllowed(relPath); - if(maxNumOfRevisions == 0) { - //it's possible if someone change the configuration - // let calling method decide what to do. - removeAsListenerAndDispose(overwriteDialog); - overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.overwrite.threeoptions.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.overwrite"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); - listenTo(overwriteDialog); - - overwriteDialog.activate(); - - } else if(versions.getRevisions().isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) { - // let calling method decide what to do. - removeAsListenerAndDispose(overwriteDialog); - overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.versionoroverwrite", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.newVersion"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); - listenTo(overwriteDialog); - - overwriteDialog.activate(); - - } else { - - String title = translate("ul.tooManyRevisions.title", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())}); - String description = translate("ul.tooManyRevisions.description", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())}); - - removeAsListenerAndDispose(revisionListCtr); - revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, title, description, false); - listenTo(revisionListCtr); - - removeAsListenerAndDispose(revisionListDialogBox); - revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent()); - listenTo(revisionListDialogBox); - - revisionListDialogBox.activate(); - } - } else { - // let calling method decide what to do. - // for this, we put a list with "existing name" and "new name" - overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.overwrite.threeoptions.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.overwrite"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); - listenTo(overwriteDialog); - overwriteDialog.activate(); - } - } else { - showError("failed"); - status = FolderCommandStatus.STATUS_FAILED; - fireEvent(ureq, Event.FAILED_EVENT); + filename = FileUtils.normalizeFilename(filename) + "." + suffix; + metaDataCtr.getFilenameEl().setExampleKey("mf.filename.warning", null); } + metaDataCtr.setFilename(filename); } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void formOK(UserRequest ureq) { + if(targetSubPath != null) setUploadRelPath(targetSubPath.getValue()); + if ( fileEl.isUploadSuccess()) { + doUpload(ureq); } else { if (mainForm.getLastRequestError() == Form.REQUEST_ERROR_GENERAL ) { showError("failed"); } else if (mainForm.getLastRequestError() == Form.REQUEST_ERROR_FILE_EMPTY ) { showError("failed"); - }else if (mainForm.getLastRequestError() == Form.REQUEST_ERROR_UPLOAD_LIMIT_EXCEEDED) { + } else if (mainForm.getLastRequestError() == Form.REQUEST_ERROR_UPLOAD_LIMIT_EXCEEDED) { showError("QuotaExceeded"); } status = FolderCommandStatus.STATUS_FAILED; @@ -473,120 +349,35 @@ public class FileUploadController extends FormBasicController { @Override public void event(UserRequest ureq, Controller source, Event event) { if (source == overwriteDialog) { - if (event instanceof ButtonClickedEvent) { ButtonClickedEvent buttonClickedEvent = (ButtonClickedEvent) event; if (buttonClickedEvent.getPosition() == 0) { //ok - if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { - //new version - String relPath = null; - if(existingVFSItem instanceof OlatRootFileImpl) { - relPath = ((OlatRootFileImpl)existingVFSItem).getRelPath(); - } - int maxNumOfRevisions = FolderConfig.versionsAllowed(relPath); - if(maxNumOfRevisions == 0) { - //someone play with the configuration - // Overwrite... - String fileName = existingVFSItem.getName(); - existingVFSItem.delete(); - newFile.rename(fileName); - - // ... and notify listeners. - finishUpload(ureq); - } else { - removeAsListenerAndDispose(commentVersionCtr); - removeAsListenerAndDispose(commentVersionDialogBox); - - boolean locked = vfsLockManager.isLocked(existingVFSItem); - commentVersionCtr = new VersionCommentController(ureq, getWindowControl(), locked, true); - listenTo(commentVersionCtr); - commentVersionDialogBox = new CloseableModalController(getWindowControl(), translate("save"), commentVersionCtr.getInitialComponent()); - listenTo(commentVersionDialogBox); - commentVersionDialogBox.activate(); - } - } else { - //if the file is locked, ask for unlocking it - if(vfsLockManager.isLocked(existingVFSItem)) { - removeAsListenerAndDispose(unlockCtr); - unlockCtr = new VersionCommentController(ureq,getWindowControl(), true, false); - listenTo(unlockCtr); - - removeAsListenerAndDispose(unlockDialogBox); - unlockDialogBox = new CloseableModalController(getWindowControl(), translate("ok"), unlockCtr.getInitialComponent()); - listenTo(unlockDialogBox); - - unlockDialogBox.activate(); - - } else { - // Overwrite... - String fileName = existingVFSItem.getName(); - existingVFSItem.delete(); - newFile.rename(fileName); - - // ... and notify listeners. - finishUpload(ureq); - } - } + doFinishOverwrite(ureq); } else if (buttonClickedEvent.getPosition() == 1) { //not ok // Upload renamed. Since we've already uploaded the file with a changed name, don't do anything much here... - this.fileOverwritten = true; - + fileOverwritten = true; // ... and notify listeners. finishUpload(ureq); } else if (buttonClickedEvent.getPosition() == 2) { // cancel // Cancel. Remove the new file since it has already been uploaded. Note that we don't have to explicitly close the // dialog box since it closes itself whenever something gets clicked. - newFile.deleteSilently(); - } else { - throw new RuntimeException("Unknown button number " + buttonClickedEvent.getPosition()); + doCancel(ureq); } } } else if (source == lockedFileDialog) { - if (event instanceof ButtonClickedEvent) { ButtonClickedEvent buttonClickedEvent = (ButtonClickedEvent) event; - switch(buttonClickedEvent.getPosition()) { - case 0: { - //upload the file with a new name - this.fileOverwritten = true; - // ... and notify listeners. - finishUpload(ureq); - break; - } - case 1: {//cancel - newFile.deleteSilently(); - fireEvent(ureq, Event.CANCELLED_EVENT); - break; - } - default: - throw new RuntimeException("Unknown button number " + buttonClickedEvent.getPosition()); + if(buttonClickedEvent.getPosition() == 0) { + //upload the file with a new name + fileOverwritten = true; + // ... and notify listeners. + finishUpload(ureq); + } else if(buttonClickedEvent.getPosition() == 1) { + doCancel(ureq); } } } else if (source == commentVersionCtr) { - String comment = commentVersionCtr.getComment(); - - Roles roles = ureq.getUserSession().getRoles(); - boolean locked = vfsLockManager.isLocked(existingVFSItem); - if(locked && !commentVersionCtr.keepLocked()) { - vfsLockManager.unlock(existingVFSItem, getIdentity(), roles); - } - - commentVersionDialogBox.deactivate(); - if(revisionListDialogBox != null) { - revisionListDialogBox.deactivate(); - } - - //ok, new version of the file - Versionable existingVersionableItem = (Versionable)existingVFSItem; - boolean ok = existingVersionableItem.getVersions().addVersion(ureq.getIdentity(), comment, newFile.getInputStream()); - if(ok) { - newFile.deleteSilently(); - //what can i do if existingVFSItem is a container - if(existingVFSItem instanceof VFSLeaf) { - newFile = (VFSLeaf)existingVFSItem; - } - } - finishUpload(ureq); + doFinishComment(ureq); } else if (source == unlockCtr) { // Overwrite... String fileName = existingVFSItem.getName(); @@ -597,7 +388,6 @@ public class FileUploadController extends FormBasicController { existingVFSItem.delete(); newFile.rename(fileName); - // ... and notify listeners. finishUpload(ureq); @@ -606,61 +396,304 @@ public class FileUploadController extends FormBasicController { revisionListCtr = null; removeAsListenerAndDispose(revisionListDialogBox); revisionListDialogBox = null; - - //remove the file - newFile.deleteSilently(); + doCancel(ureq); } else if (source == revisionListCtr) { + revisionListDialogBox.deactivate(); + removeAsListenerAndDispose(revisionListDialogBox); + revisionListDialogBox = null; + if(FolderCommandStatus.STATUS_CANCELED == revisionListCtr.getStatus()) { - - revisionListDialogBox.deactivate(); - removeAsListenerAndDispose(revisionListDialogBox); - revisionListDialogBox = null; - //don't want to delete revisions, clean the temporary file - if(newFile != null) { - newFile.deleteSilently(); - } + doCancel(ureq); + } else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { + doFinishRevisionList(ureq); + } + } + } + + /** + * Delete the uploaded file and send cancel event + * @param ureq + */ + private void doCancel(UserRequest ureq) { + if(newFile != null) { + newFile.deleteSilently(); + } + fireEvent(ureq, Event.CANCELLED_EVENT); + } + + private void doFinishOverwrite(UserRequest ureq) { + if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { + //new version + int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem(); + if(maxNumOfRevisions == 0) { + //someone play with the configuration + // Overwrite... + String fileName = existingVFSItem.getName(); + existingVFSItem.delete(); + newFile.rename(fileName); + + // ... and notify listeners. + finishUpload(ureq); } else { - if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { - - revisionListDialogBox.deactivate(); - removeAsListenerAndDispose(revisionListDialogBox); - revisionListDialogBox = null; - - if(existingVFSItem.getParentContainer() != null) { - existingVFSItem = existingVFSItem.getParentContainer().resolve(existingVFSItem.getName()); - } - - Versionable versionable = (Versionable)existingVFSItem; - Versions versions = versionable.getVersions(); - int maxNumOfRevisions = FolderConfig.versionsAllowed(null); - if(maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) { - removeAsListenerAndDispose(commentVersionCtr); - removeAsListenerAndDispose(commentVersionDialogBox); + askForComment(ureq); + } + } else { + //if the file is locked, ask for unlocking it + if(vfsLockManager.isLocked(existingVFSItem)) { + askForUnlock(ureq); + + } else { + // Overwrite... + String fileName = existingVFSItem.getName(); + existingVFSItem.delete(); + newFile.rename(fileName); + + // ... and notify listeners. + finishUpload(ureq); + } + } + } + + private void doFinishComment(UserRequest ureq) { + String comment = commentVersionCtr.getComment(); + + Roles roles = ureq.getUserSession().getRoles(); + boolean locked = vfsLockManager.isLocked(existingVFSItem); + if(locked && !commentVersionCtr.keepLocked()) { + vfsLockManager.unlock(existingVFSItem, getIdentity(), roles); + } + + commentVersionDialogBox.deactivate(); + if(revisionListDialogBox != null) { + revisionListDialogBox.deactivate(); + } + + //ok, new version of the file + Versionable existingVersionableItem = (Versionable)existingVFSItem; + boolean ok = existingVersionableItem.getVersions().addVersion(ureq.getIdentity(), comment, newFile.getInputStream()); + if(ok) { + newFile.deleteSilently(); + //what can i do if existingVFSItem is a container + if(existingVFSItem instanceof VFSLeaf) { + newFile = (VFSLeaf)existingVFSItem; + } + } + finishUpload(ureq); + } + + private void doFinishRevisionList(UserRequest ureq) { + if(existingVFSItem.getParentContainer() != null) { + existingVFSItem = existingVFSItem.getParentContainer().resolve(existingVFSItem.getName()); + } + + Versionable versionable = (Versionable)existingVFSItem; + Versions versions = versionable.getVersions(); + int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem(); + if(maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) { + askForComment(ureq); + } else { + askToReduceRevisionList(ureq, versionable); + } + } + + private int getMaxNumOfRevisionsOfExistingVFSItem() { + String relPath = null; + if(existingVFSItem instanceof OlatRootFileImpl) { + relPath = ((OlatRootFileImpl)existingVFSItem).getRelPath(); + } + return FolderConfig.versionsAllowed(relPath); + } + + private void askToReduceRevisionList(UserRequest ureq, Versionable versionable) { + removeAsListenerAndDispose(revisionListCtr); + removeAsListenerAndDispose(revisionListDialogBox); + + Versions versions = versionable.getVersions(); + int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem(); + String[] params = new String[]{ Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size()) }; + String title = translate("ul.tooManyRevisions.title", params); + String description = translate("ul.tooManyRevisions.description", params); + + revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, null, description, false); + listenTo(revisionListCtr); + + revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent(), true, title); + listenTo(revisionListDialogBox); + revisionListDialogBox.activate(); + } + + private void askForUnlock(UserRequest ureq) { + removeAsListenerAndDispose(unlockCtr); + removeAsListenerAndDispose(unlockDialogBox); + + unlockCtr = new VersionCommentController(ureq,getWindowControl(), true, false); + listenTo(unlockCtr); + String title = unlockCtr.getAndRemoveFormTitle(); + unlockDialogBox = new CloseableModalController(getWindowControl(), translate("ok"), unlockCtr.getInitialComponent(), true, title); + listenTo(unlockDialogBox); + unlockDialogBox.activate(); + } + + private void askForComment(UserRequest ureq) { + removeAsListenerAndDispose(commentVersionCtr); + removeAsListenerAndDispose(commentVersionDialogBox); + + boolean locked = vfsLockManager.isLocked(existingVFSItem); + commentVersionCtr = new VersionCommentController(ureq, getWindowControl(), locked, true); + listenTo(commentVersionCtr); + String title = commentVersionCtr.getAndRemoveFormTitle(); + commentVersionDialogBox = new CloseableModalController(getWindowControl(), translate("save"), commentVersionCtr.getInitialComponent(), true, title); + listenTo(commentVersionDialogBox); + commentVersionDialogBox.activate(); + } + + private void doUpload(UserRequest ureq) { + // check for available space + if (remainingQuotKB != -1 && (fileEl.getUploadFile().length() / 1024 > remainingQuotKB)) { + fileEl.setErrorKey("QuotaExceeded", null); + fileEl.getUploadFile().delete(); + return; + } + + String fileName = fileEl.getUploadFileName(); + if(metaDataCtr != null && StringHelper.containsNonWhitespace(metaDataCtr.getFilename())) { + fileName = metaDataCtr.getFilename(); + } + + File uploadedFile = fileEl.getUploadFile(); + if(resizeImg && fileName != null && imageExtPattern.matcher(fileName.toLowerCase()).find() + && resizeEl.isSelected(0)) { + String extension = FileUtils.getFileSuffix(fileName); + File imageScaled = new File(uploadedFile.getParentFile(), "scaled_" + uploadedFile.getName() + "." + extension); + if(imageHelper.scaleImage(uploadedFile, extension, imageScaled, 1280, 1280, false) != null) { + //problem happen, special GIF's (see bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6358674) + //don't try to scale if not all ok + uploadedFile = imageScaled; + } + } + + // check if such a filename does already exist + existingVFSItem = uploadVFSContainer.resolve(fileName); + if (existingVFSItem == null) { + uploadNewFile(ureq, uploadedFile, fileName); + } else { + // file already exists... upload anyway with new filename and + // in the folder manager status. + // rename file and ask user what to do + if ( ! (existingVFSItem instanceof LocalImpl)) { + throw new AssertException("Can only LocalImpl VFS items, don't know what to do with file of type::" + existingVFSItem.getClass().getCanonicalName()); + } - boolean locked = vfsLockManager.isLocked(existingVFSItem); - commentVersionCtr = new VersionCommentController(ureq,getWindowControl(), locked, true); - listenTo(commentVersionCtr); - commentVersionDialogBox = new CloseableModalController(getWindowControl(), translate("save"), commentVersionCtr.getInitialComponent()); - listenTo(commentVersionDialogBox); - commentVersionDialogBox.activate(); - } else { - - removeAsListenerAndDispose(revisionListCtr); - revisionListCtr = new RevisionListController(ureq,getWindowControl(),versionable, false); - listenTo(revisionListCtr); - - removeAsListenerAndDispose(revisionListDialogBox); - revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent()); - listenTo(revisionListDialogBox); - - revisionListDialogBox.activate(); - } + String renamedFilename = VFSManager.rename(uploadVFSContainer, existingVFSItem.getName()); + newFile = uploadVFSContainer.createChildLeaf(renamedFilename); + + // Copy content to tmp file + boolean success = false; + try(InputStream in = new FileInputStream(uploadedFile); + BufferedOutputStream out = new BufferedOutputStream(newFile.getOutputStream(false))) { + success = FileUtils.copy(in, out); + uploadedFile.delete(); + } catch (IOException e) { + success = false; + } + + if (success) { + boolean locked = vfsLockManager.isLockedForMe(existingVFSItem, getIdentity(), ureq.getUserSession().getRoles()); + if (locked) { + //the file is locked and cannot be overwritten + lockedFileDialog(ureq, renamedFilename); + } else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { + uploadVersionedFile(ureq, renamedFilename); + } else { + askOverwriteOrRename(ureq, renamedFilename); } + } else { + showError("failed"); + status = FolderCommandStatus.STATUS_FAILED; + fireEvent(ureq, Event.FAILED_EVENT); } } } + private void lockedFileDialog(UserRequest ureq, String renamedFilename) { + removeAsListenerAndDispose(lockedFileDialog); + String title = translate("ul.lockedFile.title"); + String text = translate("ul.lockedFile.text", new String[] { existingVFSItem.getName(), renamedFilename} ); + lockedFileDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), title, text, + asList(translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); + listenTo(lockedFileDialog); + lockedFileDialog.activate(); + } + + private void uploadVersionedFile(UserRequest ureq, String renamedFilename) { + Versionable versionable = (Versionable)existingVFSItem; + Versions versions = versionable.getVersions(); + int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem(); + if(maxNumOfRevisions == 0) { + //it's possible if someone change the configuration + // let calling method decide what to do. + askOverwriteOrRename(ureq, renamedFilename); + } else if(versions.getRevisions().isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) { + // let calling method decide what to do. + askNewVersionOrRename(ureq, renamedFilename); + } else { + //too many revisions + askToReduceRevisionList(ureq, versionable); + } + } + + private void askOverwriteOrRename(UserRequest ureq, String renamedFilename) { + removeAsListenerAndDispose(overwriteDialog); + // let calling method decide what to do. + // for this, we put a list with "existing name" and "new name" + overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), + translate("ul.overwrite.threeoptions.title"), translate("ul.overwrite.threeoptions.text", new String[] {existingVFSItem.getName(), renamedFilename} ), + asList(translate("ul.overwrite.threeoptions.overwrite"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); + listenTo(overwriteDialog); + overwriteDialog.activate(); + } + + private void askNewVersionOrRename(UserRequest ureq, String renamedFilename) { + removeAsListenerAndDispose(overwriteDialog); + overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), + translate("ul.overwrite.threeoptions.title"), translate("ul.versionoroverwrite", new String[] {existingVFSItem.getName(), renamedFilename} ), + asList(translate("ul.overwrite.threeoptions.newVersion"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); + listenTo(overwriteDialog); + overwriteDialog.activate(); + } + + private void uploadNewFile(UserRequest ureq, File uploadedFile, String filename) { + // save file and finish + newFile = uploadVFSContainer.createChildLeaf(filename); + + boolean success = true; + if(newFile == null) { + // FXOLAT-409 somehow "createChildLeaf" did not succeed... + // if so, there is alread a error-msg in log (vfsContainer.createChildLeaf) + success = false; + } else { + try(InputStream in = new FileInputStream(uploadedFile); + OutputStream out = newFile.getOutputStream(false)) { + FileUtils.bcopy(in, out, "uploadTmpFileToDestFile"); + uploadedFile.delete(); + } catch (IOException e) { + success = false; + } + } + + if (success) { + String filePath = (uploadRelPath == null ? "" : uploadRelPath + "/") + newFile.getName(); + finishSuccessfullUpload(filePath, newFile, ureq); + fileInfoMBean.logUpload(newFile.getSize()); + fireEvent(ureq, Event.DONE_EVENT); + } else { + showError("failed"); + status = FolderCommandStatus.STATUS_FAILED; + fireEvent(ureq, Event.FAILED_EVENT); + } + } + private void finishUpload(UserRequest ureq) { // in both cases the upload must be finished and notified with a FolderEvent String filePath = (uploadRelPath == null ? "" : uploadRelPath + "/") + newFile.getName(); @@ -681,11 +714,11 @@ public class FileUploadController extends FormBasicController { if (item instanceof OlatRootFileImpl) { OlatRootFileImpl relPathItem = (OlatRootFileImpl) item; // create meta data - MetaInfo meta = CoreSpringFactory.getImpl(MetaInfoFactory.class).createMetaInfoFor(relPathItem); + MetaInfo meta = metaInfoFactory.createMetaInfoFor(relPathItem); if (metaDataCtr != null) { meta = metaDataCtr.getMetaInfo(meta); } - meta.setAuthor(ureq.getIdentity()); + meta.setAuthor(getIdentity()); meta.clearThumbnails();//if overwrite an older file meta.write(); } @@ -836,27 +869,37 @@ public class FileUploadController extends FormBasicController { targetSubPath.clearError(); } } - // Check file name - String fileName = fileEl.getUploadFileName(); - if (!StringHelper.containsNonWhitespace(fileName)) { - fileEl.setErrorKey("NoFileChosen", null); - return false; + if(metaDataCtr != null && StringHelper.containsNonWhitespace(metaDataCtr.getFilename())) { + return validateFilename(metaDataCtr.getFilename(), metaDataCtr.getFilenameEl()); + } + String filename = fileEl.getUploadFileName(); + return validateFilename(filename, fileEl); + } + + private boolean validateFilename(String filename, FormItem itemEl) { + itemEl.clearError(); + + + boolean allOk = true; + if (!StringHelper.containsNonWhitespace(filename)) { + itemEl.setErrorKey("NoFileChosen", null); + allOk &= false; } - boolean isFilenameValid = FileUtils.validateFilename(fileName); + boolean isFilenameValid = FileUtils.validateFilename(filename); if(!isFilenameValid) { - fileEl.setErrorKey("cfile.name.notvalid", null); - return false; + itemEl.setErrorKey("cfile.name.notvalid", null); + allOk &= false; } if (remainingQuotKB != -1 && fileEl.getUploadFile().length() / 1024 > remainingQuotKB) { - fileEl.clearError(); String supportAddr = WebappHelper.getMailConfig("mailQuota"); getWindowControl().setError(translate("ULLimitExceeded", new String[] { Formatter.roundToString((uploadLimitKB+0f) / 1000, 1), supportAddr })); - return false; + allOk &= false; } - return true; + + return allOk; } } diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUpload.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUpload.java index b782e332be93468a63a0d0f7dbfb8925ff4228e2..f8d16350649da824299dff2b3c93c09756b33736 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUpload.java +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUpload.java @@ -75,7 +75,7 @@ public class CmdUpload extends BasicController implements FolderCommand { private String uploadFileName; private VFSLeaf vfsNewFile; private long quotaKB; - private int uploadLimitKB; + private long uploadLimitKB; private boolean overwritten = false; private FileUploadController fileUploadCtr; private boolean cancelResetsForm; @@ -93,13 +93,14 @@ public class CmdUpload extends BasicController implements FolderCommand { this.showMetadata = showMetadata; } + @Override public Controller execute(FolderComponent fc, UserRequest ureq, WindowControl windowControl, Translator trans) { return execute(fc, ureq, trans, false); } - public Controller execute(FolderComponent fc, UserRequest ureq, Translator trans, boolean cancelResetsForm) { + public Controller execute(FolderComponent fc, UserRequest ureq, Translator trans, boolean cancelResetsButton) { this.folderComponent = fc; - this.cancelResetsForm = cancelResetsForm; + this.cancelResetsForm = cancelResetsButton; setTranslator(trans); currentContainer = folderComponent.getCurrentContainer(); @@ -130,21 +131,25 @@ public class CmdUpload extends BasicController implements FolderCommand { } } // set wether we have a quota on this folder - if (quotaKB == Quota.UNLIMITED) ubar.setIsNoMax(true); - else ubar.setMax(quotaKB / 1024); + if (quotaKB == Quota.UNLIMITED) { + ubar.setIsNoMax(true); + } else { + ubar.setMax(quotaKB / 1024); + } // set default ulLimit if none is defined... - if (uploadLimitKB == Quota.UNLIMITED) - uploadLimitKB = (int) QuotaManager.getInstance().getDefaultQuotaDependingOnRole(ureq.getIdentity()).getUlLimitKB().longValue(); + if (uploadLimitKB == Quota.UNLIMITED) { + uploadLimitKB = QuotaManager.getInstance().getDefaultQuotaDependingOnRole(ureq.getIdentity()).getUlLimitKB().longValue(); + } // Add file upload form - int remainingQuotaKB = (int) quotaKB - (int) actualUsage; - if (quotaKB == Quota.UNLIMITED) remainingQuotaKB = (int) quotaKB; + long remainingQuotaKB = quotaKB - actualUsage; + if (quotaKB == Quota.UNLIMITED) remainingQuotaKB = quotaKB; else if (quotaKB - actualUsage < 0) remainingQuotaKB = 0; - else remainingQuotaKB = (int) quotaKB - (int) actualUsage; + else remainingQuotaKB = quotaKB - actualUsage; + removeAsListenerAndDispose(fileUploadCtr); - fileUploadCtr = new FileUploadController(getWindowControl(), currentContainer, ureq, uploadLimitKB, remainingQuotaKB, null, - true, showMetadata, true, showCancel, true); + true, showMetadata, true, showCancel, false); listenTo(fileUploadCtr); mainVC.put("fileUploadCtr", fileUploadCtr.getInitialComponent()); mainVC.contextPut("showFieldset", Boolean.TRUE); @@ -201,7 +206,7 @@ public class CmdUpload extends BasicController implements FolderCommand { @Override public String getModalTitle() { - return translate("ul.quote"); + return translate("ul"); } public void event(UserRequest ureq, Component source, Event event) { diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/MetaInfoFormController.java b/src/main/java/org/olat/core/commons/modules/bc/meta/MetaInfoFormController.java index 7e41c6e7a546563557830c6c684b559be3c4c46e..d1b606f3a4735ab95ef6b90bb778336220526e3d 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/meta/MetaInfoFormController.java +++ b/src/main/java/org/olat/core/commons/modules/bc/meta/MetaInfoFormController.java @@ -56,6 +56,7 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSLockManager; import org.olat.core.util.vfs.lock.LockInfo; import org.olat.user.UserManager; +import org.springframework.beans.factory.annotation.Autowired; /** * This is the metadata flexiform controller with or without upload capability. @@ -78,9 +79,13 @@ public class MetaInfoFormController extends FormBasicController { private String resourceUrl; private final Roles roles; - private final UserManager userManager; - private final VFSLockManager vfsLockManager; - private final MetaInfoFactory metaInfoFactory; + + @Autowired + private UserManager userManager; + @Autowired + private VFSLockManager vfsLockManager; + @Autowired + private MetaInfoFactory metaInfoFactory; /** * Use this controller for editing meta data of an existing file. @@ -95,9 +100,6 @@ public class MetaInfoFormController extends FormBasicController { this.resourceUrl = resourceUrl; // load the metainfo roles = ureq.getUserSession().getRoles(); - userManager = CoreSpringFactory.getImpl(UserManager.class); - vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class); - metaInfoFactory = CoreSpringFactory.getImpl(MetaInfoFactory.class); initForm(ureq); } @@ -112,9 +114,6 @@ public class MetaInfoFormController extends FormBasicController { public MetaInfoFormController(UserRequest ureq, WindowControl control, Form parentForm) { super(ureq, control, FormBasicController.LAYOUT_DEFAULT, null, parentForm); roles = ureq.getUserSession().getRoles(); - userManager = CoreSpringFactory.getImpl(UserManager.class); - vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class); - metaInfoFactory = CoreSpringFactory.getImpl(MetaInfoFactory.class); isSubform = true; initForm(ureq); } @@ -132,9 +131,6 @@ public class MetaInfoFormController extends FormBasicController { isSubform = true; this.item = vfsItem; roles = ureq.getUserSession().getRoles(); - userManager = CoreSpringFactory.getImpl(UserManager.class); - vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class); - metaInfoFactory = CoreSpringFactory.getImpl(MetaInfoFactory.class); initForm(ureq); } @@ -189,21 +185,19 @@ public class MetaInfoFormController extends FormBasicController { setFormTitle("mf.metadata.title"); } setFormContextHelp("Folders#_metadata"); - - // filename - if (!isSubform) { - initialFilename = item.getName(); - filename = uifactory.addTextElement("filename", "mf.filename", -1, item.getName(), formLayout); - filename.setEnabled(item.canRename() == VFSConstants.YES); - filename.setNotEmptyCheck("mf.error.empty"); - filename.setMandatory(true); - } MetaInfo meta = item instanceof OlatRelPathImpl ? metaInfoFactory.createMetaInfoFor((OlatRelPathImpl)item) : null; // title String titleVal = (meta != null ? meta.getTitle() : null); title = uifactory.addTextElement("title", "mf.title", -1, titleVal, formLayout); + + // filename + initialFilename = (item == null ? null : item.getName()); + filename = uifactory.addTextElement("filename", "mf.filename", -1, initialFilename, formLayout); + filename.setEnabled(item == null || item.canRename() == VFSConstants.YES); + filename.setNotEmptyCheck("mf.error.empty"); + filename.setMandatory(true); // comment/description String commentVal = (meta != null ? meta.getComment() : null); @@ -405,6 +399,14 @@ public class MetaInfoFormController extends FormBasicController { return filename.getValue(); } + public TextElement getFilenameEl() { + return filename; + } + + public void setFilename(String name) { + filename.setValue(name); + } + public MetaInfo getMetaInfo(MetaInfo meta) { meta.setCreator(creator.getValue()); meta.setComment(comment.getValue()); diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_de.properties index 11c377813147cc714505b2c7f7bd2b76d4ffd4d8..ea72b9a004f2245d64a3018ee671f5af021a259b 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_de.properties @@ -14,6 +14,7 @@ mf.error.filename.exists=Ein Objekt mit gleichem Namen existiert bereits. mf.error.filename.invalidchars=Der Name des Objektes enth\u00E4lt ung\u00FCltige Zeichen. mf.file=Datei mf.filename=Dateiname +mf.filename.warning=<i class="o_icon o_icon_warn"> </i> Dieser Dateiname enth\u00E4lt unzul\u00E4ssige Zeichen und die wurden entfernt. mf.header=Metadaten Datei/Ordner mf.language=Sprache mf.lastModified=Datum letzte \u00C4nderung diff --git a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_en.properties index 8a20a599602914b64b10b6426a4ee91ae2c2fb86..aa2ac8587b1d46c7ca17b1660461a929d3f1a02d 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/commons/modules/bc/meta/_i18n/LocalStrings_en.properties @@ -14,6 +14,7 @@ mf.error.filename.exists=An object with that name already exists. mf.error.filename.invalidchars=The object's name contains invalid characters. mf.file=File mf.filename=File name +mf.filename.warning=<i class="o_icon o_icon_warn"> </i> This file name contains invalid characters and they were removed. mf.header=Metadata file/folder mf.language=Language mf.lastModified=Last modified\: diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java b/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java index a3687157edd48341bd7f1267ed067a96bb023b0b..b844f1224f4ef1c94acdd06d0e8ab01d4cc433f1 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java +++ b/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java @@ -60,7 +60,7 @@ public class VersionCommentController extends FormBasicController { initForm(ureq); } - + @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { if(comment && lock) { diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html b/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html index 1dfcf16e55486f39f44170b14fcd723a7bdb4ab3..cf46480a75b14198b8676913f93d6399a5d78f75 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html +++ b/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html @@ -2,6 +2,6 @@ <h5>$title</h5> #end #if ($description) - <p>$description</p> + <p class="o_info">$description</p> #end $r.render("revisionList") \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java index 3a68043f7fcc0d43fb1afbac44c7ac20eb488d19..e969d7195afb544218b62282926bdb7c6a3475a6 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormBasicController.java @@ -433,6 +433,14 @@ public abstract class FormBasicController extends BasicController implements IFo } } } + + public String getAndRemoveFormTitle() { + String title = (String)flc.contextGet("off_title"); + if(title != null) { + flc.contextRemove("off_title"); + } + return title; + } /** * Set an optional form title that is rendered as a fieldset legend. If you diff --git a/src/main/java/org/olat/core/util/FileUtils.java b/src/main/java/org/olat/core/util/FileUtils.java index aae8b418a19a5e675f18cc0c0a33454c3600ad72..420739154cea3b2fbf4201fc932833e235b677c6 100644 --- a/src/main/java/org/olat/core/util/FileUtils.java +++ b/src/main/java/org/olat/core/util/FileUtils.java @@ -852,6 +852,8 @@ public class FileUtils { return nameSanitized; } + + /** * Creates a new directory in the specified directory, using the given prefix and suffix strings to generate its name. * It uses File.createTempFile() and should provide a unique name. diff --git a/src/main/java/org/olat/core/util/vfs/VirtualContainer.java b/src/main/java/org/olat/core/util/vfs/VirtualContainer.java index 4e7ebc5eddd948213fd6f63db5eb07bab501b54d..bffa9376a2ad6d4d4b0de4522b3df0b4a861eaf1 100644 --- a/src/main/java/org/olat/core/util/vfs/VirtualContainer.java +++ b/src/main/java/org/olat/core/util/vfs/VirtualContainer.java @@ -27,7 +27,6 @@ package org.olat.core.util.vfs; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import org.olat.core.util.vfs.callbacks.VFSSecurityCallback; @@ -58,16 +57,18 @@ public class VirtualContainer extends AbstractVirtualContainer { } public List<VFSItem> getItems() { - return getItems(null); + return children; } public List<VFSItem> getItems(VFSItemFilter filter) { - if (filter == null) return children; - else { - List<VFSItem> filtered = new ArrayList<VFSItem>(); - for (Iterator<VFSItem> iter = children.iterator(); iter.hasNext();) { - VFSItem vfsItem = iter.next(); - if (filter.accept(vfsItem)) filtered.add(vfsItem); + if (filter == null) { + return children; + } else { + List<VFSItem> filtered = new ArrayList<VFSItem>(children.size()); + for (VFSItem vfsItem : children) { + if (filter.accept(vfsItem)) { + filtered.add(vfsItem); + } } return filtered; } diff --git a/src/main/java/org/olat/course/MergedCourseContainer.java b/src/main/java/org/olat/course/MergedCourseContainer.java index 428e01720d00f3268ceac838cc877cd0dc5b3b99..fd68725036ad78ca152534245560dc21d818ba28 100644 --- a/src/main/java/org/olat/course/MergedCourseContainer.java +++ b/src/main/java/org/olat/course/MergedCourseContainer.java @@ -81,41 +81,19 @@ public class MergedCourseContainer extends MergeSource { protected void init(PersistingCourseImpl persistingCourse) { super.init(); - RepositoryEntry re = null; if(identityEnv == null || identityEnv.getRoles().isOLATAdmin()) { addContainersChildren(persistingCourse.getIsolatedCourseFolder(), true); } else { - re = persistingCourse.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + RepositoryEntry re = persistingCourse.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); RepositoryEntrySecurity reSecurity = RepositoryManager.getInstance() .isAllowed(identityEnv.getIdentity(), identityEnv.getRoles(), re); if(reSecurity.isEntryAdmin()) { addContainersChildren(persistingCourse.getIsolatedCourseFolder(), true); } } - - // grab any shared folder that is configured, but only when in unchecked - // security mode (no identity environment) or when the user has course - // admin rights - OlatRootFolderImpl sharedFolder = null; - String sfSoftkey = persistingCourse.getCourseConfig().getSharedFolderSoftkey(); - if (StringHelper.containsNonWhitespace(sfSoftkey) && !CourseConfig.VALUE_EMPTY_SHAREDFOLDER_SOFTKEY.equals(sfSoftkey)) { - if (re == null) { - // reuse if already loaded, else load - re = persistingCourse.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); - } - if(identityEnv == null || identityEnv.getRoles().isOLATAdmin() || RepositoryManager.getInstance().isOwnerOfRepositoryEntry(identityEnv.getIdentity(), re)) { - OLATResource sharedResource = CoreSpringFactory.getImpl(RepositoryService.class).loadRepositoryEntryResourceBySoftKey(sfSoftkey); - if (sharedResource != null) { - sharedFolder = SharedFolderManager.getInstance().getSharedFolder(sharedResource); - if (sharedFolder != null) { - sharedFolder.setLocalSecurityCallback(new ReadOnlyCallback()); - //add local course folder's children as read/write source and any sharedfolder as subfolder - addContainer(new NamedContainerImpl("_sharedfolder", sharedFolder)); - } - } - } - } + + initSharedFolder(persistingCourse); // add all course building blocks of type BC to a virtual folder MergeSource nodesContainer = new MergeSource(null, "_courseelementdata"); @@ -138,6 +116,34 @@ public class MergedCourseContainer extends MergeSource { } } + /** + * Grab any shared folder that is configured, but only when in unchecked + * security mode (no identity environment) or when the user has course + * admin rights + * + * @param persistingCourse + */ + private void initSharedFolder(PersistingCourseImpl persistingCourse) { + CourseConfig courseConfig = persistingCourse.getCourseConfig(); + String sfSoftkey = courseConfig.getSharedFolderSoftkey(); + if (StringHelper.containsNonWhitespace(sfSoftkey) && !CourseConfig.VALUE_EMPTY_SHAREDFOLDER_SOFTKEY.equals(sfSoftkey)) { + RepositoryEntry re = persistingCourse.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); + if(identityEnv == null || identityEnv.getRoles().isOLATAdmin() || RepositoryManager.getInstance().isOwnerOfRepositoryEntry(identityEnv.getIdentity(), re)) { + OLATResource sharedResource = CoreSpringFactory.getImpl(RepositoryService.class).loadRepositoryEntryResourceBySoftKey(sfSoftkey); + if (sharedResource != null) { + OlatRootFolderImpl sharedFolder = SharedFolderManager.getInstance().getSharedFolder(sharedResource); + if (sharedFolder != null) { + if(courseConfig.isSharedFolderReadOnlyMount()) { + sharedFolder.setLocalSecurityCallback(new ReadOnlyCallback()); + } + //add local course folder's children as read/write source and any sharedfolder as subfolder + addContainer(new NamedContainerImpl("_sharedfolder", sharedFolder)); + } + } + } + } + } + private void addFolderBuildingBlocks(PersistingCourseImpl course, MergeSource nodesContainer, TreeNode courseNode) { if(courseNode == null) return; @@ -161,25 +167,26 @@ public class MergedCourseContainer extends MergeSource { // add folder not to merge source. Use name and node id to have unique name VFSContainer rootFolder = null; String subpath = bcNode.getModuleConfiguration().getStringValue(BCCourseNodeEditController.CONFIG_SUBPATH); - if(StringHelper.containsNonWhitespace(subpath)){ - if(bcNode.isSharedFolder()){ + if(StringHelper.containsNonWhitespace(subpath)) { + if(bcNode.isSharedFolder()) { // grab any shared folder that is configured - OlatRootFolderImpl sharedFolder = null; - String sfSoftkey = course.getCourseConfig().getSharedFolderSoftkey(); + CourseConfig courseConfig = course.getCourseConfig(); + String sfSoftkey = courseConfig.getSharedFolderSoftkey(); if (StringHelper.containsNonWhitespace(sfSoftkey) && !CourseConfig.VALUE_EMPTY_SHAREDFOLDER_SOFTKEY.equals(sfSoftkey)) { OLATResource sharedResource = CoreSpringFactory.getImpl(RepositoryService.class) .loadRepositoryEntryResourceBySoftKey(sfSoftkey); if (sharedResource != null) { - sharedFolder = SharedFolderManager.getInstance().getSharedFolder(sharedResource); - VFSContainer courseBase = sharedFolder; - sharedFolder.setLocalSecurityCallback(new ReadOnlyCallback()); + OlatRootFolderImpl sharedFolder = SharedFolderManager.getInstance().getSharedFolder(sharedResource); + if(sharedFolder != null && courseConfig.isSharedFolderReadOnlyMount()) { + sharedFolder.setLocalSecurityCallback(new ReadOnlyCallback()); + } subpath = subpath.replaceFirst("/_sharedfolder", ""); - rootFolder = (VFSContainer) courseBase.resolve(subpath); + rootFolder = (VFSContainer) sharedFolder.resolve(subpath); } } } else { VFSContainer courseBase = course.getCourseBaseContainer(); - rootFolder = (VFSContainer) courseBase.resolve("/coursefolder"+subpath); + rootFolder = (VFSContainer)courseBase.resolve("/coursefolder" + subpath); } } if(bcNode.getModuleConfiguration().getBooleanSafe(BCCourseNodeEditController.CONFIG_AUTO_FOLDER)){ @@ -251,7 +258,7 @@ public class MergedCourseContainer extends MergeSource { for (int i = 0; i < courseNode.getChildCount(); i++) { CourseNode child = (CourseNode) courseNode.getChildAt(i); String folderName = RequestUtil.normalizeFilename(child.getShortTitle()); - MergeSource courseNodeContainer; + if (child instanceof BCCourseNode) { final BCCourseNode bcNode = (BCCourseNode) child; bcNode.updateModuleConfigDefaults(false); @@ -273,14 +280,14 @@ public class MergedCourseContainer extends MergeSource { VFSContainer courseBase = sharedFolder; subpath = subpath.replaceFirst("/_sharedfolder", ""); rootFolder = (VFSContainer) courseBase.resolve(subpath); - if(rootFolder != null){ + if(rootFolder != null && course.getCourseConfig().isSharedFolderReadOnlyMount()) { rootFolder.setLocalSecurityCallback(new ReadOnlyCallback()); } } } }else{ VFSContainer courseBase = course.getCourseBaseContainer(); - rootFolder = (VFSContainer) courseBase.resolve("/coursefolder"+subpath); + rootFolder = (VFSContainer) courseBase.resolve("/coursefolder" + subpath); } } if(bcNode.getModuleConfiguration().getBooleanSafe(BCCourseNodeEditController.CONFIG_AUTO_FOLDER)){ @@ -288,7 +295,6 @@ public class MergedCourseContainer extends MergeSource { rootFolder = new OlatRootFolderImpl(path, null); } - // add node ident if multiple files have same name if (nodesContainer.getItems(new VFSItemFilter() { @Override @@ -302,7 +308,7 @@ public class MergedCourseContainer extends MergeSource { if(rootFolder != null){ // Create a container for this node content and wrap it with a merge source which is attached to tree VFSContainer nodeContentContainer = new NamedContainerImpl(folderName, rootFolder); - courseNodeContainer = new MergeSource(nodesContainer, folderName); + MergeSource courseNodeContainer = new MergeSource(nodesContainer, folderName); courseNodeContainer.addContainersChildren(nodeContentContainer, true); nodesContainer.addContainer(courseNodeContainer); // Do recursion for all children @@ -310,7 +316,7 @@ public class MergedCourseContainer extends MergeSource { } } else { // For non-folder course nodes, add merge source (no files to show) ... - courseNodeContainer = new MergeSource(null, folderName); + MergeSource courseNodeContainer = new MergeSource(null, folderName); // , then do recursion for all children ... addFolderBuildingBlocks(course, courseNodeContainer, child); // ... but only add this container if it contains any children with at least one BC course node diff --git a/src/main/java/org/olat/course/config/CourseConfig.java b/src/main/java/org/olat/course/config/CourseConfig.java index 1fa12a1573a4a41b143f76528f65be832ba42407..2b02c7ce23c3d72641ae8c928b91fe75c694b27c 100644 --- a/src/main/java/org/olat/course/config/CourseConfig.java +++ b/src/main/java/org/olat/course/config/CourseConfig.java @@ -125,6 +125,10 @@ public class CourseConfig implements Serializable, Cloneable { * */ transient public static final String KEY_SHAREDFOLDER_SOFTKEY = "SHAREDFOLDER_SOFTKEY"; + /** + * + */ + transient public static final String KEY_SHAREDFOLDER_READONLY = "SHAREDFOLDER_RO"; /** * current key set */ @@ -384,6 +388,15 @@ public class CourseConfig implements Serializable, Cloneable { public boolean hasCustomSharedFolder() { return !(VALUE_EMPTY_SHAREDFOLDER_SOFTKEY.equals(getSharedFolderSoftkey())); } + + public boolean isSharedFolderReadOnlyMount() { + Object obj = configuration.get(KEY_SHAREDFOLDER_READONLY); + return (obj == null || !Boolean.FALSE.equals(obj)); + } + + public void setSharedFolderReadOnlyMount(boolean mount) { + configuration.put(KEY_SHAREDFOLDER_READONLY, new Boolean(mount)); + } /** * @param b @@ -537,6 +550,7 @@ public class CourseConfig implements Serializable, Cloneable { clone.setEfficencyStatementIsEnabled(isEfficencyStatementEnabled()); clone.setGlossarySoftKey(getGlossarySoftKey()); clone.setSharedFolderSoftkey(getSharedFolderSoftkey()); + clone.setSharedFolderReadOnlyMount(isSharedFolderReadOnlyMount()); clone.setAutomaticCertificationEnabled(isAutomaticCertificationEnabled()); clone.setManualCertificationEnabled(isManualCertificationEnabled()); clone.setCertificateTemplate(getCertificateTemplate()); @@ -556,11 +570,12 @@ public class CourseConfig implements Serializable, Cloneable { public boolean equals(Object obj) { try { CourseConfig aCourseConfig = (CourseConfig) obj; - boolean sameCalendarSettings = aCourseConfig.isCalendarEnabled() == this.isCalendarEnabled(); - boolean sameChatSettings = aCourseConfig.isChatEnabled() == this.isChatEnabled(); - boolean sameCssLayout = aCourseConfig.getCssLayoutRef().equals(this.getCssLayoutRef()); - boolean sameEfficiencyStatementSettings = aCourseConfig.isEfficencyStatementEnabled() == this.isEfficencyStatementEnabled(); - boolean sameSharedFolderSettings = aCourseConfig.getSharedFolderSoftkey().equals(this.getSharedFolderSoftkey()); + boolean sameCalendarSettings = aCourseConfig.isCalendarEnabled() == isCalendarEnabled(); + boolean sameChatSettings = aCourseConfig.isChatEnabled() == isChatEnabled(); + boolean sameCssLayout = aCourseConfig.getCssLayoutRef().equals(getCssLayoutRef()); + boolean sameEfficiencyStatementSettings = aCourseConfig.isEfficencyStatementEnabled() == isEfficencyStatementEnabled(); + boolean sameSharedFolderSettings = aCourseConfig.getSharedFolderSoftkey().equals(getSharedFolderSoftkey()) + && aCourseConfig.isSharedFolderReadOnlyMount() == isSharedFolderReadOnlyMount(); boolean sameGlossarySettings = false; if (aCourseConfig.getGlossarySoftKey() != null && this.getGlossarySoftKey() != null) { diff --git a/src/main/java/org/olat/course/config/ui/CourseOptionsController.java b/src/main/java/org/olat/course/config/ui/CourseOptionsController.java index 5062e954576b0a2ece7847a08ad96422f5e49a91..627a7cf223ff5895c96e0af588c821645db8f82a 100644 --- a/src/main/java/org/olat/course/config/ui/CourseOptionsController.java +++ b/src/main/java/org/olat/course/config/ui/CourseOptionsController.java @@ -28,6 +28,7 @@ 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.FormLink; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.SelectionElement; import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; @@ -69,6 +70,7 @@ import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryManagedFlag; import org.olat.repository.RepositoryManager; import org.olat.repository.controllers.ReferencableEntriesSearchController; +import org.olat.repository.model.RepositoryEntrySecurity; import org.olat.resource.references.Reference; import org.olat.resource.references.ReferenceManager; import org.olat.util.logging.activity.LoggingResourceable; @@ -92,10 +94,11 @@ public class CourseOptionsController extends FormBasicController { private FormLink addGlossaryCommand, removeGlossaryCommand; private StaticTextElement glossaryNameEl; private FormLink saveButton; - private FormLayoutContainer saveCont, calendarCont, chatCont, glossaryCont; + private FormLayoutContainer saveCont, calendarCont, chatCont, glossaryCont, sharedFolderCont; private FormLink addFolderCommand, removeFolderCommand; private StaticTextElement folderNameEl; + private MultipleSelectionElement folderReadOnlyEl; private final boolean editable; private CourseConfig courseConfig; @@ -160,10 +163,15 @@ public class CourseOptionsController extends FormBasicController { folderNameEl.setValue(StringHelper.escapeHtml(repoEntry.getDisplayname())); folderNameEl.setUserObject(repoEntry); removeFolderCommand.setVisible(editable && !managedFolder); + + RepositoryEntrySecurity reSecurity = repositoryService.isAllowed(ureq, repoEntry); + folderReadOnlyEl.setVisible(true); + folderReadOnlyEl.setEnabled(reSecurity.isEntryAdmin()); } } else if(editable && !managedFolder) { removeFolderCommand.setVisible(false); addFolderCommand.setVisible(true); + folderReadOnlyEl.setVisible(false); } } @@ -240,7 +248,7 @@ public class CourseOptionsController extends FormBasicController { //shared folder boolean managedFolder = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.resourcefolder); - FormLayoutContainer sharedFolderCont = FormLayoutContainer.createDefaultFormLayout("sharedfolder", getTranslator()); + sharedFolderCont = FormLayoutContainer.createDefaultFormLayout("sharedfolder", getTranslator()); sharedFolderCont.setRootForm(mainForm); formLayout.add(sharedFolderCont); @@ -248,9 +256,19 @@ public class CourseOptionsController extends FormBasicController { translate("sf.notconfigured"), sharedFolderCont); folderNameEl.setHelpText(translate("sf.resourcetitle.helptext")); folderNameEl.setHelpUrlForManualPage("Course Settings#_detail_ressourcen"); - + + String[] readOnlyValues = new String[]{ translate("sf.resource.readonly") }; + folderReadOnlyEl = uifactory.addCheckboxesHorizontal("sf.resource.readonly", sharedFolderCont, onKeys, readOnlyValues); + folderReadOnlyEl.addActionListener(FormEvent.ONCHANGE); + folderReadOnlyEl.setLabel(null, null); + folderReadOnlyEl.setEnabled(false); + if(courseConfig.isSharedFolderReadOnlyMount()) { + folderReadOnlyEl.select(onKeys[0], true); + } + FormLayoutContainer buttons2Cont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); sharedFolderCont.add(buttons2Cont); + removeFolderCommand = uifactory.addFormLink("sf.unselectsfresource", buttons2Cont, Link.BUTTON); removeFolderCommand.setVisible(editable && !managedFolder); addFolderCommand = uifactory.addFormLink("sf.changesfresource", buttons2Cont, Link.BUTTON); @@ -284,7 +302,7 @@ public class CourseOptionsController extends FormBasicController { cmc.deactivate(); if (event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) { RepositoryEntry repoEntry = folderSearchCtr.getSelectedEntry(); - doSelectSharedFolder(repoEntry); + doSelectSharedFolder(ureq, repoEntry); setSaveButtonDirty(); } cleanUp(); @@ -345,9 +363,9 @@ public class CourseOptionsController extends FormBasicController { } updateToolbar(); setSaveButtonDirty(); - } else if (source instanceof SelectionElement) { + } else if (source instanceof SelectionElement || source == folderReadOnlyEl) { setSaveButtonDirty(); - } else if(saveButton == source) { + } else if(saveButton == source) { doSave(ureq); } } @@ -456,8 +474,11 @@ public class CourseOptionsController extends FormBasicController { || (currentFolderSoftKey != null && !currentFolderSoftKey.equals(newFolderSoftKey)); courseConfig.setSharedFolderSoftkey(newFolderSoftKey); - - + if(folderReadOnlyEl.isEnabled()) { + courseConfig.setSharedFolderReadOnlyMount(folderReadOnlyEl.isAtLeastSelected(1)); + } else { + courseConfig.setSharedFolderReadOnlyMount(true); + } CourseFactory.setCourseConfig(course.getResourceableId(), courseConfig); CourseFactory.closeCourseEditSession(course.getResourceableId(), true); @@ -559,16 +580,23 @@ public class CourseOptionsController extends FormBasicController { removeGlossaryCommand.setVisible(false); } - private void doSelectSharedFolder(RepositoryEntry repoEntry) { + private void doSelectSharedFolder(UserRequest ureq, RepositoryEntry repoEntry) { folderNameEl.setValue(StringHelper.escapeHtml(repoEntry.getDisplayname())); folderNameEl.setUserObject(repoEntry); removeFolderCommand.setVisible(true); + + RepositoryEntrySecurity reSecurity = repositoryService.isAllowed(ureq, repoEntry); + folderReadOnlyEl.setVisible(true); + folderReadOnlyEl.setEnabled(reSecurity.isEntryAdmin()); + folderReadOnlyEl.select(onKeys[0], true); + sharedFolderCont.setDirty(true); } private void doRemoveSharedFolder() { folderNameEl.setValue(translate("sf.notconfigured")); folderNameEl.setUserObject(null); removeFolderCommand.setVisible(false); + folderReadOnlyEl.setVisible(false); } } \ No newline at end of file diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties index 3cb45eb758e792c451ad84affbee788c9f021d4a..3051034c7984861964893f5ec7414f317c22f235 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_de.properties @@ -25,6 +25,7 @@ sf.changesfresource=Auswechseln sf.notconfigured=<i>Kein Ressourcenordner ausgew\u00E4hlt</i> sf.resourcetitle=Gew\u00E4hlter Ressourcenordner sf.resourcetitle.helptext=Die im Ressourcenordner abgelegten Dateien finden Sie im Ablageordner des Kurses im Unterordner \u201E_sharedfolder\u201C. +sf.resource.readonly=Schreibgesch\u00FCtzt sf.selectsfresource=Ausw\u00E4hlen sf.unselectsfresource=Auswahl l\u00F6schen tab.calendar.title=Einstellungen diff --git a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties index 51cfa61939eb04ae6b3a958ce94b13841308f804..a0000291ec1ae698dd7ad34aa60e0efd4117c2c7 100644 --- a/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/config/ui/_i18n/LocalStrings_en.properties @@ -25,6 +25,7 @@ sf.changesfresource=Replace sf.notconfigured=<i>No resource folder selected</i> sf.resourcetitle=Selected recource folder sf.resourcetitle.helptext=The files stored there can be found in the storage folder of your course when selecting the sub-folder "_sharedfolder". +sf.resource.readonly=Read only sf.selectsfresource=Select sf.unselectsfresource=Deselect tab.calendar.title=Settings diff --git a/src/main/java/org/olat/course/nodes/bc/BCCourseNodeEditForm.java b/src/main/java/org/olat/course/nodes/bc/BCCourseNodeEditForm.java index 592a13320f9f117ddf744272e0acf5577be596c4..56131f0c3238effb2704819cbe11def1317fae0d 100644 --- a/src/main/java/org/olat/course/nodes/bc/BCCourseNodeEditForm.java +++ b/src/main/java/org/olat/course/nodes/bc/BCCourseNodeEditForm.java @@ -112,9 +112,9 @@ public class BCCourseNodeEditForm extends FormBasicController implements Control } - if(node.isSharedFolder()){ - sharedFolderInfo.setVisible(true); - }else{ + if(node.isSharedFolder()) { + sharedFolderInfo.setVisible(course.getCourseConfig().isSharedFolderReadOnlyMount()); + } else { sharedFolderInfo.setVisible(false); } @@ -143,8 +143,8 @@ public class BCCourseNodeEditForm extends FormBasicController implements Control }else{ sharedFolderWarning.setVisible(false); } - if(node.isSharedFolder()){ - sharedFolderInfo.setVisible(true); + if(node.isSharedFolder()) { + sharedFolderInfo.setVisible(course.getCourseConfig().isSharedFolderReadOnlyMount()); }else{ sharedFolderInfo.setVisible(false); } diff --git a/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java b/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java index f4b19bd830bf8af55aac168a7ad0d751471f08ee..26117bedcf0e7655f95a4045a281557eaac83712 100644 --- a/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java +++ b/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java @@ -86,15 +86,16 @@ public class SharedFolderManager { public OlatRootFolderImpl getSharedFolder(OLATResourceable res) { OlatRootFolderImpl rootFolderImpl = (OlatRootFolderImpl)FileResourceManager.getInstance().getFileResourceRootImpl(res).resolve(SharedFolderManager.FOLDER_NAME); - if (rootFolderImpl == null) return null; - rootFolderImpl.setLocalSecurityCallback(new SharedFolderSecurityCallback(rootFolderImpl.getRelPath())); + if (rootFolderImpl != null) { + rootFolderImpl.setLocalSecurityCallback(new SharedFolderSecurityCallback(rootFolderImpl.getRelPath())); + } return rootFolderImpl; } public MediaResource getAsMediaResource(OLATResourceable res) { String exportFileName = res.getResourceableId() + ".zip"; File fExportZIP = new File(WebappHelper.getTmpDir() + "/" + exportFileName); - VFSContainer sharedFolder = SharedFolderManager.getInstance().getSharedFolder(res); + VFSContainer sharedFolder = getSharedFolder(res); //OLAT-5368: do intermediate commit to avoid transaction timeout // discussion intermediatecommit vs increased transaction timeout: