diff --git a/src/main/java/org/olat/modules/portfolio/CategoryToElement.java b/src/main/java/org/olat/modules/portfolio/CategoryToElement.java new file mode 100644 index 0000000000000000000000000000000000000000..e5c18f2104bcd54f090eb49bb4e4763347a2ed76 --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/CategoryToElement.java @@ -0,0 +1,36 @@ +/** + * <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.portfolio; + +import org.olat.core.id.OLATResourceable; + +/** + * + * Initial date: 29.06.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface CategoryToElement { + + public Category getCategory(); + + public OLATResourceable getCategorizedResource(); + +} diff --git a/src/main/java/org/olat/modules/portfolio/Page.java b/src/main/java/org/olat/modules/portfolio/Page.java index 674b60d918b2d48e0d2b7ac395f9951ece30e6d2..336e2782bb8713ab8e22be4fd8c0ca31ac89c657 100644 --- a/src/main/java/org/olat/modules/portfolio/Page.java +++ b/src/main/java/org/olat/modules/portfolio/Page.java @@ -33,6 +33,10 @@ public interface Page extends PortfolioElement { public PageStatus getPageStatus(); + public Date getInitialPublicationDate(); + + public Date getLastPublicationDate(); + public void setTitle(String title); public String getSummary(); diff --git a/src/main/java/org/olat/modules/portfolio/PortfolioElement.java b/src/main/java/org/olat/modules/portfolio/PortfolioElement.java index 093acb329d1e0a8630da5b675ef24b9bf32759e6..08717659186e913dee70b40f7706899dc1521618 100644 --- a/src/main/java/org/olat/modules/portfolio/PortfolioElement.java +++ b/src/main/java/org/olat/modules/portfolio/PortfolioElement.java @@ -40,5 +40,6 @@ public interface PortfolioElement { public Group getBaseGroup(); public PortfolioElementType getType(); + } diff --git a/src/main/java/org/olat/modules/portfolio/PortfolioService.java b/src/main/java/org/olat/modules/portfolio/PortfolioService.java index b54745d764e734266cea8ceca5313b8b1fc2e11d..8c06067303ea611e75d3775dec27ef2770ceb2c8 100644 --- a/src/main/java/org/olat/modules/portfolio/PortfolioService.java +++ b/src/main/java/org/olat/modules/portfolio/PortfolioService.java @@ -130,6 +130,7 @@ public interface PortfolioService { /** * Check if this template is used, has some copies. + * * @param template * @param courseEntry * @param subIdent @@ -143,6 +144,7 @@ public interface PortfolioService { /** * The list of owners of the binder. + * * @param binder * @param roles At least a role need to be specified * @return @@ -157,9 +159,34 @@ public interface PortfolioService { public void changeAccessRights(List<Identity> identities, List<AccessRightChange> changes); - public List<Category> getCategories(Binder binder); + public List<Category> getCategories(PortfolioElement element); + + /** + * Get the categories of the sections and pages under the specified binder. + * + * @param binder + * @return + */ + public List<CategoryToElement> getCategorizedSectionsAndPages(BinderRef binder); + + /** + * Get the categories of the section and the pages under the specified section. + * + * @param section + * @return + */ + public List<CategoryToElement> getCategorizedSectionAndPages(SectionRef section); + + /** + * Get the categories of the pages that the specified user owned. + * + * @param owner + * @return + */ + public List<CategoryToElement> getCategorizedOwnedPages(IdentityRef owner); + - public void updateCategories(Binder binder, List<String> categories); + public void updateCategories(PortfolioElement element, List<String> categories); public File getPosterImageFile(BinderLight binder); diff --git a/src/main/java/org/olat/modules/portfolio/handler/TextHandler.java b/src/main/java/org/olat/modules/portfolio/handler/TextHandler.java index 96c3dd41c16b8821460f151c19b90a3db37bec62..2aa8d0db682a73206b6586280d9f1da529ba9a27 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/TextHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/TextHandler.java @@ -24,12 +24,14 @@ 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.StringHelper; import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaInformations; import org.olat.modules.portfolio.MediaLight; import org.olat.modules.portfolio.manager.MediaDAO; import org.olat.modules.portfolio.ui.media.TextMediaController; +import org.olat.portfolio.manager.EPFrontendManager; import org.olat.portfolio.model.artefacts.AbstractArtefact; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -47,6 +49,8 @@ public class TextHandler extends AbstractMediaHandler { @Autowired private MediaDAO mediaDao; + @Autowired + private EPFrontendManager oldPortfolioManager; public TextHandler() { super(TEXT_MEDIA); @@ -78,6 +82,10 @@ public class TextHandler extends AbstractMediaHandler { String title = artefact.getTitle(); String description = artefact.getDescription(); String content = artefact.getFulltextContent(); + if(!StringHelper.containsNonWhitespace(content)) { + content = oldPortfolioManager.getArtefactFullTextContent(artefact); + } + String businessPath = artefact.getBusinessPath(); if(businessPath == null) { businessPath = "[PortfolioV2:0][MediaCenter:0]"; diff --git a/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java b/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java index 4f5ef667657e29fae608cb18abaed9ca4ad0fd20..8257fd3a009cd7740ec3a5626edf1dbb6c287e94 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java +++ b/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java @@ -195,6 +195,11 @@ public class BinderDAO { .getResultList(); } + /** + * The same type of query is user for the categories + * @param owner + * @return + */ public List<BinderRow> searchOwnedBinders(IdentityRef owner) { StringBuilder sb = new StringBuilder(); sb.append("select binder.key, binder.title, binder.imagePath, binder.lastModified, binder.status,") diff --git a/src/main/java/org/olat/modules/portfolio/manager/CategoryDAO.java b/src/main/java/org/olat/modules/portfolio/manager/CategoryDAO.java index 60f750acb3692f782febc61c42caf8c54365535d..fab4b9deb049bef765842d7aba169a066fc7fa60 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/CategoryDAO.java +++ b/src/main/java/org/olat/modules/portfolio/manager/CategoryDAO.java @@ -22,9 +22,14 @@ package org.olat.modules.portfolio.manager; import java.util.Date; import java.util.List; +import org.olat.basesecurity.GroupRoles; +import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.DB; import org.olat.core.id.OLATResourceable; +import org.olat.modules.portfolio.BinderRef; import org.olat.modules.portfolio.Category; +import org.olat.modules.portfolio.CategoryToElement; +import org.olat.modules.portfolio.SectionRef; import org.olat.modules.portfolio.model.CategoryImpl; import org.olat.modules.portfolio.model.CategoryToElementImpl; import org.springframework.beans.factory.annotation.Autowired; @@ -87,5 +92,53 @@ public class CategoryDAO { .setParameter("resId", ores.getResourceableId()) .getResultList(); } + + public List<CategoryToElement> getCategorizedSectionsAndPages(BinderRef binder) { + StringBuilder sb = new StringBuilder(); + sb.append("select rel from pfcategoryrelation as rel") + .append(" inner join fetch rel.category as category") + .append(" where exists (select binder from pfbinder as binder") + .append(" inner join binder.sections as section") + .append(" inner join section.pages as page") + .append(" where binder.key=:binderKey") + .append(" and ((rel.resId=page.key and rel.resName='Page') or (rel.resId=section.key and rel.resName='Section'))") + .append(" )"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), CategoryToElement.class) + .setParameter("binderKey", binder.getKey()) + .getResultList(); + } + + public List<CategoryToElement> getCategorizedSectionAndPages(SectionRef section) { + StringBuilder sb = new StringBuilder(); + sb.append("select rel from pfcategoryrelation as rel") + .append(" inner join fetch rel.category as category") + .append(" where exists (select section from pfsection as section") + .append(" inner join section.pages as page") + .append(" where section.key=:sectionKey") + .append(" and ((rel.resId=page.key and rel.resName='Page') or (rel.resId=section.key and rel.resName='Section'))") + .append(" )"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), CategoryToElement.class) + .setParameter("sectionKey", section.getKey()) + .getResultList(); + } + + public List<CategoryToElement> getCategorizedOwnedPages(IdentityRef identity) { + StringBuilder sb = new StringBuilder(); + sb.append("select rel from pfcategoryrelation as rel") + .append(" inner join fetch rel.category as category") + .append(" inner join pfpage as page on (rel.resId=page.key and rel.resName='Page')") + .append(" left join pfsection as section on (section.key = page.section.key)") + .append(" left join pfbinder as binder on (binder.key=section.binder.key)") + .append(" where exists (select pageMember from bgroupmember as pageMember") + .append(" inner join pageMember.identity as ident on (ident.key=:ownerKey and pageMember.role='").append(GroupRoles.owner.name()).append("')") + .append(" where pageMember.group.key=page.baseGroup.key or pageMember.group.key=binder.baseGroup.key") + .append(" )"); + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), CategoryToElement.class) + .setParameter("ownerKey", identity.getKey()) + .getResultList(); + } } diff --git a/src/main/java/org/olat/modules/portfolio/manager/PageDAO.java b/src/main/java/org/olat/modules/portfolio/manager/PageDAO.java index f2aef4fb6c62e450d0ef8a62436e465661ddf371..99e52da416981d4405166391d77874650787de53 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/PageDAO.java +++ b/src/main/java/org/olat/modules/portfolio/manager/PageDAO.java @@ -147,7 +147,7 @@ public class PageDAO { .append(" left join section.binder as binder") .append(" where exists (select pageMember from bgroupmember as pageMember") .append(" inner join pageMember.identity as ident on (ident.key=:ownerKey and pageMember.role='").append(GroupRoles.owner.name()).append("')") - .append(" where pageMember.group.key=page.baseGroup.key or pageMember.group.key=binder.baseGroup.key or pageMember.group.key=page.baseGroup.key") + .append(" where pageMember.group.key=page.baseGroup.key or pageMember.group.key=binder.baseGroup.key") .append(" )"); List<Page> pages = dbInstance.getCurrentEntityManager() diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java index b3a658cc62a2b3f8e35742a9526fac8f2175708f..57f968b785f9ed09638236f7229ffb68b11608f1 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java +++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java @@ -59,6 +59,7 @@ import org.olat.modules.portfolio.Binder; import org.olat.modules.portfolio.BinderLight; import org.olat.modules.portfolio.BinderRef; import org.olat.modules.portfolio.Category; +import org.olat.modules.portfolio.CategoryToElement; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaHandler; import org.olat.modules.portfolio.MediaLight; @@ -330,16 +331,40 @@ public class PortfolioServiceImpl implements PortfolioService { } @Override - public List<Category> getCategories(Binder binder) { - OLATResourceable ores = OresHelper.createOLATResourceableInstance(Binder.class, binder.getKey()); + public List<Category> getCategories(PortfolioElement element) { + OLATResourceable ores = getOLATResoucreable(element); return categoryDao.getCategories(ores); } @Override - public void updateCategories(Binder binder, List<String> categories) { - OLATResourceable ores = OresHelper.createOLATResourceableInstance(Binder.class, binder.getKey()); + public List<CategoryToElement> getCategorizedSectionsAndPages(BinderRef binder) { + return categoryDao.getCategorizedSectionsAndPages(binder); + } + + @Override + public List<CategoryToElement> getCategorizedSectionAndPages(SectionRef section) { + return categoryDao.getCategorizedSectionAndPages(section); + } + + @Override + public List<CategoryToElement> getCategorizedOwnedPages(IdentityRef owner) { + return categoryDao.getCategorizedOwnedPages(owner); + } + + @Override + public void updateCategories(PortfolioElement element, List<String> categories) { + OLATResourceable ores = getOLATResoucreable(element); updateCategories(ores, categories); } + + private OLATResourceable getOLATResoucreable(PortfolioElement element) { + switch(element.getType()) { + case binder: return OresHelper.createOLATResourceableInstance(Binder.class, element.getKey()); + case section: return OresHelper.createOLATResourceableInstance(Section.class, element.getKey()); + case page: return OresHelper.createOLATResourceableInstance(Page.class, element.getKey()); + default: return null; + } + } private void updateCategories(OLATResourceable oresource, List<String> categories) { List<Category> currentCategories = categoryDao.getCategories(oresource); @@ -536,6 +561,13 @@ public class PortfolioServiceImpl implements PortfolioService { public Page changePageStatus(Page page, PageStatus status) { Page reloadedPage = pageDao.loadByKey(page.getKey()); ((PageImpl)reloadedPage).setPageStatus(status); + if(status == PageStatus.published) { + Date now = new Date(); + if(reloadedPage.getInitialPublicationDate() == null) { + ((PageImpl)reloadedPage).setInitialPublicationDate(now); + } + ((PageImpl)reloadedPage).setLastPublicationDate(now); + } return pageDao.updatePage(reloadedPage); } diff --git a/src/main/java/org/olat/modules/portfolio/model/CategoryToElementImpl.java b/src/main/java/org/olat/modules/portfolio/model/CategoryToElementImpl.java index 8bc403094087292bc50f2c1ce5c6e5e4847a97b8..f77dadf10ba9b0b02a7b5ad0d9092002bddf71d1 100644 --- a/src/main/java/org/olat/modules/portfolio/model/CategoryToElementImpl.java +++ b/src/main/java/org/olat/modules/portfolio/model/CategoryToElementImpl.java @@ -32,10 +32,14 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import javax.persistence.Transient; import org.olat.core.id.CreateInfo; +import org.olat.core.id.OLATResourceable; import org.olat.core.id.Persistable; +import org.olat.core.util.resource.OresHelper; import org.olat.modules.portfolio.Category; +import org.olat.modules.portfolio.CategoryToElement; /** * @@ -47,7 +51,7 @@ import org.olat.modules.portfolio.Category; */ @Entity(name="pfcategoryrelation") @Table(name="o_pf_category_relation") -public class CategoryToElementImpl implements Persistable, CreateInfo { +public class CategoryToElementImpl implements CategoryToElement, Persistable, CreateInfo { private static final long serialVersionUID = -5196328449832113662L; @@ -104,6 +108,7 @@ public class CategoryToElementImpl implements Persistable, CreateInfo { this.resId = resId; } + @Override public Category getCategory() { return category; } @@ -111,6 +116,12 @@ public class CategoryToElementImpl implements Persistable, CreateInfo { public void setCategory(Category category) { this.category = category; } + + @Override + @Transient + public OLATResourceable getCategorizedResource() { + return OresHelper.createOLATResourceableInstance(resName, resId); + } @Override public int hashCode() { diff --git a/src/main/java/org/olat/modules/portfolio/model/PageImpl.java b/src/main/java/org/olat/modules/portfolio/model/PageImpl.java index e8670ba2435f4be5b2eb4777a421fefee647d6ea..71db3a5536cafd23e698bd588bce78a8facb399a 100644 --- a/src/main/java/org/olat/modules/portfolio/model/PageImpl.java +++ b/src/main/java/org/olat/modules/portfolio/model/PageImpl.java @@ -69,7 +69,7 @@ public class PageImpl implements Persistable, ModifiedInfo, CreateInfo, Page { @Temporal(TemporalType.TIMESTAMP) @Column(name="lastmodified", nullable=false, insertable=true, updatable=true) private Date lastModified; - + /** Only used for order by */ @GeneratedValue @Column(name="pos") @@ -161,6 +161,24 @@ public class PageImpl implements Persistable, ModifiedInfo, CreateInfo, Page { public void setStatus(String status) { this.status = status; } + + @Override + public Date getInitialPublicationDate() { + return initialPublicationDate; + } + + public void setInitialPublicationDate(Date initialPublicationDate) { + this.initialPublicationDate = initialPublicationDate; + } + + @Override + public Date getLastPublicationDate() { + return lastPublicationDate; + } + + public void setLastPublicationDate(Date lastPublicationDate) { + this.lastPublicationDate = lastPublicationDate; + } @Override public String getTitle() { diff --git a/src/main/java/org/olat/modules/portfolio/model/PageRow.java b/src/main/java/org/olat/modules/portfolio/model/PageRow.java index e8189febdb60783101d0673cc79f5a801be6540b..433ba7100da4800325867a157bc022bef55e905b 100644 --- a/src/main/java/org/olat/modules/portfolio/model/PageRow.java +++ b/src/main/java/org/olat/modules/portfolio/model/PageRow.java @@ -19,6 +19,7 @@ */ package org.olat.modules.portfolio.model; +import java.util.Collection; import java.util.Date; import org.olat.core.gui.components.form.flexible.elements.FormLink; @@ -44,6 +45,9 @@ public class PageRow { private boolean firstPageOfSection; private final AssessmentSection assessmentSection; + private Collection<String> pageCategories; + private Collection<String> sectionCategories; + private Link openLink; private FormLink openFormLink; private FormLink newEntryLink; @@ -81,6 +85,14 @@ public class PageRow { return page.getLastModified(); } + public boolean hasLastPublicationDate() { + return page != null && page.getLastPublicationDate() != null; + } + + public Date getLastPublicationDate() { + return page.getLastPublicationDate(); + } + public String getCssClassStatus() { return page.getPageStatus() == null ? PageStatus.draft.cssClass() : page.getPageStatus().cssClass(); @@ -133,6 +145,30 @@ public class PageRow { this.firstPageOfSection = firstPageOfSection; } + public boolean hasPageCategories() { + return pageCategories != null && pageCategories.size() > 0; + } + + public Collection<String> getPageCategories() { + return pageCategories; + } + + public void setPageCategories(Collection<String> pageCategories) { + this.pageCategories = pageCategories; + } + + public boolean hasSectionCategories() { + return sectionCategories != null && sectionCategories.size() > 0; + } + + public Collection<String> getSectionCategories() { + return sectionCategories; + } + + public void setSectionCategories(Collection<String> sectionCategories) { + this.sectionCategories = sectionCategories; + } + public boolean isAssessable() { return assessable; } diff --git a/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java index 7eed82582d9a9714e46380d9d573a6af1eaaa1a6..702c2c34beee439bae268e20454c0dd699c12dfe 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/AbstractPageListController.java @@ -19,7 +19,9 @@ */ package org.olat.modules.portfolio.ui; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; @@ -44,12 +46,15 @@ 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.dtabs.Activateable2; +import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; import org.olat.core.util.StringHelper; +import org.olat.core.util.resource.OresHelper; import org.olat.modules.portfolio.AssessmentSection; import org.olat.modules.portfolio.BinderConfiguration; import org.olat.modules.portfolio.BinderSecurityCallback; +import org.olat.modules.portfolio.Category; import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.Section; @@ -133,7 +138,9 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate { protected abstract void loadModel(); - protected PageRow forgeRow(Page page, AssessmentSection assessmentSection, boolean firstOfSection) { + protected PageRow forgeRow(Page page, AssessmentSection assessmentSection, boolean firstOfSection, + Map<OLATResourceable,List<Category>> categorizedElementMap) { + PageRow row = new PageRow(page, page.getSection(), assessmentSection, firstOfSection, config.isAssessable()); String openLinkId = "open_" + (++counter); FormLink openLink = uifactory.addFormLink(openLinkId, "open.full", "open.full.page", null, flc, Link.BUTTON_SMALL); @@ -141,10 +148,13 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate { openLink.setPrimary(true); row.setOpenFormLink(openLink); openLink.setUserObject(row); + addCategoriesToRow(row, categorizedElementMap); return row; } - protected PageRow forgeRow(Section section, AssessmentSection assessmentSection, boolean firstOfSection) { + protected PageRow forgeRow(Section section, AssessmentSection assessmentSection, boolean firstOfSection, + Map<OLATResourceable,List<Category>> categorizedElementMap) { + PageRow row = new PageRow(null, section, assessmentSection, firstOfSection, config.isAssessable()); String openLinkId = "open_" + (++counter); FormLink openLink = uifactory.addFormLink(openLinkId, "open.full", "open.full.page", null, flc, Link.BUTTON_SMALL); @@ -152,9 +162,33 @@ implements Activateable2, TooledController, FlexiTableComponentDelegate { openLink.setPrimary(true); row.setOpenFormLink(openLink); openLink.setUserObject(row); + addCategoriesToRow(row, categorizedElementMap); return row; } + private void addCategoriesToRow(PageRow row, Map<OLATResourceable,List<Category>> categorizedElementMap) { + if(categorizedElementMap != null) { + if(row.getPage() != null) { + OLATResourceable ores = OresHelper.createOLATResourceableInstance(Page.class, row.getPage().getKey()); + row.setPageCategories(getCategories(ores, categorizedElementMap)); + } + } + } + + private List<String> getCategories(OLATResourceable ores, Map<OLATResourceable,List<Category>> categorizedElementMap) { + List<String> strings = null; + List<Category> categories = categorizedElementMap.get(ores); + if(categories != null && categories.size() > 0) { + strings = new ArrayList<>(categories.size()); + for(Category category:categories) { + strings.add(category.getName()); + } + } + return strings; + } + + + @Override public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { // 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 7ffc5c788e12756d0a0aad0ff30ef60dbe38bc41..d90121326dc753b3b1f9a2573d81b41ce2e06e9b 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/BinderPageListController.java @@ -21,8 +21,10 @@ package org.olat.modules.portfolio.ui; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.UserRequest; @@ -40,10 +42,13 @@ 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.id.OLATResourceable; import org.olat.modules.portfolio.AssessmentSection; import org.olat.modules.portfolio.Binder; import org.olat.modules.portfolio.BinderConfiguration; import org.olat.modules.portfolio.BinderSecurityCallback; +import org.olat.modules.portfolio.Category; +import org.olat.modules.portfolio.CategoryToElement; import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.Section; import org.olat.modules.portfolio.SectionStatus; @@ -96,6 +101,18 @@ public class BinderPageListController extends AbstractPageListController { protected void loadModel() { List<Section> sections = portfolioService.getSections(binder); + List<CategoryToElement> categorizedElements = portfolioService.getCategorizedSectionsAndPages(binder); + Map<OLATResourceable,List<Category>> categorizedElementMap = new HashMap<>(); + Map<Section,Set<String>> sectionAggregatedCategoriesMap = new HashMap<>(); + for(CategoryToElement categorizedElement:categorizedElements) { + List<Category> categories = categorizedElementMap.get(categorizedElement.getCategorizedResource()); + if(categories == null) { + categories = new ArrayList<>(); + categorizedElementMap.put(categorizedElement.getCategorizedResource(), categories); + } + categories.add(categorizedElement.getCategory()); + } + List<AssessmentSection> assessmentSections = portfolioService.getAssessmentSections(binder, getIdentity()); Map<Section,AssessmentSection> sectionToAssessmentSectionMap = new HashMap<>(); for(AssessmentSection assessmentSection:assessmentSections) { @@ -110,7 +127,7 @@ public class BinderPageListController extends AbstractPageListController { if (sections.remove(section)) { first = true; } - PageRow pageRow = forgeRow(page, sectionToAssessmentSectionMap.get(section), first); + PageRow pageRow = forgeRow(page, sectionToAssessmentSectionMap.get(section), first, categorizedElementMap); rows.add(pageRow); if(secCallback.canAddPage() && section != null && section.getSectionStatus() != SectionStatus.closed @@ -120,10 +137,24 @@ public class BinderPageListController extends AbstractPageListController { newEntryButton.setUserObject(pageRow); pageRow.setNewEntryLink(newEntryButton); } + + if(section != null) { + Set<String> categories = sectionAggregatedCategoriesMap.get(section); + if(categories == null) { + categories = new HashSet<>(); + sectionAggregatedCategoriesMap.put(section, categories); + } + if(pageRow.hasPageCategories()) { + categories.addAll(pageRow.getPageCategories()); + } + + pageRow.setSectionCategories(categories); + } } + //sections without pages for(Section section:sections) { - PageRow pageRow = forgeRow(section, sectionToAssessmentSectionMap.get(section), true); + PageRow pageRow = forgeRow(section, sectionToAssessmentSectionMap.get(section), true, categorizedElementMap); rows.add(pageRow); if(secCallback.canAddPage() && section != null && section.getSectionStatus() != SectionStatus.closed diff --git a/src/main/java/org/olat/modules/portfolio/ui/MyPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/MyPageListController.java index 94f708d8876ed4ac9ad3b00722cc43ce3b7ec828..3b1b8b271b416451b7dea82677313f6e30ede047 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/MyPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/MyPageListController.java @@ -20,7 +20,9 @@ package org.olat.modules.portfolio.ui; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; @@ -32,8 +34,11 @@ 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.id.OLATResourceable; import org.olat.modules.portfolio.BinderConfiguration; import org.olat.modules.portfolio.BinderSecurityCallback; +import org.olat.modules.portfolio.Category; +import org.olat.modules.portfolio.CategoryToElement; import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.model.PageRow; @@ -67,10 +72,21 @@ public class MyPageListController extends AbstractPageListController { @Override protected void loadModel() { + List<CategoryToElement> categorizedElements = portfolioService.getCategorizedOwnedPages(getIdentity()); + Map<OLATResourceable,List<Category>> categorizedElementMap = new HashMap<>(); + for(CategoryToElement categorizedElement:categorizedElements) { + List<Category> categories = categorizedElementMap.get(categorizedElement.getCategorizedResource()); + if(categories == null) { + categories = new ArrayList<>(); + categorizedElementMap.put(categorizedElement.getCategorizedResource(), categories); + } + categories.add(categorizedElement.getCategory()); + } + List<Page> pages = portfolioService.searchOwnedPages(getIdentity()); List<PageRow> rows = new ArrayList<>(pages.size()); for (Page page : pages) { - rows.add(forgeRow(page, null, false)); + rows.add(forgeRow(page, null, false, categorizedElementMap)); } model.setObjects(rows); tableEl.reset(); diff --git a/src/main/java/org/olat/modules/portfolio/ui/PageController.java b/src/main/java/org/olat/modules/portfolio/ui/PageController.java index 432b20df6ccadb07b9410dbf000e7b909f720b7b..a621d2ac3d1c5d1c9eb9aed35ee88c74978651d9 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/PageController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/PageController.java @@ -154,6 +154,7 @@ public class PageController extends BasicController implements TooledController } else if(editMetadataCtrl == source) { if(event == Event.DONE_EVENT) { loadModel(ureq); + fireEvent(ureq, Event.CHANGED_EVENT); } cmc.deactivate(); cleanUp(); diff --git a/src/main/java/org/olat/modules/portfolio/ui/PageMetadataEditController.java b/src/main/java/org/olat/modules/portfolio/ui/PageMetadataEditController.java index 28f9e8d2f7f513d1fc1e94e2d67189222f6be11d..597cd285642aa59c3f9fe1f68c0904525f1daa42 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/PageMetadataEditController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/PageMetadataEditController.java @@ -20,8 +20,10 @@ package org.olat.modules.portfolio.ui; import java.io.File; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.olat.core.gui.UserRequest; @@ -29,6 +31,7 @@ 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.SingleSelection; +import org.olat.core.gui.components.form.flexible.elements.TextBoxListElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; @@ -39,6 +42,7 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; import org.olat.modules.portfolio.Binder; +import org.olat.modules.portfolio.Category; import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.Section; @@ -64,6 +68,7 @@ public class PageMetadataEditController extends FormBasicController { private TextElement titleEl, summaryEl; private SingleSelection bindersEl, sectionsEl; + private TextBoxListElement categoriesEl; private FileElement fileUpload; private static final int picUploadlimitKB = 5120; @@ -74,6 +79,9 @@ public class PageMetadataEditController extends FormBasicController { private final boolean chooseBinder; private final boolean chooseSection; + + private Map<String,String> categories = new HashMap<>(); + private Map<String,Category> categoriesMap = new HashMap<>(); @Autowired private PortfolioService portfolioService; @@ -104,6 +112,14 @@ public class PageMetadataEditController extends FormBasicController { this.chooseBinder = chooseBinder; this.chooseSection = chooseSection; + if(page != null) { + List<Category> tags = portfolioService.getCategories(page); + for(Category tag:tags) { + categories.put(tag.getName(), tag.getName()); + categoriesMap.put(tag.getName(), tag); + } + } + initForm(ureq); } @@ -176,6 +192,10 @@ public class PageMetadataEditController extends FormBasicController { bindersEl.setEnabled(false); } + categoriesEl = uifactory.addTextBoxListElement("categories", "categories", "categories.hint", categories, formLayout, getTranslator()); + categoriesEl.setElementCssClass("o_sel_ep_tagsinput"); + categoriesEl.setAllowDuplicates(false); + //list of sections if(chooseSection) { retrieveSections(formLayout, true); @@ -272,7 +292,7 @@ public class PageMetadataEditController extends FormBasicController { imagePath = portfolioService.addPosterImageForPage(fileUpload.getUploadFile(), fileUpload.getUploadFileName()); } - portfolioService.appendNewPage(getIdentity(), title, summary, imagePath, selectSection); + page = portfolioService.appendNewPage(getIdentity(), title, summary, imagePath, selectSection); } else { page.setTitle(titleEl.getValue()); page.setSummary(summaryEl.getValue()); @@ -294,6 +314,9 @@ public class PageMetadataEditController extends FormBasicController { } page = portfolioService.updatePage(page, newParent); } + + List<String> updatedCategories = categoriesEl.getValueList(); + portfolioService.updateCategories(page, updatedCategories); fireEvent(ureq, Event.DONE_EVENT); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/SectionEditController.java b/src/main/java/org/olat/modules/portfolio/ui/SectionEditController.java index 96ecbd70635ce2c329b4cb41fa44a202c6fd6305..1bb773c574f4a43bf052ac63d49b2c7141bbe501 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/SectionEditController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/SectionEditController.java @@ -129,6 +129,7 @@ public class SectionEditController extends FormBasicController { reloadedSection.setEndDate(endDateEl.getDate()); section = portfolioService.updateSection(reloadedSection); } + fireEvent(ureq, Event.DONE_EVENT); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/SectionPageListController.java b/src/main/java/org/olat/modules/portfolio/ui/SectionPageListController.java index ea0ff1461025efe60531f62225e0a57fbbf496c2..2a56976099bf857710348bb04225fc608a71b391 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/SectionPageListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/SectionPageListController.java @@ -20,7 +20,11 @@ package org.olat.modules.portfolio.ui; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; @@ -32,10 +36,13 @@ 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.id.OLATResourceable; import org.olat.modules.portfolio.AssessmentSection; import org.olat.modules.portfolio.Binder; import org.olat.modules.portfolio.BinderConfiguration; import org.olat.modules.portfolio.BinderSecurityCallback; +import org.olat.modules.portfolio.Category; +import org.olat.modules.portfolio.CategoryToElement; import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.Section; import org.olat.modules.portfolio.model.PageRow; @@ -76,6 +83,19 @@ public class SectionPageListController extends AbstractPageListController { @Override protected void loadModel() { + List<CategoryToElement> categorizedElements = portfolioService.getCategorizedSectionAndPages(section); + Map<OLATResourceable,List<Category>> categorizedElementMap = new HashMap<>(); + Set<String> sectionAggregatedCategories = new HashSet<>(); + for(CategoryToElement categorizedElement:categorizedElements) { + List<Category> categories = categorizedElementMap.get(categorizedElement.getCategorizedResource()); + if(categories == null) { + categories = new ArrayList<>(); + categorizedElementMap.put(categorizedElement.getCategorizedResource(), categories); + } + categories.add(categorizedElement.getCategory()); + sectionAggregatedCategories.add(categorizedElement.getCategory().getName()); + } + AssessmentSection assessmentSection = null; List<AssessmentSection> assessmentSections = portfolioService.getAssessmentSections(binder, getIdentity()); for(AssessmentSection aSection:assessmentSections) { @@ -88,7 +108,9 @@ public class SectionPageListController extends AbstractPageListController { List<PageRow> rows = new ArrayList<>(); boolean first = true; for (Page page : pages) { - rows.add(forgeRow(page, assessmentSection, first)); + PageRow row = forgeRow(page, assessmentSection, first, categorizedElementMap); + row.setSectionCategories(sectionAggregatedCategories); + rows.add(row); first = false; } model.setObjects(rows); diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/page_row.html b/src/main/java/org/olat/modules/portfolio/ui/_content/page_row.html index c53ba61c12b53f3367a3ac28876a5ac94181eeb5..ad4a905185b04b86b3cc814b42fd36a0daa2dc03 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_content/page_row.html +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/page_row.html @@ -19,6 +19,18 @@ <div class="o_section_lead o_block_large_bottom"> <p>$r.xssScan($row.sectionDescription)</p> </div> + + #if(${row.hasSectionCategories()}) + <div class="o_block_large_bottom"> + <div class="o_portfolio_page_meta text-muted o_small"> + $r.translate("meta.section.categories") <i class="o_icon o_icon_tags"> </i> + #foreach($category in $row.sectionCategories) + #if(${foreach.count} > 1), #end + $category + #end + </div> + </div> + #end </div> #if(${row.hasNewEntryLink()}) @@ -42,9 +54,23 @@ <i class="o_icon ${row.getCssClassStatus()} o_icon-fw"> </i> $r.escapeHtml($row.title) </h4> - <div class="o_portfolio_page_meta text-muted o_small"> + #if(${row.hasLastPublicationDate()}) + <span class="o_portfolio_page_meta text-muted o_small"> + $r.translate("meta.last.publication", $r.formatDateAndTime($row.lastPublicationDate)) + </span> + #end + #if(${row.hasPageCategories()}) + <span class="o_portfolio_page_meta text-muted o_small"> + $r.translate("meta.categories") <i class="o_icon o_icon_tags"> </i> + #foreach($category in $row.pageCategories) + #if(${foreach.count} > 1), #end + $category + #end + </span> + #end + <span class="o_portfolio_page_meta text-muted o_small"> $r.translate("meta.last.modified", $r.formatDateAndTime($row.lastModified)) - </div> + </span> <div class="o_portfolio_page_summary o_block"> $r.xssScan($row.summary) </div> diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties index c07bdb81b00ce5c3faec62d048631ca3c73a35d3..00ba8391ce9dc1589e418b95b3d324f1cc013cd4 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties @@ -44,6 +44,7 @@ create.new.binder.descr=Erstellen Sie eine portfolio Mappe um Ihre Eintr\u00E4ge create.new.binder.title=Neue Mappe erstellen create.new.page=Neuer Eintrag erstellen create.new.page.tite=Neuer Eintrag erstellen +create.new.page.descr=Neuer Eintrag erstellen create.new.section=Neuer Bereich erstellen create.new.section.text=Erstellen Sie einen neuen Bereich in der Portfolio Mappe um Ihre Eintr\u00E4ge zu organisieren. create.new.section.title=Neuer Bereich hinzuf\u00FCgen @@ -83,7 +84,10 @@ map.passed=$org.olat.course.assessment\:map.passed map.returnDate=$org.olat.course.nodes.portfolio\:map.returnDate media.center=Mediencenter media.center.text=Hier k\u00F6nnen Sie Mediendateien, Dokumente oder andere Artefakte hinzuf\u00FCgen. Verwenden Sie die Medien um Ihre Eintr\u00E4ge zu illustrieren und zu erg\u00E4nzen. +meta.categories=Kategorien meta.last.modified=zuletzt bearbeitet am {0} +meta.last.publication=ver\u00F6ffentlich am {0} +meta.section.categories=<strong>Kategorien</strong> in diesem Bereich my.entries=Meine Beitr\u00E4ge my.entries.text=Liste aller Beitr\u00E4ge in chronologischer Reihenfolge unabh\u00E4ngig von ihrem Kontext. Dies ist das Herzst\u00FCck Ihrer Portfolioarbeit. my.portfolio.binders=Meine Portfolio Mappen diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties index 20bc48097e77fdc0d0f77f5d5e59e841ccbba253..4377beef4a1b37cb107a9104de7ae28c8b31e406 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties @@ -71,8 +71,6 @@ invitation.mail.subject=Invitation to a binder already released invitation.mail.body=You have been invited by {1} to have a look at a binder in OpenOLAT. Please go to\: {0} invitation.mail.success=The persons invited have been notified successfully via e-mail. invitation.mail.failure=Error while sending your e-mail. The persons invited could not be notified. Please try again later or contact your support team. - - lastName=Last name mail=E-Mail map.available=$org.olat.course.nodes.portfolio\:map.available @@ -85,9 +83,12 @@ map.not.passed=$org.olat.course.assessment\:map.not.passed map.not.rated.yet=$org.olat.course.assessment\:map.not.rated.yet map.passed=$org.olat.course.assessment\:map.passed map.returnDate=$org.olat.course.nodes.portfolio\:map.returnDate +meta.categories=Categories media.center=Media center media.center.text=Search, create, add media files or other artefacts that you want to use within your entries for illustration purpose. meta.last.modified=last modified {0} +meta.last.publication=published at {0} +meta.section.categories=<strong>Categories</strong> in this section my.entries=My entries my.entries.text=List all your portfolio entries regardless of their context. This is the heart of your portfolio work. my.portfolio.binders=My portfolio binders