diff --git a/src/main/java/org/olat/core/commons/editor/fileeditor/FileEditorController.java b/src/main/java/org/olat/core/commons/editor/fileeditor/FileEditorController.java index 608d05aa8c76c1f923517a2dd16b37e5aea36a2f..bcdaea568f036d3b38cc85be72b87716e19b059c 100644 --- a/src/main/java/org/olat/core/commons/editor/fileeditor/FileEditorController.java +++ b/src/main/java/org/olat/core/commons/editor/fileeditor/FileEditorController.java @@ -96,11 +96,11 @@ public class FileEditorController extends BasicController { CustomLinkTreeModel customLinkTreeModel = config.getCustomLinkTreeModel(); if (customLinkTreeModel != null) { htmlCtrl = WysiwygFactory.createWysiwygControllerWithInternalLink(ureq, getWindowControl(), - config.getVfsContainer(), config.getFilePath(), true, customLinkTreeModel, + config.getVfsContainer(), config.getFilePath(), true, secCallback.isVersionControlled(), customLinkTreeModel, config.getEdusharingProvider()); } else { htmlCtrl = WysiwygFactory.createWysiwygController(ureq, getWindowControl(), config.getVfsContainer(), - config.getFilePath(), config.getMediaPath(), true, true, config.getEdusharingProvider()); + config.getFilePath(), config.getMediaPath(), true, secCallback.isVersionControlled(), config.getEdusharingProvider()); } htmlCtrl.setNewFile(false); @@ -115,7 +115,7 @@ public class FileEditorController extends BasicController { } } else { - editCtrl = new TextEditorController(ureq, getWindowControl(), vfsLeaf, "utf-8", !isEdit); + editCtrl = new TextEditorController(ureq, getWindowControl(), vfsLeaf, "utf-8", !isEdit, secCallback.isVersionControlled()); } listenTo(editCtrl); diff --git a/src/main/java/org/olat/core/commons/editor/htmleditor/WysiwygFactory.java b/src/main/java/org/olat/core/commons/editor/htmleditor/WysiwygFactory.java index e4b28a651585c151ce4d262d4e19d771fe2a223f..4ece1a0c8b59938fa53ace9e762fd2f97f5dade6 100644 --- a/src/main/java/org/olat/core/commons/editor/htmleditor/WysiwygFactory.java +++ b/src/main/java/org/olat/core/commons/editor/htmleditor/WysiwygFactory.java @@ -120,15 +120,24 @@ public class WysiwygFactory { UserRequest ureq, WindowControl wControl, VFSContainer baseContainer, String relFilePath, boolean editorCheckEnabled, CustomLinkTreeModel customLinkTreeModel) { - return createWysiwygControllerWithInternalLink(ureq, wControl, baseContainer, relFilePath, editorCheckEnabled, customLinkTreeModel, null); + return createWysiwygControllerWithInternalLink(ureq, wControl, baseContainer, relFilePath, editorCheckEnabled, + customLinkTreeModel, null); } public static HTMLEditorController createWysiwygControllerWithInternalLink( UserRequest ureq, WindowControl wControl, VFSContainer baseContainer, String relFilePath, boolean editorCheckEnabled, CustomLinkTreeModel customLinkTreeModel, VFSEdusharingProvider edusharingProvider) { + return createWysiwygControllerWithInternalLink(ureq, wControl, baseContainer, relFilePath, editorCheckEnabled, + true, customLinkTreeModel, edusharingProvider); + } + + public static HTMLEditorController createWysiwygControllerWithInternalLink( + UserRequest ureq, WindowControl wControl, VFSContainer baseContainer, + String relFilePath, boolean editorCheckEnabled, boolean version, + CustomLinkTreeModel customLinkTreeModel, VFSEdusharingProvider edusharingProvider) { return new HTMLEditorController(ureq, wControl, baseContainer, relFilePath, - customLinkTreeModel, null, editorCheckEnabled, true, edusharingProvider); + customLinkTreeModel, null, editorCheckEnabled, version, edusharingProvider); } /** diff --git a/src/main/java/org/olat/core/commons/editor/plaintexteditor/TextEditorController.java b/src/main/java/org/olat/core/commons/editor/plaintexteditor/TextEditorController.java index 31a8cae7deeb0874e9afb5e6212270f6f2c74252..c349901291425519acb260bf415049cdc800cb0a 100644 --- a/src/main/java/org/olat/core/commons/editor/plaintexteditor/TextEditorController.java +++ b/src/main/java/org/olat/core/commons/editor/plaintexteditor/TextEditorController.java @@ -45,11 +45,12 @@ import org.springframework.beans.factory.annotation.Autowired; /** * * Initial date: 18 Mar 2019<br> + * * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * */ public class TextEditorController extends FormBasicController { - + private TextElement contentEl; private FormLink saveLink; private FormLink saveCloseLink; @@ -58,47 +59,49 @@ public class TextEditorController extends FormBasicController { private final VFSLeaf vfsLeaf; private final String encoding; private final boolean readonly; - + private final boolean versionControlled; + @Autowired private VFSRepositoryService vfsRepositoryService; - public TextEditorController(UserRequest ureq, WindowControl wControl, VFSLeaf vfsLeaf, String encoding, boolean readonly) { + public TextEditorController(UserRequest ureq, WindowControl wControl, VFSLeaf vfsLeaf, String encoding, + boolean readonly, boolean versionControlled) { super(ureq, wControl, LAYOUT_VERTICAL); this.vfsLeaf = vfsLeaf; this.encoding = encoding; this.readonly = readonly; - + this.versionControlled = versionControlled; + initForm(ureq); } - + @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { contentEl = uifactory.addTextAreaElement("textarea", "textarea", -1, 25, 100, true, false, "", formLayout); - + FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonCont.setElementCssClass("o_button_group"); formLayout.add("buttons", buttonCont); - long size = vfsLeaf.getSize(); //bytes + long size = vfsLeaf.getSize(); // bytes if (size > FolderConfig.getMaxEditSizeLimit()) { - setFormWarning("plaintext.error.tolarge", new String[]{ - String.valueOf(size / 1000), + setFormWarning("plaintext.error.tolarge", new String[] { String.valueOf(size / 1000), String.valueOf(FolderConfig.getMaxEditSizeLimit() / 1000) }); } else { - String content = FileUtils.load(vfsLeaf.getInputStream(),encoding); + String content = FileUtils.load(vfsLeaf.getInputStream(), encoding); contentEl.setValue(content); contentEl.setLabel("file.name", new String[] { vfsLeaf.getName() }); contentEl.setEnabled(!readonly); - + saveLink = uifactory.addFormLink("save", buttonCont, Link.BUTTON); saveLink.setVisible(!readonly); saveCloseLink = uifactory.addFormLink("save.close", buttonCont, Link.BUTTON); saveCloseLink.setVisible(!readonly); } - + closeLink = uifactory.addFormLink("close", buttonCont, Link.BUTTON); } - + @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if (source == saveLink) { @@ -114,16 +117,16 @@ public class TextEditorController extends FormBasicController { private void doSave() { String content = contentEl.getValue(); - if(vfsLeaf.canVersion() == VFSConstants.YES) { + if (versionControlled && vfsLeaf.canVersion() == VFSConstants.YES) { try (InputStream inStream = FileUtils.getInputStream(content, encoding)) { vfsRepositoryService.addVersion(vfsLeaf, getIdentity(), "", inStream); } catch (IOException e) { logError("", e); } } else { - try(OutputStream out = vfsLeaf.getOutputStream(false)) { + try (OutputStream out = vfsLeaf.getOutputStream(false)) { FileUtils.save(out, content, encoding); - } catch(IOException e) { + } catch (IOException e) { logError("", e); } } diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdCreateFile.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdCreateFile.java index 330a5b999eb6997183be0bc98f4929d79dc6db92..231b5055275e532aa6573bdbf5037098ad2fc5a1 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdCreateFile.java +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdCreateFile.java @@ -191,7 +191,7 @@ public class CmdCreateFile extends BasicController implements FolderCommand { VFSLeafEditorSecurityCallback secCallback = VFSLeafEditorSecurityCallbackBuilder.builder() .withMode(VFSLeafEditor.Mode.EDIT) - .canClose(true) + .withVersionControlled(true) .build(); HTMLEditorConfig htmlEditorConfig = getHtmlEditorConfig(); VFSLeafEditorConfigs configs = VFSLeafEditorConfigs.builder() diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdOpenContent.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdOpenContent.java index e7e467bd7c9fa5cc804569366d3efcb803a37a5a..86ce31a70456ddd31d0d482351730a51ff95f374 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdOpenContent.java +++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdOpenContent.java @@ -107,6 +107,7 @@ public class CmdOpenContent extends BasicController implements FolderCommand { VFSSecurityCallback containerSecCallback = container.getLocalSecurityCallback(); VFSLeafEditorSecurityCallback secCallback = VFSLeafEditorSecurityCallbackBuilder.builder() .withMode(getMode(vfsLeaf, containerSecCallback.canWrite())) + .withVersionControlled(true) .build(); HTMLEditorConfig htmlEditorConfig = getHtmlEditorConfig(vfsLeaf); VFSLeafEditorConfigs configs = VFSLeafEditorConfigs.builder() diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSLeafEditorSecurityCallback.java b/src/main/java/org/olat/core/commons/services/vfs/VFSLeafEditorSecurityCallback.java index 5b6f9918c0da083ac9e36893241000d6c660b455..07afb86527477195a9f0de077425b013d335b468 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/VFSLeafEditorSecurityCallback.java +++ b/src/main/java/org/olat/core/commons/services/vfs/VFSLeafEditorSecurityCallback.java @@ -30,6 +30,8 @@ import org.olat.core.commons.services.vfs.VFSLeafEditor.Mode; public interface VFSLeafEditorSecurityCallback { Mode getMode(); + + boolean isVersionControlled(); boolean canClose(); diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSLeafEditorSecurityCallbackBuilder.java b/src/main/java/org/olat/core/commons/services/vfs/VFSLeafEditorSecurityCallbackBuilder.java index 4d4167ceb18bf5337acd858e2c7e6b84ff01c7ce..1c1bad298672e4f560244d4fe3bf4be625090084 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/VFSLeafEditorSecurityCallbackBuilder.java +++ b/src/main/java/org/olat/core/commons/services/vfs/VFSLeafEditorSecurityCallbackBuilder.java @@ -30,6 +30,7 @@ import org.olat.core.commons.services.vfs.VFSLeafEditor.Mode; public class VFSLeafEditorSecurityCallbackBuilder { private Mode mode = Mode.VIEW; + private boolean versionControlled = false; private boolean canClose = true; /** @@ -43,6 +44,17 @@ public class VFSLeafEditorSecurityCallbackBuilder { return this; } + /** + * Default: false + * + * @param versionControlled + * @return + */ + public VFSLeafEditorSecurityCallbackBuilder withVersionControlled(boolean versionControlled) { + this.versionControlled = versionControlled; + return this; + } + /** * Default: true * @@ -57,6 +69,7 @@ public class VFSLeafEditorSecurityCallbackBuilder { public VFSLeafEditorSecurityCallback build() { VFSLeafEditorSecurityCallbackImpl secCallback = new VFSLeafEditorSecurityCallbackImpl(); secCallback.setMode(this.mode); + secCallback.setVersionControlled(this.versionControlled); secCallback.setCanClose(this.canClose); return secCallback; } @@ -68,6 +81,7 @@ public class VFSLeafEditorSecurityCallbackBuilder { public static VFSLeafEditorSecurityCallbackBuilder clone(VFSLeafEditorSecurityCallback secCallback) { return builder() .withMode(secCallback.getMode()) + .withVersionControlled(secCallback.isVersionControlled()) .canClose(secCallback.canClose()); } @@ -77,6 +91,7 @@ public class VFSLeafEditorSecurityCallbackBuilder { private static class VFSLeafEditorSecurityCallbackImpl implements VFSLeafEditorSecurityCallback { private Mode mode; + private boolean versionControlled; private boolean canClose; @Override @@ -84,10 +99,19 @@ public class VFSLeafEditorSecurityCallbackBuilder { return mode; } - public void setMode(Mode mode) { + private void setMode(Mode mode) { this.mode = mode; } + @Override + public boolean isVersionControlled() { + return versionControlled; + } + + private void setVersionControlled(boolean versionControlled) { + this.versionControlled = versionControlled; + } + @Override public boolean canClose() { return canClose; diff --git a/src/main/java/org/olat/modules/wopi/Access.java b/src/main/java/org/olat/modules/wopi/Access.java index 5fd9fcdc3495547ad5f6a91c50eec5c46d2b551d..ca2964f192752378d4c0fc089c789e46f04cbd33 100644 --- a/src/main/java/org/olat/modules/wopi/Access.java +++ b/src/main/java/org/olat/modules/wopi/Access.java @@ -39,6 +39,8 @@ public interface Access { VFSMetadata getVfsMetadata(); boolean canEdit(); + + boolean isVersionControlled(); boolean canClose(); diff --git a/src/main/java/org/olat/modules/wopi/collabora/CollaboraService.java b/src/main/java/org/olat/modules/wopi/collabora/CollaboraService.java index e8e2616cc5a9a8c24e95f5c3984791445db5dbe8..8ed1b8c022b25e2a253650798c36f170e9fdb6c7 100644 --- a/src/main/java/org/olat/modules/wopi/collabora/CollaboraService.java +++ b/src/main/java/org/olat/modules/wopi/collabora/CollaboraService.java @@ -56,9 +56,9 @@ public interface CollaboraService { void deleteAccess(Access access); - boolean canUpdateContent(String fileId, Access access); + boolean canUpdateContent(Access access, String fileId); - boolean updateContent(String fileId, InputStream fileInputStream); + boolean updateContent(Access access, InputStream fileInputStream); Discovery getDiscovery(); diff --git a/src/main/java/org/olat/modules/wopi/collabora/manager/CollaboraServiceImpl.java b/src/main/java/org/olat/modules/wopi/collabora/manager/CollaboraServiceImpl.java index aafe92af6311029913c066bfc2fcb378a86d0660..bc3aaeda38273575017b0ab9a75e684f3c5c23e8 100644 --- a/src/main/java/org/olat/modules/wopi/collabora/manager/CollaboraServiceImpl.java +++ b/src/main/java/org/olat/modules/wopi/collabora/manager/CollaboraServiceImpl.java @@ -27,6 +27,7 @@ import javax.annotation.PostConstruct; import org.olat.core.commons.services.vfs.VFSLeafEditor.Mode; import org.olat.core.commons.services.vfs.VFSLeafEditorSecurityCallback; import org.olat.core.commons.services.vfs.VFSMetadata; +import org.olat.core.commons.services.vfs.VFSRepositoryService; import org.olat.core.gui.control.Event; import org.olat.core.id.Identity; import org.olat.core.logging.OLog; @@ -34,6 +35,7 @@ import org.olat.core.logging.Tracing; import org.olat.core.util.FileUtils; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; +import org.olat.core.util.vfs.VFSConstants; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSLockApplicationType; import org.olat.core.util.vfs.VFSLockManager; @@ -71,6 +73,8 @@ public class CollaboraServiceImpl implements CollaboraService, GenericEventListe @Autowired private WopiDiscoveryClient discoveryClient; @Autowired + private VFSRepositoryService vfsRepositoryService; + @Autowired private VFSLockManager lockManager; @PostConstruct @@ -111,7 +115,7 @@ public class CollaboraServiceImpl implements CollaboraService, GenericEventListe } @Override - public boolean canUpdateContent(String fileId, Access access) { + public boolean canUpdateContent(Access access, String fileId) { if (!fileId.equals(access.getFileId())) { return false; } @@ -120,17 +124,26 @@ public class CollaboraServiceImpl implements CollaboraService, GenericEventListe } @Override - public boolean updateContent(String fileId, InputStream fileInputStream) { - VFSLeaf vfsLeaf = wopiService.getVfsLeaf(fileId); - boolean updated = VFSManager.copyContent(fileInputStream, vfsLeaf); + public boolean updateContent(Access access, InputStream fileInputStream) { + VFSLeaf vfsLeaf = wopiService.getVfsLeaf(access.getFileId()); + boolean updated = false; + try { + if(access.isVersionControlled() && vfsLeaf.canVersion() == VFSConstants.YES) { + updated = vfsRepositoryService.addVersion(vfsLeaf, access.getIdentity(), "Collabora Office", + fileInputStream); + } else { + updated = VFSManager.copyContent(fileInputStream, vfsLeaf); + } + } catch(Exception e) { + log.error("", e); + } if (updated) { - refreshLock(fileId); + refreshLock(vfsLeaf); } return updated; } - private void refreshLock(String fileId) { - VFSLeaf vfsLeaf = wopiService.getVfsLeaf(fileId); + private void refreshLock(VFSLeaf vfsLeaf) { LockInfo lock = lockManager.getLock(vfsLeaf); if (lock != null) { long inADay = System.currentTimeMillis() + (24 * 60 * 60 * 1000); diff --git a/src/main/java/org/olat/modules/wopi/collabora/restapi/FilesWebService.java b/src/main/java/org/olat/modules/wopi/collabora/restapi/FilesWebService.java index 6f8dbe892155eafb13beaa3266c590df15f06ed7..7eac1742f8e8a3b70853f3527558920dfa626eb1 100644 --- a/src/main/java/org/olat/modules/wopi/collabora/restapi/FilesWebService.java +++ b/src/main/java/org/olat/modules/wopi/collabora/restapi/FilesWebService.java @@ -27,7 +27,6 @@ import java.io.InputStream; import java.util.Date; import java.util.List; import java.util.Map.Entry; -import java.util.UUID; import java.util.stream.Collectors; import javax.ws.rs.Consumes; @@ -107,7 +106,7 @@ public class FilesWebService { .withSize(metadata.getFileSize()) .withUserId(access.getIdentity().getKey().toString()) .withUserFriendlyName(userManager.getUserDisplayName(access.getIdentity())) - .withVersion(UUID.randomUUID().toString()) + .withVersion(String.valueOf(metadata.getRevisionNr())) .withLastModifiedTime(getAsIso6801(metadata.getLastModified())) .withUserCanWrite(access.canEdit()) .withDisablePrint(Boolean.FALSE) @@ -180,7 +179,7 @@ public class FilesWebService { return Response.serverError().status(Status.UNAUTHORIZED).build(); } - boolean canUpdate = collaboraService.canUpdateContent(fileId, access); + boolean canUpdate = collaboraService.canUpdateContent(access, fileId); if (!canUpdate) { log.debug("Access has not right to update file. File ID: " + fileId + ", token: " + accessToken); return Response.serverError().status(Status.UNAUTHORIZED).build(); @@ -191,7 +190,7 @@ public class FilesWebService { log.debug("File changed at " + timestamp + ". File ID: " + fileId + ", token: " + accessToken); try { - boolean updated = collaboraService.updateContent(fileId, fileInputStream); + boolean updated = collaboraService.updateContent(access, fileInputStream); if (updated) { PutFileVO putFileVO = PutFileVO.builder() .withLastModifiedTime(getAsIso6801(new Date())) diff --git a/src/main/java/org/olat/modules/wopi/manager/WopiServiceImpl.java b/src/main/java/org/olat/modules/wopi/manager/WopiServiceImpl.java index 5ad4472aa13f4ec15d560e0c08f9ab1c52aed7bc..583ff0f4ffcd52fb10ca0a381b8bd9a318520e09 100644 --- a/src/main/java/org/olat/modules/wopi/manager/WopiServiceImpl.java +++ b/src/main/java/org/olat/modules/wopi/manager/WopiServiceImpl.java @@ -115,6 +115,7 @@ public class WopiServiceImpl implements WopiService { access.setFileId(fileId); access.setIdentity(identity); access.setCanEdit(Mode.EDIT.equals(secCallback.getMode())); + access.setVersionControlled(secCallback.isVersionControlled()); access.setCanClose(secCallback.canClose()); accessCache.put(token, access); return access; diff --git a/src/main/java/org/olat/modules/wopi/model/AccessImpl.java b/src/main/java/org/olat/modules/wopi/model/AccessImpl.java index db13cba570f0f46d2cf97ff2ff8ac6a47f830d8f..feb021715f58f5e8ab46a8497638db3871c106cb 100644 --- a/src/main/java/org/olat/modules/wopi/model/AccessImpl.java +++ b/src/main/java/org/olat/modules/wopi/model/AccessImpl.java @@ -35,6 +35,7 @@ public class AccessImpl implements Access { private String token; private Identity identity; private boolean canEdit; + private boolean versionControlled; private boolean canClose; private VFSMetadata vfsMetadata; @@ -74,6 +75,15 @@ public class AccessImpl implements Access { this.canEdit = canEdit; } + @Override + public boolean isVersionControlled() { + return versionControlled; + } + + public void setVersionControlled(boolean versionControlled) { + this.versionControlled = versionControlled; + } + @Override public boolean canClose() { return canClose;