diff --git a/src/main/java/org/olat/course/assessment/portfolio/EfficiencyStatementMediaHandler.java b/src/main/java/org/olat/course/assessment/portfolio/EfficiencyStatementMediaHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..4dce652bdcb46f075d4307bcf6b32064fb424543 --- /dev/null +++ b/src/main/java/org/olat/course/assessment/portfolio/EfficiencyStatementMediaHandler.java @@ -0,0 +1,80 @@ +package org.olat.course.assessment.portfolio; + +import org.olat.core.commons.services.image.Size; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.id.Identity; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.xml.XStreamHelper; +import org.olat.course.assessment.EfficiencyStatement; +import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementController; +import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.handler.AbstractMediaHandler; +import org.olat.modules.portfolio.manager.MediaDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.thoughtworks.xstream.XStream; + +/** + * + * Initial date: 24.06.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class EfficiencyStatementMediaHandler extends AbstractMediaHandler { + + private static final OLog log = Tracing.createLoggerFor(EfficiencyStatementMediaHandler.class); + private static final XStream myXStream = XStreamHelper.createXStreamInstance(); + + public static final String EFF_MEDIA = "EfficiencyStatement"; + + @Autowired + private MediaDAO mediaDao; + + public EfficiencyStatementMediaHandler() { + super(EFF_MEDIA); + } + + @Override + public String getIconCssClass(Media media) { + return "o_icon_certificate"; + } + + @Override + public VFSLeaf getThumbnail(Media media, Size size) { + return null; + } + + @Override + public Media createMedia(String title, String description, Object mediaObject, String businessPath, Identity author) { + Media media = null; + if (mediaObject instanceof EfficiencyStatement){ + EfficiencyStatement statement = (EfficiencyStatement) mediaObject; + String xml = myXStream.toXML(statement); + media = mediaDao.createMedia(title, description, xml, EFF_MEDIA, businessPath, 90, author); + } + return media; + } + + @Override + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { + String statementXml = media.getContent(); + EfficiencyStatement statement = null; + if(StringHelper.containsNonWhitespace(statementXml)) { + try { + statement = (EfficiencyStatement)myXStream.fromXML(statementXml); + } catch (Exception e) { + log.error("Cannot load efficiency statement from artefact", e); + } + } + CertificateAndEfficiencyStatementController ctrl = new CertificateAndEfficiencyStatementController(wControl, ureq, statement); + ctrl.disableMediaCollector(); + return ctrl; + } +} diff --git a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java index e413091da4cf7a70d5efe5cffd208152d7e03bc6..0ee17572c936cd80a64f421d0c016ada152502c6 100644 --- a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java +++ b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementController.java @@ -64,12 +64,15 @@ import org.olat.course.assessment.IdentityAssessmentOverviewController; import org.olat.course.assessment.manager.EfficiencyStatementManager; import org.olat.course.assessment.model.AssessmentNodeData; import org.olat.course.assessment.portfolio.EfficiencyStatementArtefact; +import org.olat.course.assessment.portfolio.EfficiencyStatementMediaHandler; import org.olat.course.certificate.Certificate; import org.olat.course.certificate.CertificatesManager; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.group.model.SearchBusinessGroupParams; import org.olat.modules.co.ContactFormController; +import org.olat.modules.portfolio.PortfolioV2Module; +import org.olat.modules.portfolio.ui.component.MediaCollectorComponent; import org.olat.portfolio.EPArtefactHandler; import org.olat.portfolio.PortfolioModule; import org.olat.portfolio.model.artefacts.AbstractArtefact; @@ -110,6 +113,10 @@ public class CertificateAndEfficiencyStatementController extends BasicController private CertificateController certificateCtrl; private IdentityAssessmentOverviewController courseDetailsCtrl; + @Autowired + private EfficiencyStatementMediaHandler mediaHandler; + @Autowired + private PortfolioV2Module portfolioV2Module; @Autowired private PortfolioModule portfolioModule; @Autowired @@ -188,10 +195,17 @@ public class CertificateAndEfficiencyStatementController extends BasicController } if(efficiencyStatement != null && statementOwner.equals(ureq.getIdentity())) { - EPArtefactHandler<?> artHandler = portfolioModule.getArtefactHandler(EfficiencyStatementArtefact.ARTEFACT_TYPE); - if(portfolioModule.isEnabled() && artHandler != null && artHandler.isEnabled()) { - collectArtefactLink = LinkFactory.createCustomLink("collectArtefactLink", "collectartefact", "", Link.NONTRANSLATED, mainVC, this); - collectArtefactLink.setIconLeftCSS("o_icon o_icon-lg o_icon_eportfolio_add"); + if(portfolioV2Module.isEnabled()) { + String businessPath = "[RepositoryEntry:" + efficiencyStatement.getCourseRepoEntryKey() + "]"; + MediaCollectorComponent collectorCmp = new MediaCollectorComponent("collectArtefactLink", getWindowControl(), efficiencyStatement, + mediaHandler, businessPath); + mainVC.put("collectArtefactLink", collectorCmp); + } else { + EPArtefactHandler<?> artHandler = portfolioModule.getArtefactHandler(EfficiencyStatementArtefact.ARTEFACT_TYPE); + if(portfolioModule.isEnabled() && artHandler != null && artHandler.isEnabled()) { + collectArtefactLink = LinkFactory.createCustomLink("collectArtefactLink", "collectartefact", "", Link.NONTRANSLATED, mainVC, this); + collectArtefactLink.setIconLeftCSS("o_icon o_icon-lg o_icon_eportfolio_add"); + } } } @@ -208,6 +222,13 @@ public class CertificateAndEfficiencyStatementController extends BasicController protected void doDispose() { // } + + public void disableMediaCollector() { + Component component = mainVC.getComponent("collectArtefactLink"); + if(component != null) { + mainVC.remove(component); + } + } private void populateAssessedIdentityInfos(UserRequest ureq, RepositoryEntry courseRepo, BusinessGroup group, boolean links) { if(efficiencyStatement != null) { diff --git a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java index b0d74972cdb6a87568ff61d8e60d1f92b5d14635..e4608bb100d5d3fb47e8ce82ae9c6d46e1be3e6a 100644 --- a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java +++ b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java @@ -46,6 +46,7 @@ import org.olat.core.gui.components.stack.BreadcrumbPanelAware; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.gui.render.Renderer; @@ -64,11 +65,14 @@ import org.olat.course.assessment.bulk.PassedCellRenderer; import org.olat.course.assessment.manager.EfficiencyStatementManager; import org.olat.course.assessment.model.UserEfficiencyStatementLight; import org.olat.course.assessment.portfolio.EfficiencyStatementArtefact; +import org.olat.course.assessment.portfolio.EfficiencyStatementMediaHandler; import org.olat.course.certificate.CertificateEvent; import org.olat.course.certificate.CertificateLight; import org.olat.course.certificate.CertificatesManager; import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement; import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementListModel.Cols; +import org.olat.modules.portfolio.PortfolioV2Module; +import org.olat.modules.portfolio.ui.wizard.CollectArtefactController; import org.olat.portfolio.EPArtefactHandler; import org.olat.portfolio.PortfolioModule; import org.olat.portfolio.model.artefacts.AbstractArtefact; @@ -91,12 +95,15 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo private static final String CMD_LAUNCH_COURSE = "cmd.launch.course"; private static final String CMD_DELETE = "cmd.delete"; private static final String CMD_ARTEFACT = "cmd.artefact"; + private static final String CMD_MEDIA = "cmd.MEDIA"; private FlexiTableElement tableEl; private BreadcrumbPanel stackPanel; private FormLink coachingToolButton; private CertificateAndEfficiencyStatementListModel tableModel; + private CloseableModalController cmc; + private CollectArtefactController collectorCtrl; private DialogBoxController confirmDeleteCtr; private ArtefactWizzardStepsController ePFCollCtrl; @@ -108,11 +115,15 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo @Autowired private PortfolioModule portfolioModule; @Autowired + private PortfolioV2Module portfolioV2Module; + @Autowired private RepositoryManager repositoryManager; @Autowired private RepositoryService repositoryService; @Autowired private CertificatesManager certificatesManager; + @Autowired + private EfficiencyStatementMediaHandler mediaHandler; public CertificateAndEfficiencyStatementListController(UserRequest ureq, WindowControl wControl) { this(ureq, wControl, ureq.getUserSession().getIdentity(), false); @@ -188,12 +199,18 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.delete", translate("table.action.delete"), CMD_DELETE)); - //delete - EPArtefactHandler<?> artHandler = portfolioModule.getArtefactHandler(EfficiencyStatementArtefact.ARTEFACT_TYPE); - if(portfolioModule.isEnabled() && artHandler != null && artHandler.isEnabled() && assessedIdentity.equals(getIdentity())) { + //artefact + if(portfolioV2Module.isEnabled()) { tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.artefact", - Cols.efficiencyStatement.ordinal(), CMD_ARTEFACT, - new StaticFlexiCellRenderer(CMD_ARTEFACT, new AsArtefactCellRenderer()))); + Cols.efficiencyStatement.ordinal(), CMD_MEDIA, + new StaticFlexiCellRenderer(CMD_MEDIA, new AsArtefactCellRenderer()))); + } else { + EPArtefactHandler<?> artHandler = portfolioModule.getArtefactHandler(EfficiencyStatementArtefact.ARTEFACT_TYPE); + if(portfolioModule.isEnabled() && artHandler != null && artHandler.isEnabled() && assessedIdentity.equals(getIdentity())) { + tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.artefact", + Cols.efficiencyStatement.ordinal(), CMD_ARTEFACT, + new StaticFlexiCellRenderer(CMD_ARTEFACT, new AsArtefactCellRenderer()))); + } } tableModel = new CertificateAndEfficiencyStatementListModel(tableColumnModel, getLocale()); @@ -260,6 +277,8 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo doShowStatement(ureq, statement); } else if(CMD_ARTEFACT.equals(cmd)) { doCollectArtefact(ureq, statement.getDisplayName(), statement.getEfficiencyStatementKey()); + } else if(CMD_MEDIA.equals(cmd)) { + doCollectMedia(ureq, statement.getDisplayName(), statement.getEfficiencyStatementKey()); } } } else if(coachingToolButton == source) { @@ -275,9 +294,21 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo CertificateAndEfficiencyStatement statement = (CertificateAndEfficiencyStatement)confirmDeleteCtr.getUserObject(); doDelete(statement.getEfficiencyStatementKey()); } + } else if(collectorCtrl == source) { + cmc.deactivate(); + cleanUp(); + } else if(cmc == source) { + cleanUp(); } } + private void cleanUp() { + removeAsListenerAndDispose(collectorCtrl); + removeAsListenerAndDispose(cmc); + collectorCtrl = null; + cmc = null; + } + private void doShowStatement(UserRequest ureq, CertificateAndEfficiencyStatement statement) { RepositoryEntry entry = repositoryService.loadByResourceKey(statement.getResourceKey()); EfficiencyStatement efficiencyStatment = esm.getUserEfficiencyStatementByKey(statement.getEfficiencyStatementKey()); @@ -344,6 +375,17 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo } } + private void doCollectMedia(UserRequest ureq, String title, Long efficiencyStatementKey) { + EfficiencyStatement fullStatement = esm.getUserEfficiencyStatementByKey(efficiencyStatementKey); + + collectorCtrl = new CollectArtefactController(ureq, getWindowControl(), fullStatement, mediaHandler, ""); + listenTo(this); + + cmc = new CloseableModalController(getWindowControl(), null, collectorCtrl.getInitialComponent(), true, title, true); + cmc.addControllerListener(this); + cmc.activate(); + } + public class AsArtefactCellRenderer implements FlexiCellRenderer { @Override diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioFileStorage.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioFileStorage.java index d0c76eafd22d28a1c8c426e6d2ab393e58f05146..a3ec17f7e8efca5167900b6422f77daa041f210d 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioFileStorage.java +++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioFileStorage.java @@ -24,6 +24,8 @@ import java.nio.file.Path; import java.util.UUID; import org.olat.core.commons.modules.bc.FolderConfig; +import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl; +import org.olat.core.util.vfs.VFSContainer; import org.olat.modules.portfolio.Media; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Service; @@ -83,6 +85,10 @@ public class PortfolioFileStorage implements InitializingBean { return dir; } + public VFSContainer getMediaContainer(Media media) { + return new OlatRootFolderImpl("/" + media.getStoragePath(), null); + } + public File generateMediaSubDirectory(Media media) { File subDirectory = generateMediaSubDirectory(); return new File(subDirectory, media.getKey().toString()); diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java index 31090bcf14310e5a20b1d874fb3fa7a4e3e2a06f..7ffc5c788e12756d0a0aad0ff30ef60dbe38bc41 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java @@ -112,7 +112,7 @@ public class BinderPageListController extends AbstractPageListController { } PageRow pageRow = forgeRow(page, sectionToAssessmentSectionMap.get(section), first); rows.add(pageRow); - if(section != null + if(secCallback.canAddPage() && section != null && section.getSectionStatus() != SectionStatus.closed && section.getSectionStatus() != SectionStatus.submitted) { FormLink newEntryButton = uifactory.addFormLink("new.entry." + (++counter), "new.entry", "create.new.page", null, flc, Link.BUTTON); @@ -125,7 +125,7 @@ public class BinderPageListController extends AbstractPageListController { for(Section section:sections) { PageRow pageRow = forgeRow(section, sectionToAssessmentSectionMap.get(section), true); rows.add(pageRow); - if(section != null + if(secCallback.canAddPage() && section != null && section.getSectionStatus() != SectionStatus.closed && section.getSectionStatus() != SectionStatus.submitted) { FormLink newEntryButton = uifactory.addFormLink("new.entry." + (++counter), "new.entry", "create.new.page", null, flc, Link.BUTTON); diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html b/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html index faf960c0f61bfe76306c34d08eaec10a8a7727e3..1671dc1c0dfa0efc1934e826300ab063207f7812 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html @@ -1,5 +1,4 @@ <h2><i class="o_icon o_icon-lg $iconCssClass"> </i> $title</h2> - -<div class="clearfix"> +<div class=""> $r.render("media") </div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMedia.java b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMedia.java new file mode 100644 index 0000000000000000000000000000000000000000..17b83a671ef1fee6cd69527d1aa8fce7156f3759 --- /dev/null +++ b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMedia.java @@ -0,0 +1,29 @@ +package org.olat.modules.webFeed.portfolio; + +import org.olat.modules.webFeed.models.Feed; +import org.olat.modules.webFeed.models.Item; + +/** + * + * Initial date: 24.06.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class BlogEntryMedia { + + private final Feed feed; + private final Item item; + + public BlogEntryMedia(Feed feed, Item item) { + this.feed = feed; + this.item = item; + } + + public Feed getFeed() { + return feed; + } + + public Item getItem() { + return item; + } +} diff --git a/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaController.java b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaController.java new file mode 100644 index 0000000000000000000000000000000000000000..26081b59a04e0f6c5768d86f0d7798b89c43b046 --- /dev/null +++ b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaController.java @@ -0,0 +1,133 @@ +/** + * <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.modules.webFeed.portfolio; + +import java.io.InputStream; + +import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.date.DateComponentFactory; +import org.olat.core.gui.components.velocity.VelocityContainer; +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.util.StringHelper; +import org.olat.core.util.filter.Filter; +import org.olat.core.util.filter.FilterFactory; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSContainerMapper; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.xml.XStreamHelper; +import org.olat.modules.portfolio.Media; +import org.olat.modules.webFeed.models.Item; + +import com.thoughtworks.xstream.XStream; + +/** + * + * Description:<br> + * Read-only view for a blog entry + * + * <P> + * Initial Date: 3 déc. 2010 <br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class BlogEntryMediaController extends BasicController { + + private static final XStream xstream = XStreamHelper.createXStreamInstance(); + static { + xstream.alias("item", Item.class); + } + + public BlogEntryMediaController(UserRequest ureq, WindowControl wControl, Media media, boolean readOnlyMode) { + super(ureq, wControl); + VelocityContainer mainVC = createVelocityContainer("media_post"); + if (StringHelper.containsNonWhitespace(media.getStoragePath())) { + VFSContainer container = new OlatRootFolderImpl("/" + media.getStoragePath(), null); + VFSItem item = container.resolve(BlogArtefact.BLOG_FILE_NAME); + if(item instanceof VFSLeaf) { + VFSLeaf itemLeaf = (VFSLeaf)item; + try(InputStream in = itemLeaf.getInputStream()) { + Item blogItem = (Item)xstream.fromXML(in); + if(blogItem.getDate() != null) { + DateComponentFactory.createDateComponentWithYear("dateComp", blogItem.getDate(), mainVC); + } + + String content = blogItem.getContent(); + if (!StringHelper.containsNonWhitespace(content)) { + content = blogItem.getDescription(); + } + + mainVC.contextPut("content", content); + mainVC.contextPut("readOnlyMode", readOnlyMode); + mainVC.contextPut("item", blogItem); + + String mapperBase = registerMapper(ureq, new VFSContainerMapper(container)); + mainVC.contextPut("helper", new ItemHelper(mapperBase)); + } catch(Exception ex) { + logError("", ex); + } + } + } + putInitialPanel(mainVC); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } + + public class ItemHelper { + + private final String baseUri; + + public ItemHelper(String baseUri) { + this.baseUri = baseUri; + } + + public String getItemContentForBrowser(Item item) { + String itemContent = item.getContent(); + if (itemContent != null) { + //Add relative media base to media elements to display internal media files + Filter mediaUrlFilter = FilterFactory.getBaseURLToMediaRelativeURLFilter(baseUri); + itemContent = mediaUrlFilter.filter(itemContent); + } + return itemContent; + } + + public String getItemDescriptionForBrowser(Item item) { + String itemDescription = item.getDescription(); + if (itemDescription != null) { + //Add relative media base to media elements to display internal media files + Filter mediaUrlFilter = FilterFactory.getBaseURLToMediaRelativeURLFilter(baseUri); + itemDescription = mediaUrlFilter.filter(itemDescription); + } + return itemDescription; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaHandler.java b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..b3dda110c7930db98d49869fc72cbf24165f54de --- /dev/null +++ b/src/main/java/org/olat/modules/webFeed/portfolio/BlogEntryMediaHandler.java @@ -0,0 +1,77 @@ +package org.olat.modules.webFeed.portfolio; + +import java.io.File; + +import org.olat.core.commons.services.image.Size; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.id.Identity; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.core.util.vfs.VFSManager; +import org.olat.fileresource.types.BlogFileResource; +import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.handler.AbstractMediaHandler; +import org.olat.modules.portfolio.manager.MediaDAO; +import org.olat.modules.portfolio.manager.PortfolioFileStorage; +import org.olat.modules.webFeed.managers.FeedManager; +import org.olat.modules.webFeed.models.Feed; +import org.olat.modules.webFeed.models.Item; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 24.06.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class BlogEntryMediaHandler extends AbstractMediaHandler { + + public static final String BLOG_ENTRY_HANDLER = BlogFileResource.TYPE_NAME; + + @Autowired + private MediaDAO mediaDao; + @Autowired + private FeedManager feedManager; + @Autowired + private PortfolioFileStorage fileStorage; + + public BlogEntryMediaHandler() { + super(BLOG_ENTRY_HANDLER); + } + + @Override + public String getIconCssClass(Media media) { + return "o_blog_icon"; + } + + @Override + public VFSLeaf getThumbnail(Media media, Size size) { + return null; + } + + @Override + public Media createMedia(String title, String description, Object mediaObject, String businessPath, Identity author) { + BlogEntryMedia entry = (BlogEntryMedia)mediaObject; + Feed feed = entry.getFeed(); + Item item = entry.getItem(); + + Media media = mediaDao.createMedia(title, description, "", BLOG_ENTRY_HANDLER, businessPath, 70, author); + File mediaDir = fileStorage.generateMediaSubDirectory(media); + String storagePath = fileStorage.getRelativePath(mediaDir); + media = mediaDao.updateStoragePath(media, storagePath); + VFSContainer mediaContainer = fileStorage.getMediaContainer(media); + VFSContainer itemContainer = feedManager.getItemContainer(item, feed); + VFSManager.copyContent(itemContainer, mediaContainer); + + return media; + } + + @Override + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { + return new BlogEntryMediaController(ureq, wControl, media, true); + } +} diff --git a/src/main/java/org/olat/modules/webFeed/portfolio/_content/media_post.html b/src/main/java/org/olat/modules/webFeed/portfolio/_content/media_post.html new file mode 100644 index 0000000000000000000000000000000000000000..d0b29b86cbdcdd37073105a2d0490a351788b3e4 --- /dev/null +++ b/src/main/java/org/olat/modules/webFeed/portfolio/_content/media_post.html @@ -0,0 +1,27 @@ +<div class="o_feed"><div class="o_post"> + <div class="o_block_with_datecomp clearfix"> + <div class="o_head o_block_large clearfix"> + #if($r.available("dateComp")) + $r.render("dateComp") + #end + <h3 class="o_title">$r.escapeHtml($item.getTitle())</h3> + <div class="o_meta"> + #set ( $info = $helper.getInfo($item) ) + #if ( $info ) + $info + #if($helper.isModified($item)), + <div class="text-warning">$r.escapeHtml($helper.getModifierInfo($item))</div> + #end + #end + </div> + </div> + <div class="o_content o_user_content_block"> + $!helper.getItemDescriptionForBrowser($item) + #if ($item.getContent() && $item.getContent() != "") + <div class="o_block_large_top"> + $!helper.getItemContentForBrowser($item) + </div> + #end + </div> + </div> +</div></div> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java b/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java index 7ce99ded690ebf0e0cddcb3f691185a6a9a2e417..3a272e0814e304d3bb8191d4013dcdbae7db780a 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java +++ b/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java @@ -61,15 +61,20 @@ import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.CodeHelper; import org.olat.core.util.coordinate.LockResult; import org.olat.core.util.vfs.VFSContainer; +import org.olat.modules.portfolio.PortfolioV2Module; +import org.olat.modules.portfolio.ui.component.MediaCollectorComponent; import org.olat.modules.webFeed.FeedSecurityCallback; import org.olat.modules.webFeed.FeedViewHelper; import org.olat.modules.webFeed.managers.FeedManager; import org.olat.modules.webFeed.models.Feed; import org.olat.modules.webFeed.models.Item; import org.olat.modules.webFeed.models.ItemPublishDateComparator; +import org.olat.modules.webFeed.portfolio.BlogEntryMedia; +import org.olat.modules.webFeed.portfolio.BlogEntryMediaHandler; import org.olat.portfolio.EPUIFactory; import org.olat.user.UserManager; import org.olat.util.logging.activity.LoggingResourceable; +import org.springframework.beans.factory.annotation.Autowired; /** * This class is responsible for dealing with items. For internal podcasts, @@ -108,7 +113,12 @@ public class ItemsController extends BasicController implements Activateable2 { public static Event HANDLE_NEW_EXTERNAL_FEED_DIALOG_EVENT = new Event("cmd.handle.new.external.feed.dialog"); public static Event FEED_INFO_IS_DIRTY_EVENT = new Event("cmd.feed.info.is.dirty"); - private final UserManager userManager; + @Autowired + private UserManager userManager; + @Autowired + private PortfolioV2Module portfolioModule; + @Autowired + private BlogEntryMediaHandler blogMediaHandler; /** * default constructor, with full FeedItemDisplayConfig @@ -140,7 +150,6 @@ public class ItemsController extends BasicController implements Activateable2 { final FeedSecurityCallback callback, final VelocityContainer vcRightColumn, FeedItemDisplayConfig displayConfig) { super(ureq, wControl); - userManager = CoreSpringFactory.getImpl(UserManager.class); if (displayConfig == null) { displayConfig = new FeedItemDisplayConfig(true, true, true); } @@ -226,7 +235,7 @@ public class ItemsController extends BasicController implements Activateable2 { addItemButton.setElementCssClass("o_sel_feed_item_new"); if (items != null) { for (Item item : items) { - createButtonsForItem(ureq, item); + createButtonsForItem(ureq, feed, item); } } } else if (feed.isUndefined()) { @@ -341,7 +350,7 @@ public class ItemsController extends BasicController implements Activateable2 { /** * @param item */ - private void createButtonsForItem(UserRequest ureq, Item item) { + private void createButtonsForItem(UserRequest ureq, Feed feed, Item item) { boolean author = getIdentity().getKey().equals(item.getAuthorKey()); boolean edit = callback.mayEditItems() || author; boolean delete = callback.mayDeleteItems() || author; @@ -362,10 +371,18 @@ public class ItemsController extends BasicController implements Activateable2 { if(feedResource.isInternal() && getIdentity().getKey() != null && getIdentity().getKey().equals(item.getAuthorKey())) { String businessPath = BusinessControlFactory.getInstance().getAsString(getWindowControl().getBusinessControl()); businessPath += "[item=" + item.getGuid() + ":0]"; - Controller artefactCtrl = EPUIFactory.createArtefactCollectWizzardController(ureq, getWindowControl(), feedResource, businessPath); - if(artefactCtrl != null) { - artefactLinks.put(item, artefactCtrl); - vcItems.put("feed.artefact.item.".concat(guid), artefactCtrl.getInitialComponent()); + + if(portfolioModule.isEnabled()) { + String name = "feed.artefact.item.".concat(guid); + BlogEntryMedia media = new BlogEntryMedia(feed, item); + MediaCollectorComponent collectorCmp = new MediaCollectorComponent(name, getWindowControl(), media, blogMediaHandler, businessPath); + vcItems.put(name, collectorCmp); + } else { + Controller artefactCtrl = EPUIFactory.createArtefactCollectWizzardController(ureq, getWindowControl(), feedResource, businessPath); + if(artefactCtrl != null) { + artefactLinks.put(item, artefactCtrl); + vcItems.put("feed.artefact.item.".concat(guid), artefactCtrl.getInitialComponent()); + } } } @@ -619,7 +636,7 @@ public class ItemsController extends BasicController implements Activateable2 { } if(feed != null) { - createButtonsForItem(ureq, currentItem); + createButtonsForItem(ureq, feed, currentItem); createItemLink(currentItem); // Add date component String guid = currentItem.getGuid(); diff --git a/src/main/java/org/olat/modules/wiki/WikiMainController.java b/src/main/java/org/olat/modules/wiki/WikiMainController.java index 7d7d94773d1f780f495b1d0601f6bd32d5937ac5..0e980c67fa89744cbfa984e790cd7d1d09a42e2d 100644 --- a/src/main/java/org/olat/modules/wiki/WikiMainController.java +++ b/src/main/java/org/olat/modules/wiki/WikiMainController.java @@ -96,6 +96,8 @@ import org.olat.modules.fo.Forum; import org.olat.modules.fo.ForumCallback; import org.olat.modules.fo.manager.ForumManager; import org.olat.modules.fo.ui.ForumController; +import org.olat.modules.portfolio.PortfolioV2Module; +import org.olat.modules.portfolio.ui.component.MediaCollectorComponent; import org.olat.modules.wiki.gui.components.wikiToHtml.ErrorEvent; import org.olat.modules.wiki.gui.components.wikiToHtml.FilterUtil; import org.olat.modules.wiki.gui.components.wikiToHtml.RequestImageEvent; @@ -104,12 +106,14 @@ import org.olat.modules.wiki.gui.components.wikiToHtml.RequestNewPageEvent; import org.olat.modules.wiki.gui.components.wikiToHtml.RequestPageEvent; import org.olat.modules.wiki.gui.components.wikiToHtml.WikiMarkupComponent; import org.olat.modules.wiki.portfolio.WikiArtefact; +import org.olat.modules.wiki.portfolio.WikiMediaHandler; import org.olat.modules.wiki.versioning.ChangeInfo; import org.olat.modules.wiki.versioning.HistoryTableDateModel; import org.olat.portfolio.EPUIFactory; import org.olat.search.SearchServiceUIFactory; import org.olat.search.SearchServiceUIFactory.DisplayOption; import org.olat.util.logging.activity.LoggingResourceable; +import org.springframework.beans.factory.annotation.Autowired; @@ -154,6 +158,7 @@ public class WikiMainController extends BasicController implements CloneableCont private Controller searchCtrl; private WikiArticleSearchForm createArticleForm; private CloseableCalloutWindowController calloutCtrl; + private CloseableModalController cmc; private StackedPanel mainPanel; private Dropdown wikiMenuDropdown, navigationDropdown, breadcrumpDropdown; @@ -175,8 +180,10 @@ public class WikiMainController extends BasicController implements CloneableCont // indicates if user is already on image-detail-view-page (OLAT-6233) private boolean isImageDetailView = false; - - private CloseableModalController cmc; + @Autowired + private WikiMediaHandler wikiMediaHandler; + @Autowired + private PortfolioV2Module portfolioModule; public WikiMainController(UserRequest ureq, WindowControl wControl, OLATResourceable ores, WikiSecurityCallback securityCallback, String initialPageName) { @@ -1157,12 +1164,17 @@ public class WikiMainController extends BasicController implements CloneableCont String subPath = page.getPageName(); String businessPath = getWindowControl().getBusinessControl().getAsString(); businessPath += "[page=" + subPath + ":0]"; - OLATResourceable wikiRes = OresHelper.createOLATResourceableInstance(WikiArtefact.ARTEFACT_TYPE, ores.getResourceableId()); - Controller ePFCollCtrl = EPUIFactory.createArtefactCollectWizzardController(ureq, getWindowControl(), wikiRes, businessPath); - if (ePFCollCtrl != null) { - navigationContent.put("portfolio-link", ePFCollCtrl.getInitialComponent()); - } + + if(portfolioModule.isEnabled()) { + MediaCollectorComponent collectorCmp = new MediaCollectorComponent("portfolio-link", getWindowControl(), page, wikiMediaHandler, businessPath); + navigationContent.put("portfolio-link", collectorCmp); + } else { + Controller ePFCollCtrl = EPUIFactory.createArtefactCollectWizzardController(ureq, getWindowControl(), wikiRes, businessPath); + if (ePFCollCtrl != null) { + navigationContent.put("portfolio-link", ePFCollCtrl.getInitialComponent()); + } + } } else { clearPortfolioLink(); } diff --git a/src/main/java/org/olat/modules/wiki/_spring/wikiContext.xml b/src/main/java/org/olat/modules/wiki/_spring/wikiContext.xml index e061bbf6fd44a81e1edaa38b53a622659c74d656..6f010a27ce7a58533c7741f6a57f70027f82152f 100644 --- a/src/main/java/org/olat/modules/wiki/_spring/wikiContext.xml +++ b/src/main/java/org/olat/modules/wiki/_spring/wikiContext.xml @@ -4,14 +4,14 @@ xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + http://www.springframework.org/schema/context/spring-context.xsd"> -<bean id="wikiManger" class="org.olat.modules.wiki.WikiManager"> - <property name="coordinator" ref="coordinatorManager"></property> - <property name="fileResourceManager" ref="fileresourceManager"></property> - <property name="resourceManager" ref="resourceManager"></property> -</bean> + <bean id="wikiManger" class="org.olat.modules.wiki.WikiManager"> + <property name="coordinator" ref="coordinatorManager"></property> + <property name="fileResourceManager" ref="fileresourceManager"></property> + <property name="resourceManager" ref="resourceManager"></property> + </bean> </beans> \ No newline at end of file diff --git a/src/main/java/org/olat/modules/wiki/portfolio/WikiMediaHandler.java b/src/main/java/org/olat/modules/wiki/portfolio/WikiMediaHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..dc41eb4f004de425e82f5242fc9da7e59353207e --- /dev/null +++ b/src/main/java/org/olat/modules/wiki/portfolio/WikiMediaHandler.java @@ -0,0 +1,65 @@ +package org.olat.modules.wiki.portfolio; + +import org.olat.core.commons.services.image.Size; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.id.Identity; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.fileresource.types.WikiResource; +import org.olat.modules.portfolio.Media; +import org.olat.modules.portfolio.handler.AbstractMediaHandler; +import org.olat.modules.portfolio.manager.MediaDAO; +import org.olat.modules.wiki.WikiPage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 24.06.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class WikiMediaHandler extends AbstractMediaHandler { + + public static final String WIKI_HANDLER = WikiResource.TYPE_NAME; + + @Autowired + private MediaDAO mediaDao; + + public WikiMediaHandler() { + super(WIKI_HANDLER); + } + + @Override + public String getIconCssClass(Media media) { + return "o_wiki_icon"; + } + + @Override + public VFSLeaf getThumbnail(Media media, Size size) { + return null; + } + + @Override + public Media createMedia(String title, String description, Object mediaObject, String businessPath, Identity author) { + String content = null; + if(mediaObject instanceof WikiPage) { + WikiPage page = (WikiPage)mediaObject; + content = page.getContent(); + } + + Media media = mediaDao.createMedia(title, description, content, WIKI_HANDLER, businessPath, 70, author); + + return media; + } + + @Override + public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) { + return new WikiPageMediaController(ureq, wControl, media); + } + + + +} diff --git a/src/main/java/org/olat/modules/wiki/portfolio/WikiPageMediaController.java b/src/main/java/org/olat/modules/wiki/portfolio/WikiPageMediaController.java new file mode 100644 index 0000000000000000000000000000000000000000..283c5d8c114109690040b390292380aa4d0cf52e --- /dev/null +++ b/src/main/java/org/olat/modules/wiki/portfolio/WikiPageMediaController.java @@ -0,0 +1,112 @@ +/** + * <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.modules.wiki.portfolio; + +import java.util.Locale; + +import org.jamwiki.DataHandler; +import org.jamwiki.model.Topic; +import org.jamwiki.model.WikiFile; +import org.jamwiki.parser.AbstractParser; +import org.jamwiki.parser.ParserDocument; +import org.jamwiki.parser.ParserInput; +import org.jamwiki.parser.jflex.JFlexParser; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.velocity.VelocityContainer; +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.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.filter.FilterFactory; +import org.olat.modules.portfolio.Media; + +/** + * + * Initial date: 24.06.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class WikiPageMediaController extends BasicController { + + private static final OLog log = Tracing.createLoggerFor(WikiPageMediaController.class); + + public WikiPageMediaController(UserRequest ureq, WindowControl wControl, Media media) { + super(ureq, wControl); + + VelocityContainer mainVC = createVelocityContainer("details"); + String wikiText = getContent(media.getContent()); + mainVC.contextPut("text", wikiText); + putInitialPanel(mainVC); + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } + + @Override + protected void doDispose() { + // + } + + private static String getContent(String content) { + try { + ParserInput input = new ParserInput(); + input.setWikiUser(null); + input.setAllowSectionEdit(false); + input.setDepth(2); + input.setContext(""); + input.setLocale(Locale.ENGLISH); + input.setTopicName("dummy"); + input.setUserIpAddress("0.0.0.0"); + input.setDataHandler(new DummyDataHandler()); + input.setVirtualWiki("/olat"); + + AbstractParser parser = new JFlexParser(input); + ParserDocument parsedDoc = parser.parseHTML(content); + String parsedContent = parsedDoc.getContent(); + return FilterFactory.getHtmlTagAndDescapingFilter().filter(parsedContent); + } catch(Exception e) { + log.error("", e); + return content; + } + } + + public static class DummyDataHandler implements DataHandler { + + @Override + public boolean exists(String virtualWiki, String topic) { + return true; + } + + @Override + public Topic lookupTopic(String virtualWiki, String topicName, boolean deleteOK, Object transactionObject) throws Exception { + return null; + } + + @Override + public WikiFile lookupWikiFile(String virtualWiki, String topicName) throws Exception { + return null; + } + } +} +