diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java index 4e626e6ab5c3819318fe916bb942130b866f809e..1a5248e61c50412ecfaf5378c9a7203c73a3c592 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java +++ b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java @@ -71,6 +71,14 @@ public interface VFSRepositoryService { public List<VFSMetadata> getMostDownloaded(VFSMetadata ancestorMetadata, int maxResults); + /** + * + * @param ancestorMetadata + * @param maxResults + * @return + */ + public List<VFSMetadata> getNewest(VFSMetadata ancestorMetadata, int maxResults); + public void itemSaved(VFSLeaf leaf); public VFSMetadata updateMetadata(VFSMetadata data); diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java index 6c2ad14c641776e1bb34a89fc7ba299d53b74bfd..289683fc95706d64336e8aa855a788ecb327d5bd 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java +++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java @@ -288,6 +288,11 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv return metadataDao.getMetadatas(parentMetadata); } + @Override + public List<VFSMetadata> getNewest(VFSMetadata ancestorMetadata, int maxResults) { + return metadataDao.getNewest(ancestorMetadata.getRelativePath(), maxResults); + } + @Override public List<VFSMetadata> getMostDownloaded(VFSMetadata ancestorMetadata, int maxResults) { return metadataDao.getMostDownloaded(ancestorMetadata.getRelativePath(), maxResults); diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSMetadataMediaResource.java b/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSMetadataMediaResource.java new file mode 100644 index 0000000000000000000000000000000000000000..219aa9530fc64618a5b0e1f6392d223eeb1afb57 --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSMetadataMediaResource.java @@ -0,0 +1,56 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.vfs.ui.media; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.commons.services.vfs.VFSMetadata; +import org.olat.core.commons.services.vfs.VFSRepositoryService; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.VFSMediaResource; + +/** + * + * Initial date: 5 avr. 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class VFSMetadataMediaResource extends VFSMediaResource { + + private final VFSMetadata metadata; + + public VFSMetadataMediaResource(VFSMetadata metadata) { + super(null); + this.metadata = metadata; + } + + @Override + public VFSLeaf getLeaf() { + VFSLeaf leaf = super.getLeaf(); + if(leaf == null) { + VFSItem revFile = CoreSpringFactory.getImpl(VFSRepositoryService.class).getItemFor(metadata); + if(revFile instanceof VFSLeaf) { + leaf = (VFSLeaf)revFile; + setLeaf(leaf); + } + } + return leaf; + } +} diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSRevisionMediaResource.java b/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSRevisionMediaResource.java index 37d507113f3c575ee571007c2a43f009ffc1e282..ba110d5c055d591c7c5f40a0339d2ec7d4efe2e7 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSRevisionMediaResource.java +++ b/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSRevisionMediaResource.java @@ -50,7 +50,6 @@ public class VFSRevisionMediaResource implements MediaResource { private static final String MIME_TYPE_OCTET_STREAM = "application/octet-stream"; private static final OLog log = Tracing.createLoggerFor(VFSRevisionMediaResource.class); - private String encoding; private final VFSRevision revision; private final VFSMetadata metadata; @@ -74,11 +73,6 @@ public class VFSRevisionMediaResource implements MediaResource { String mimeType = WebappHelper.getMimeType(metadata.getFilename()); if (mimeType == null) { mimeType = MIME_TYPE_OCTET_STREAM; - } else { - // if any encoding is set, append it for the browser - if (encoding != null) { - mimeType = mimeType + ";charset=" + encoding; - } } return mimeType; } diff --git a/src/main/java/org/olat/core/gui/components/download/DownloadComponent.java b/src/main/java/org/olat/core/gui/components/download/DownloadComponent.java index 94dd7ff2968613ee44f16a07cb582cd8feaafbb1..0f07ff3f92a6e8a11d839c8cf6c108e1c4272827 100644 --- a/src/main/java/org/olat/core/gui/components/download/DownloadComponent.java +++ b/src/main/java/org/olat/core/gui/components/download/DownloadComponent.java @@ -97,6 +97,24 @@ public class DownloadComponent extends AbstractComponent { this.setDomReplacementWrapperRequired(false); } + /** + * @param name The component name + * @param downloadItem The resource to download + * @param linkText An optional link text + * @param linkToolTip An optional tool tip + * @param linkCssIconClass An optional icon class + */ + public DownloadComponent(String name, MediaResource downloadItem, String linkText, + String linkToolTip, String linkCssIconClass) { + super(name); + setMediaResource(downloadItem); + setLinkText(linkText); + setLinkToolTip(linkToolTip); + setLinkCssIconClass(linkCssIconClass); + // renderer puts dispatch ID in a tag + this.setDomReplacementWrapperRequired(false); + } + public DownloadLink getFormItem() { return delegate; } diff --git a/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java b/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java index 57b49b50dfd699ddd8c84b222de8ecd3db4c8aa2..23c533ba75d415b24ada09cb331921995e994ae4 100644 --- a/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java +++ b/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java @@ -58,12 +58,20 @@ public class VFSMediaResource implements MediaResource { public boolean acceptRanges() { return true; } + + public VFSLeaf getLeaf() { + return vfsLeaf; + } + + public void setLeaf(VFSLeaf vfsLeaf) { + this.vfsLeaf = vfsLeaf; + } @Override public String getContentType() { String mimeType; if(downloadable) { - mimeType = WebappHelper.getMimeType(vfsLeaf.getName()); + mimeType = WebappHelper.getMimeType(getLeaf().getName()); //html, xhtml and javascript are set to force download if (mimeType == null || "text/html".equals(mimeType) || "application/xhtml+xml".equals(mimeType) @@ -75,7 +83,7 @@ public class VFSMediaResource implements MediaResource { mimeType = mimeType + ";charset=" + encoding; } } else { - mimeType = WebappHelper.getMimeType(vfsLeaf.getName()); + mimeType = WebappHelper.getMimeType(getLeaf().getName()); if (mimeType == null) { mimeType = MIME_TYPE_OCTET_STREAM; unknownMimeType = true; @@ -92,27 +100,24 @@ public class VFSMediaResource implements MediaResource { @Override public Long getSize() { - long size = vfsLeaf.getSize(); - return (size == VFSConstants.UNDEFINED) ? null : new Long(size); + long size = getLeaf().getSize(); + return (size == VFSConstants.UNDEFINED) ? null : Long.valueOf(size); } @Override public InputStream getInputStream() { - return vfsLeaf.getInputStream(); + return getLeaf().getInputStream(); } @Override public Long getLastModified() { - long lastModified = vfsLeaf.getLastModified(); - return (lastModified == VFSConstants.UNDEFINED) ? null : new Long(lastModified); + long lastModified = getLeaf().getLastModified(); + return (lastModified == VFSConstants.UNDEFINED) ? null : Long.valueOf(lastModified); } - /** - * @see org.olat.core.gui.media.MediaResource#prepare(javax.servlet.http.HttpServletResponse) - */ @Override public void prepare(HttpServletResponse hres) { - String filename = StringHelper.urlEncodeUTF8(vfsLeaf.getName()); + String filename = StringHelper.urlEncodeUTF8(getLeaf().getName()); if (unknownMimeType || downloadable) { hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + filename); } else { diff --git a/src/main/java/org/olat/course/nodes/bc/BCPeekviewController.java b/src/main/java/org/olat/course/nodes/bc/BCPeekviewController.java index 4ebf880e84eb9df57f9c766b1b72a74b4783dd25..9bf9ea2bfa480d8adce06530d5dc916b1e3361f3 100644 --- a/src/main/java/org/olat/course/nodes/bc/BCPeekviewController.java +++ b/src/main/java/org/olat/course/nodes/bc/BCPeekviewController.java @@ -24,9 +24,10 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.FolderModule; -import org.olat.core.commons.modules.bc.components.FolderComponent; +import org.olat.core.commons.services.vfs.VFSMetadata; +import org.olat.core.commons.services.vfs.VFSRepositoryService; +import org.olat.core.commons.services.vfs.ui.media.VFSMetadataMediaResource; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.download.DownloadComponent; @@ -39,12 +40,11 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.util.CSSHelper; -import org.olat.core.util.vfs.LocalFileImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; -import org.olat.core.util.vfs.filters.VFSItemExcludePrefixFilter; -import org.olat.core.util.vfs.filters.VFSItemFilter; +import org.olat.core.util.vfs.filters.VFSSystemItemFilter; +import org.springframework.beans.factory.annotation.Autowired; /** * <h3>Description:</h3> The folder peekview controller displays the configurable @@ -60,16 +60,17 @@ import org.olat.core.util.vfs.filters.VFSItemFilter; * @author gnaegi, gnaegi@frentix.com, www.frentix.com */ public class BCPeekviewController extends BasicController implements Controller { - // comparator to sort the messages list by creation date - private static final Comparator<VFSLeaf> dateSortingComparator = new Comparator<VFSLeaf>(){ - public int compare(final VFSLeaf leaf1, final VFSLeaf leaf2) { - return Long.valueOf(leaf2.getLastModified()).compareTo(leaf1.getLastModified()); //last first - }}; - // the current course node id + + private int count = 0; private final String nodeId; + private final boolean forceDownload; - private static final VFSItemFilter attachmentExcludeFilter = new VFSItemExcludePrefixFilter(FolderComponent.ATTACHMENT_EXCLUDE_PREFIXES); + private final VelocityContainer mainVC; + @Autowired + private FolderModule folderModule; + @Autowired + private VFSRepositoryService vfsRepositoryService; /** * Constructor @@ -82,46 +83,27 @@ public class BCPeekviewController extends BasicController implements Controller public BCPeekviewController(UserRequest ureq, WindowControl wControl, VFSContainer rootFolder, String nodeId, int itemsToDisplay) { super(ureq, wControl); this.nodeId = nodeId; - - VelocityContainer peekviewVC = createVelocityContainer("peekview"); - // add items, only as many as configured - List<VFSLeaf> allLeafs = new ArrayList<VFSLeaf>(); - addItems(rootFolder, allLeafs); - // Sort messages by last modified date - Collections.sort(allLeafs, dateSortingComparator); - boolean forceDownload = CoreSpringFactory.getImpl(FolderModule.class).isForceDownload(); + mainVC = createVelocityContainer("peekview"); + forceDownload = folderModule.isForceDownload(); - // only take the configured amount of messages - List<VFSLeaf> leafs = new ArrayList<VFSLeaf>(); - for (int i = 0; i < allLeafs.size(); i++) { - if (leafs.size() == itemsToDisplay) { - break; - } - VFSLeaf leaf = allLeafs.get(i); - leafs.add(leaf); - // add link to item - // Add link to jump to course node - if (leaf instanceof LocalFileImpl) { - DownloadComponent dlComp = new DownloadComponent("nodeLinkDL_"+(i+1), leaf, forceDownload, - leaf.getName(), translate("preview.downloadfile"), - CSSHelper.createFiletypeIconCssClassFor(leaf.getName())); - dlComp.setElementCssClass("o_gotoNode"); - peekviewVC.put("nodeLinkDL_"+(i+1),dlComp); - } else { - // hu? don't konw how to work with non-local impls - } + List<DownloadComponent> links = new ArrayList<>(itemsToDisplay); + + VFSMetadata metadata = vfsRepositoryService.getMetadataFor(rootFolder); + // don't force migration here to prevent overloading big OpenOLAT instances + if("migrated".equals(metadata.getMigrated())) { + fileMetadata(links, metadata, itemsToDisplay); + } else { + fileFallback(links, rootFolder, itemsToDisplay); } - peekviewVC.contextPut("leafs", leafs); + mainVC.contextPut("links", links); + // Add link to show all items (go to node) - Link allItemsLink = LinkFactory.createLink("peekview.allItemsLink", peekviewVC, this); + Link allItemsLink = LinkFactory.createLink("peekview.allItemsLink", mainVC, this); allItemsLink.setIconRightCSS("o_icon o_icon_start"); allItemsLink.setElementCssClass("pull-right"); - putInitialPanel(peekviewVC); + putInitialPanel(mainVC); } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ @Override protected void event(UserRequest ureq, Component source, Event event) { if (source instanceof Link) { @@ -135,13 +117,48 @@ public class BCPeekviewController extends BasicController implements Controller } } - /** - * @see org.olat.core.gui.control.DefaultController#doDispose() - */ @Override protected void doDispose() { // nothing to dispose } + + private void fileMetadata(List<DownloadComponent> links, VFSMetadata metadata, int itemsToDisplay) { + List<VFSMetadata> newestData = vfsRepositoryService.getNewest(metadata, itemsToDisplay); + for(VFSMetadata newData:newestData) { + String name = "nodeLinkDL_"+ (count++); + VFSMetadataMediaResource media = new VFSMetadataMediaResource(newData); + media.setDownloadable(forceDownload); + DownloadComponent dlComp = new DownloadComponent(name, media, newData.getFilename(), + translate("preview.downloadfile"), CSSHelper.createFiletypeIconCssClassFor(newData.getFilename())); + dlComp.setElementCssClass("o_gotoNode"); + mainVC.put(name, dlComp); + links.add(dlComp); + } + } + + private void fileFallback(List<DownloadComponent> links, VFSContainer rootFolder, int itemsToDisplay) { + List<VFSLeaf> leafs = collectFiles(rootFolder, itemsToDisplay); + for(VFSLeaf leaf:leafs) { + String name = "nodeLinkDL_"+ (count++); + DownloadComponent dlComp = new DownloadComponent(name, leaf, forceDownload, leaf.getName(), + translate("preview.downloadfile"), CSSHelper.createFiletypeIconCssClassFor(leaf.getName())); + dlComp.setElementCssClass("o_gotoNode"); + mainVC.put(name, dlComp); + links.add(dlComp); + } + } + + private List<VFSLeaf> collectFiles(VFSContainer rootFolder, int itemsToDisplay) { + // add items, only as many as configured + List<VFSLeaf> allLeafs = new ArrayList<>(); + addItems(rootFolder, allLeafs); + // Sort messages by last modified date + Collections.sort(allLeafs, new LastModifiedcomparator()); + + int size = Math.min(allLeafs.size(), itemsToDisplay); + List<VFSLeaf> lastLeafs = allLeafs.subList(0, size); + return new ArrayList<>(lastLeafs); + } /** * Private helper method to get all files in a directory. Traverses the directory tree recursively @@ -149,19 +166,20 @@ public class BCPeekviewController extends BasicController implements Controller * @param allLeafs */ private void addItems(VFSContainer container, List<VFSLeaf> allLeafs) { - // exclude files which are also excluded in FolderComponent - for (VFSItem vfsItem : container.getItems(attachmentExcludeFilter)) { + for (VFSItem vfsItem : container.getItems(new VFSSystemItemFilter())) { if (vfsItem instanceof VFSLeaf) { - // add leaf to our list - VFSLeaf leaf = (VFSLeaf) vfsItem; - allLeafs.add(leaf); + allLeafs.add((VFSLeaf)vfsItem); } else if (vfsItem instanceof VFSContainer) { - // do it recursively for all children VFSContainer childContainer = (VFSContainer) vfsItem; addItems(childContainer, allLeafs); - } else { - // hu? } } } + + private static class LastModifiedcomparator implements Comparator<VFSLeaf> { + @Override + public int compare(final VFSLeaf leaf1, final VFSLeaf leaf2) { + return Long.compare(leaf2.getLastModified(), leaf1.getLastModified()); + } + } } diff --git a/src/main/java/org/olat/course/nodes/bc/_content/peekview.html b/src/main/java/org/olat/course/nodes/bc/_content/peekview.html index 1728eb41385cdc83bc7aaec20458d0fd0825c8a1..314c512171cc94ad7d26ce24145c1008937a3fdc 100644 --- a/src/main/java/org/olat/course/nodes/bc/_content/peekview.html +++ b/src/main/java/org/olat/course/nodes/bc/_content/peekview.html @@ -1,8 +1,6 @@ <div class="o_briefcase_peekview clearfix"> -#foreach( $leaf in $leafs ) - <div class="o_briefcase_peekview_file"> - $r.render("nodeLinkDL_${foreach.count}") - </div> +#foreach($link in $links) + <div class="o_briefcase_peekview_file">$r.render($link.componentName)</div> #end - $r.render("peekview.allItemsLink") +$r.render("peekview.allItemsLink") </div> \ No newline at end of file