/** * <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.course.certificate.ui; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.olat.NewControllerFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.DateFlexiCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.stack.BreadcrumbPanel; 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; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.util.Util; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.vfs.VFSContainer; import org.olat.course.CorruptedCourseException; import org.olat.course.assessment.AssessmentModule; import org.olat.course.assessment.EfficiencyStatement; 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; import org.olat.portfolio.ui.artefacts.collect.ArtefactWizzardStepsController; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; import org.springframework.beans.factory.annotation.Autowired; /** * * Initial date: 21.10.2014<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class CertificateAndEfficiencyStatementListController extends FormBasicController implements BreadcrumbPanelAware, GenericEventListener { private static final String CMD_SHOW = "cmd.show"; 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; private final boolean linkToCoachingTool; private Identity assessedIdentity; @Autowired private EfficiencyStatementManager esm; @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); } public CertificateAndEfficiencyStatementListController(UserRequest ureq, WindowControl wControl, Identity assessedIdentity, boolean linkToCoachingTool) { super(ureq, wControl, "cert_statement_list"); setTranslator(Util.createPackageTranslator(AssessmentModule.class, getLocale(), getTranslator())); this.assessedIdentity = assessedIdentity; this.linkToCoachingTool = linkToCoachingTool; initForm(ureq); CoordinatorManager.getInstance().getCoordinator().getEventBus() .registerFor(this, getIdentity(), CertificatesManager.ORES_CERTIFICATE_EVENT); } @Override protected void doDispose() { CoordinatorManager.getInstance().getCoordinator().getEventBus() .deregisterFor(this, CertificatesManager.ORES_CERTIFICATE_EVENT); } @Override public void event(Event event) { if(event instanceof CertificateEvent) { CertificateEvent ce = (CertificateEvent)event; if(getIdentity().getKey().equals(ce.getOwnerKey())) { updateStatement(ce.getResourceKey(), ce.getCertificateKey()); } } } private void updateStatement(Long resourceKey, Long certificateKey) { List<CertificateAndEfficiencyStatement> statements = tableModel.getObjects(); for(int i=statements.size(); i-->0; ) { CertificateAndEfficiencyStatement statement = statements.get(i); if(resourceKey.equals(statement.getResourceKey())) { CertificateLight certificate = certificatesManager.getCertificateLightById(certificateKey); statement.setCertificate(certificate); break; } } } @Override public void setBreadcrumbPanel(BreadcrumbPanel stackPanel) { this.stackPanel = stackPanel; } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { if(linkToCoachingTool) { coachingToolButton = uifactory.addFormLink("coaching.tool", formLayout, Link.BUTTON); } FlexiTableColumnModel tableColumnModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.displayName)); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.score)); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.passed, new PassedCellRenderer())); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.show", translate("table.header.show"), CMD_SHOW)); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.lastModified)); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.certificate, new DownloadCertificateCellRenderer(assessedIdentity))); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.recertification, new DateFlexiCellRenderer(getLocale()))); tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.launchcourse", translate("table.header.launchcourse"), CMD_LAUNCH_COURSE)); DefaultFlexiColumnModel deleteColumn = new DefaultFlexiColumnModel(Cols.deleteEfficiencyStatement.i18nHeaderKey(), Cols.deleteEfficiencyStatement.ordinal(), CMD_DELETE, new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("table.action.delete"), CMD_DELETE), null)); tableColumnModel.addFlexiColumnModel(deleteColumn); //artefact if(portfolioV2Module.isEnabled()) { tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.artefact", 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()); loadModel(); tableEl = uifactory.addTableElement(getWindowControl(), "certificates", tableModel, getTranslator(), formLayout); tableEl.setElementCssClass("o_sel_certificates_table"); } private void loadModel() { Map<Long, CertificateAndEfficiencyStatement> resourceKeyToStatments = new HashMap<>(); List<CertificateAndEfficiencyStatement> statments = new ArrayList<>(); List<UserEfficiencyStatementLight> efficiencyStatementsList = esm.findEfficiencyStatementsLight(assessedIdentity); for(UserEfficiencyStatementLight efficiencyStatement:efficiencyStatementsList) { CertificateAndEfficiencyStatement wrapper = new CertificateAndEfficiencyStatement(); wrapper.setDisplayName(efficiencyStatement.getShortTitle()); wrapper.setPassed(efficiencyStatement.getPassed()); wrapper.setScore(efficiencyStatement.getScore()); wrapper.setEfficiencyStatementKey(efficiencyStatement.getKey()); wrapper.setResourceKey(efficiencyStatement.getArchivedResourceKey()); wrapper.setLastModified(efficiencyStatement.getLastModified()); statments.add(wrapper); resourceKeyToStatments.put(efficiencyStatement.getArchivedResourceKey(), wrapper); } List<CertificateLight> certificates = certificatesManager.getLastCertificates(assessedIdentity); for(CertificateLight certificate:certificates) { Long resourceKey = certificate.getOlatResourceKey(); CertificateAndEfficiencyStatement wrapper = resourceKeyToStatments.get(resourceKey); if(wrapper == null) { wrapper = new CertificateAndEfficiencyStatement(); wrapper.setDisplayName(certificate.getCourseTitle()); resourceKeyToStatments.put(resourceKey, wrapper); statments.add(wrapper); } else { wrapper.setResourceKey(resourceKey); } if(resourceKey != null && wrapper.getResourceKey() == null) { wrapper.setResourceKey(resourceKey); } wrapper.setCertificate(certificate); } tableModel.setObjects(statments); } @Override protected void formOK(UserRequest ureq) { // } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(tableEl == source) { if(event instanceof SelectionEvent) { SelectionEvent te = (SelectionEvent) event; String cmd = te.getCommand(); CertificateAndEfficiencyStatement statement = tableModel.getObject(te.getIndex()); if(CMD_LAUNCH_COURSE.equals(cmd)) { doLaunchCourse(ureq, statement.getResourceKey()); } else if(CMD_DELETE.equals(cmd)) { doConfirmDelete(ureq, statement); } else if(CMD_SHOW.equals(cmd)) { 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) { doLaunchCoachingTool(ureq); } super.formInnerEvent(ureq, source, event); } @Override protected void event(UserRequest ureq, Controller source, Event event) { if (source == confirmDeleteCtr) { if (DialogBoxUIFactory.isYesEvent(event)) { 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()); CertificateAndEfficiencyStatementController efficiencyCtrl = new CertificateAndEfficiencyStatementController(getWindowControl(), ureq, assessedIdentity, null, statement.getResourceKey(), entry, efficiencyStatment, false); listenTo(efficiencyCtrl); stackPanel.pushController(statement.getDisplayName(), efficiencyCtrl); } private void doConfirmDelete(UserRequest ureq, CertificateAndEfficiencyStatement statement) { RepositoryEntry re = repositoryService.loadByResourceKey(statement.getResourceKey()); if(re == null) { String text = translate("efficiencyStatements.delete.confirm", statement.getDisplayName()); confirmDeleteCtr = activateYesNoDialog(ureq, null, text, confirmDeleteCtr); confirmDeleteCtr.setUserObject(statement); } else { showWarning("efficiencyStatements.cannot.delete"); } } private void doDelete(Long efficiencyStatementKey) { UserEfficiencyStatementLight efficiencyStatement = esm.getUserEfficiencyStatementLightByKey(efficiencyStatementKey); if(efficiencyStatement != null) { esm.deleteEfficiencyStatement(efficiencyStatement); } loadModel(); tableEl.reset(); showInfo("info.efficiencyStatement.deleted"); } private void doLaunchCoachingTool(UserRequest ureq) { String businessPath = "[CoachSite:0][Search:0][Identity:" + assessedIdentity.getKey() + "]"; NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); } private void doLaunchCourse(UserRequest ureq, Long resourceKey) { RepositoryEntry entry = repositoryService.loadByResourceKey(resourceKey); if(entry == null) { showWarning("efficiencyStatements.course.noexists"); } else if (!repositoryManager.isAllowedToLaunch(ureq, entry)) { showWarning("efficiencyStatements.course.noaccess"); } else { try { String businessPath = "[RepositoryEntry:" + entry.getKey() + "]"; NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); } catch (CorruptedCourseException e) { logError("Course corrupted: " + entry.getKey() + " (" + entry.getResourceableId() + ")", e); showError("cif.error.corrupted"); } } } private void doCollectArtefact(UserRequest ureq, String title, Long efficiencyStatementKey) { EPArtefactHandler<?> artHandler = portfolioModule.getArtefactHandler(EfficiencyStatementArtefact.ARTEFACT_TYPE); if(artHandler != null && artHandler.isEnabled() && assessedIdentity.equals(getIdentity())) { AbstractArtefact artefact = artHandler.createArtefact(); artefact.setAuthor(getIdentity());//only author can create artefact //no business path becouse we cannot launch an efficiency statement artefact.setCollectionDate(new Date()); artefact.setTitle(translate("artefact.title", new String[]{ title })); EfficiencyStatement fullStatement = esm.getUserEfficiencyStatementByKey(efficiencyStatementKey); artHandler.prefillArtefactAccordingToSource(artefact, fullStatement); ePFCollCtrl = new ArtefactWizzardStepsController(ureq, getWindowControl(), artefact, (VFSContainer)null); listenTo(ePFCollCtrl); } } private void doCollectMedia(UserRequest ureq, String title, Long efficiencyStatementKey) { if(collectorCtrl != null) return; EfficiencyStatement fullStatement = esm.getUserEfficiencyStatementByKey(efficiencyStatementKey); collectorCtrl = new CollectArtefactController(ureq, getWindowControl(), fullStatement, mediaHandler, ""); listenTo(collectorCtrl); cmc = new CloseableModalController(getWindowControl(), null, collectorCtrl.getInitialComponent(), true, title, true); cmc.addControllerListener(this); cmc.activate(); } public class AsArtefactCellRenderer implements FlexiCellRenderer { @Override public void render(Renderer renderer, StringOutput sb, Object cellValue, int row, FlexiTableComponent source, URLBuilder ubu, Translator translator) { sb.append("<i class='o_icon o_icon-lg o_icon_eportfolio_add'> </i> <span title=\"") .append(translate("table.add.as.artefact")) .append("\"> </span>"); } } }