From 1332822301246ac767ae7d32bd39ba7ccc7a018d Mon Sep 17 00:00:00 2001 From: uhensler <urs.hensler@frentix.com> Date: Fri, 27 Mar 2020 08:41:36 +0100 Subject: [PATCH] OO-4598: List of documents open in an external editor --- .../ui/OnlyOfficeEditorController.java | 13 +- .../ui/AdminDocEditorController.java | 28 +++- .../doceditor/ui/DocumentsInUseDataModel.java | 136 ++++++++++++++++++ .../ui/DocumentsInUseListController.java | 135 +++++++++++++++++ .../doceditor/ui/DocumentsInUseRow.java | 60 ++++++++ .../ui/_i18n/LocalStrings_de.properties | 9 ++ .../ui/_i18n/LocalStrings_en.properties | 9 ++ .../services/doceditor/wopi/Access.java | 2 + .../services/doceditor/wopi/WopiService.java | 3 + .../doceditor/wopi/manager/AccessDAO.java | 20 +++ .../wopi/manager/WopiServiceImpl.java | 5 + .../doceditor/wopi/model/AccessImpl.java | 1 + .../_spring/userPropertiesContext.xml | 22 +++ .../doceditor/wopi/manager/AccessDAOTest.java | 21 +++ 14 files changed, 460 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseDataModel.java create mode 100644 src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseListController.java create mode 100644 src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseRow.java diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java index 8118d08d2ba..a5a4a123d55 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java +++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java @@ -50,6 +50,8 @@ public class OnlyOfficeEditorController extends BasicController { private static final Logger log = Tracing.createLoggerFor(OnlyOfficeEditorController.class); private Access access; + private Mode openMode; + private Long openVfsMetadataKey; @Autowired private OnlyOfficeModule onlyOfficeModule; @@ -96,6 +98,11 @@ public class OnlyOfficeEditorController extends BasicController { mainVC.contextPut("id", "o_" + CodeHelper.getRAMUniqueID()); mainVC.contextPut("apiUrl", onlyOfficeModule.getApiUrl()); mainVC.contextPut("apiConfig", apiConfigJson); + + openVfsMetadataKey = vfsMetadata.getKey(); + openMode = secCallback.getMode(); + log.info("Document (key={}) opened with ONLYOFFICE ({}) by {}", openVfsMetadataKey, openMode, + getIdentity()); } } @@ -109,7 +116,11 @@ public class OnlyOfficeEditorController extends BasicController { @Override protected void doDispose() { - onlyOfficeService.deleteAccess(access); + if (access != null) { + log.info("Document (key={}) opened with ONLYOFFICE ({}) by {}", openVfsMetadataKey, openMode, + getIdentity()); + onlyOfficeService.deleteAccess(access); + } } } diff --git a/src/main/java/org/olat/core/commons/services/doceditor/ui/AdminDocEditorController.java b/src/main/java/org/olat/core/commons/services/doceditor/ui/AdminDocEditorController.java index 6d61d588a7f..a5f3fb71c40 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/ui/AdminDocEditorController.java +++ b/src/main/java/org/olat/core/commons/services/doceditor/ui/AdminDocEditorController.java @@ -32,6 +32,7 @@ import org.olat.core.gui.components.segmentedview.SegmentViewComponent; import org.olat.core.gui.components.segmentedview.SegmentViewEvent; import org.olat.core.gui.components.segmentedview.SegmentViewFactory; import org.olat.core.gui.components.velocity.VelocityContainer; +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.controller.BasicController; @@ -51,16 +52,19 @@ public class AdminDocEditorController extends BasicController implements Activat private static final String COLLABORA_RES_TYPE = "Collabora"; private static final String ONLY_OFFICE_RES_TYPE = "OnlyOffice"; private static final String OFFICE365_RES_TYPE = "Office365"; + private static final String DOCUMENTS_IN_USE_RES_TYPE = "OpenDocuments"; private VelocityContainer mainVC; private final Link collaboraLink; private final Link onlyOfficeLink; private final Link office365Link; + private final Link documentsInUseLink; private final SegmentViewComponent segmentView; - private CollaboraAdminController collaboraCtrl; - private OnlyOfficeAdminController onlyOfficeCtrl; - private Office365AdminController office365Ctrl; + private Controller collaboraCtrl; + private Controller onlyOfficeCtrl; + private Controller office365Ctrl; + private DocumentsInUseListController documentsInUseCtrl; public AdminDocEditorController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); @@ -74,6 +78,8 @@ public class AdminDocEditorController extends BasicController implements Activat segmentView.addSegment(onlyOfficeLink, false); office365Link = LinkFactory.createLink("admin.office365", mainVC, this); segmentView.addSegment(office365Link, false); + documentsInUseLink = LinkFactory.createLink("admin.documents.in.use", mainVC, this); + segmentView.addSegment(documentsInUseLink, false); doOpenCollabora(ureq); putInitialPanel(mainVC); @@ -93,6 +99,9 @@ public class AdminDocEditorController extends BasicController implements Activat } else if(OFFICE365_RES_TYPE.equalsIgnoreCase(type)) { doOpenOffice365(ureq); segmentView.select(office365Link); + } else if(DOCUMENTS_IN_USE_RES_TYPE.equalsIgnoreCase(type)) { + doOpenDocumentsInUse(ureq); + segmentView.select(documentsInUseLink); } } @@ -109,6 +118,8 @@ public class AdminDocEditorController extends BasicController implements Activat doOpenOnlyOffice(ureq); } else if (clickedLink == office365Link) { doOpenOffice365(ureq); + } else if (clickedLink == documentsInUseLink) { + doOpenDocumentsInUse(ureq); } } } @@ -147,6 +158,17 @@ public class AdminDocEditorController extends BasicController implements Activat mainVC.put("segmentCmp", office365Ctrl.getInitialComponent()); } + private void doOpenDocumentsInUse(UserRequest ureq) { + if(documentsInUseCtrl == null) { + WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType(DOCUMENTS_IN_USE_RES_TYPE), null); + documentsInUseCtrl = new DocumentsInUseListController(ureq, swControl); + listenTo(documentsInUseCtrl); + } else { + documentsInUseCtrl.loadModel(); + addToHistory(ureq, documentsInUseCtrl); + } + mainVC.put("segmentCmp", documentsInUseCtrl.getInitialComponent()); + } @Override protected void doDispose() { diff --git a/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseDataModel.java b/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseDataModel.java new file mode 100644 index 00000000000..6720a6a266e --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseDataModel.java @@ -0,0 +1,136 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.doceditor.ui; + +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +import org.olat.core.commons.persistence.SortKey; +import org.olat.core.commons.services.doceditor.DocEditor.Mode; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FilterableFlexiTableModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; +import org.olat.modules.fo.ui.ForumUserDataModel.UserCols; + +/** + * + * Initial date: 26 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class DocumentsInUseDataModel extends DefaultFlexiTableDataModel<DocumentsInUseRow> +implements SortableFlexiTableDataModel<DocumentsInUseRow>, FilterableFlexiTableModel { + + private final Locale locale; + private List<DocumentsInUseRow> backups; + + public DocumentsInUseDataModel(FlexiTableColumnModel columnsModel, Locale locale) { + super(columnsModel); + this.locale = locale; + } + + @Override + public void setObjects(List<DocumentsInUseRow> objects) { + super.setObjects(objects); + backups = objects; + } + + @Override + public void filter(String searchString, List<FlexiTableFilter> filters) { + if(filters != null && !filters.isEmpty() && filters.get(0) != null && !filters.get(0).isShowAll()) { + String filterKey = filters.get(0).getFilter(); + boolean canEdit = Mode.EDIT == Mode.valueOf(filterKey); + List<DocumentsInUseRow> filteredRows = backups.stream() + .filter(row -> canEdit == row.isCanEdit()) + .collect(Collectors.toList()); + super.setObjects(filteredRows); + } else { + super.setObjects(backups); + } + } + + @Override + public void sort(SortKey orderBy) { + List<DocumentsInUseRow> rows = new SortableFlexiTableModelDelegate<>(orderBy, this, locale).sort(); + super.setObjects(rows); + } + + @Override + public Object getValueAt(int row, int col) { + DocumentsInUseRow reason = getObject(row); + return getValueAt(reason, col); + } + + @Override + public Object getValueAt(DocumentsInUseRow row, int col) { + if(col >= 0 && col < UserCols.values().length) { + switch(DocumentsInUseCols.values()[col]) { + case username: return row.getIdentityName(); + case fileName: return row.getFilename(); + case app: return row.getApp(); + case edit: return row.isCanEdit(); + case opened: return row.getOpened(); + default: return null; + } + } + + int propPos = col - DocumentsInUseListController.USER_PROPS_OFFSET; + return row.getIdentityProp(propPos); + } + + @Override + public DefaultFlexiTableDataModel<DocumentsInUseRow> createCopyWithEmptyList() { + return new DocumentsInUseDataModel(getTableColumnModel(), locale); + } + + public enum DocumentsInUseCols implements FlexiSortableColumnDef { + username("table.header.username"), + fileName("table.header.file.name"), + app("table.header.app"), + edit("table.header.edit"), + opened("table.header.opened"); + + private final String i18nKey; + + private DocumentsInUseCols(String i18nKey) { + this.i18nKey = i18nKey; + } + + @Override + public String i18nHeaderKey() { + return i18nKey; + } + + @Override + public boolean sortable() { + return true; + } + + @Override + public String sortKey() { + return name(); + } + } +} diff --git a/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseListController.java b/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseListController.java new file mode 100644 index 00000000000..d6afef98bfa --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseListController.java @@ -0,0 +1,135 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.doceditor.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.basesecurity.BaseSecurityModule; +import org.olat.core.commons.services.doceditor.DocEditor.Mode; +import org.olat.core.commons.services.doceditor.ui.DocumentsInUseDataModel.DocumentsInUseCols; +import org.olat.core.commons.services.doceditor.wopi.Access; +import org.olat.core.commons.services.doceditor.wopi.WopiService; +import org.olat.core.gui.UserRequest; +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.FlexiTableFilter; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.user.UserManager; +import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 26 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class DocumentsInUseListController extends FormBasicController { + + private static final String USER_PROPS_ID = DocumentsInUseListController.class.getCanonicalName(); + public static final int USER_PROPS_OFFSET = 500; + + private FlexiTableElement tableEl; + private DocumentsInUseDataModel dataModel; + private final boolean isAdministrativeUser; + private final List<UserPropertyHandler> userPropertyHandlers; + + @Autowired + private WopiService wopiService; + @Autowired + private UserManager userManager; + @Autowired + private BaseSecurityModule securityModule; + + public DocumentsInUseListController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl, LAYOUT_BAREBONE); + setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); + + isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles()); + userPropertyHandlers = userManager.getUserPropertyHandlersFor(USER_PROPS_ID, isAdministrativeUser); + + initForm(ureq); + loadModel(); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + + + + if(isAdministrativeUser) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DocumentsInUseCols.username)); + } + + int colIndex = USER_PROPS_OFFSET; + for (int i = 0; i < userPropertyHandlers.size(); i++) { + UserPropertyHandler userPropertyHandler = userPropertyHandlers.get(i); + boolean visible = userManager.isMandatoryUserProperty(USER_PROPS_ID , userPropertyHandler); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex, null, true, "userProp-" + colIndex)); + colIndex++; + } + + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DocumentsInUseCols.fileName)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DocumentsInUseCols.app)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DocumentsInUseCols.edit)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DocumentsInUseCols.opened)); + + dataModel = new DocumentsInUseDataModel(columnsModel, getLocale()); + tableEl = uifactory.addTableElement(getWindowControl(), "table", dataModel, 20, false, getTranslator(), formLayout); + tableEl.setAndLoadPersistedPreferences(ureq, "doc-editor-files-in-use"); + + List<FlexiTableFilter> filters = new ArrayList<>(); + filters.add(new FlexiTableFilter(translate("table.filter.edit"), Mode.EDIT.name())); + filters.add(new FlexiTableFilter(translate("table.filter.read.only"), Mode.VIEW.name())); + filters.add(FlexiTableFilter.SPACER); + filters.add(new FlexiTableFilter(translate("table.filter.show.all"), "showAll", true)); + tableEl.setFilters("", filters, false); + tableEl.setSelectedFilterKey(Mode.EDIT.name()); + } + + void loadModel() { + List<Access> accesses = wopiService.getAccesses(null); + + List<DocumentsInUseRow> rows = new ArrayList<>(accesses.size()); + for (Access access : accesses) { + rows.add(new DocumentsInUseRow(access, userPropertyHandlers, getLocale())); + } + dataModel.setObjects(rows); + tableEl.reset(false, false, true); + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void doDispose() { + // + } + +} diff --git a/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseRow.java b/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseRow.java new file mode 100644 index 00000000000..c1d4367d661 --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/doceditor/ui/DocumentsInUseRow.java @@ -0,0 +1,60 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.doceditor.ui; + +import java.util.List; +import java.util.Locale; + +import org.olat.core.commons.services.doceditor.wopi.Access; +import org.olat.user.UserPropertiesRow; +import org.olat.user.propertyhandlers.UserPropertyHandler; + +/** + * + * Initial date: 26 Mar 2020<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class DocumentsInUseRow extends UserPropertiesRow { + + private final Access access; + + public DocumentsInUseRow(Access access, List<UserPropertyHandler> userPropertyHandlers, Locale locale) { + super(access.getIdentity(), userPropertyHandlers, locale); + this.access = access; + } + + public String getFilename() { + return access.getMetadata() != null? access.getMetadata().getFilename(): null; + } + + public String getApp() { + return access.getApp(); + } + + public Boolean isCanEdit() { + return Boolean.valueOf(access.isCanEdit()); + } + + public Object getOpened() { + return access.getCreationDate(); + } + +} diff --git a/src/main/java/org/olat/core/commons/services/doceditor/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/services/doceditor/ui/_i18n/LocalStrings_de.properties index 6266a1c4b6b..0c9988683dc 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/commons/services/doceditor/ui/_i18n/LocalStrings_de.properties @@ -1,5 +1,6 @@ admin.collabora=$org.olat.core.commons.services.doceditor.collabora.ui\:editor.display.name admin.data.transfer.confirmation.enabled=Best\u00E4tigung Datentransfer +admin.documents.in.use=Ge\u00F6ffnete Dokumente admin.menu.title.alt=Dokumenteneditoren admin.menu.title=Dokumenteneditoren admin.office365=$org.olat.core.commons.services.doceditor.office365.ui\:editor.display.name @@ -25,3 +26,11 @@ doc.type.txt=Text doc.type.xlsx=Excel doc.type.xml=Extensible Markup Language error.no.editor=Die Datei kann nicht angezeigt werden. +table.filter.edit=Bearbeiten +table.filter.read.only=Anzeige +table.filter.show.all=Alle anzeigen +table.header.app=Editor +table.header.edit=Bearbeiten +table.header.file.name=Dateiname +table.header.opened=Ge\u00F6ffnet +table.header.username=Benutzername diff --git a/src/main/java/org/olat/core/commons/services/doceditor/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/services/doceditor/ui/_i18n/LocalStrings_en.properties index b18ca53a4bf..c99c7962302 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/commons/services/doceditor/ui/_i18n/LocalStrings_en.properties @@ -1,5 +1,6 @@ admin.collabora=$org.olat.core.commons.services.doceditor.collabora.ui\:editor.display.name admin.data.transfer.confirmation.enabled=Confirmation of data transfer +admin.documents.in.use=Open documents admin.menu.title.alt=Document editors admin.menu.title=Document editors admin.usage.roles=Restrict usage to @@ -25,3 +26,11 @@ doc.type.txt=Text doc.type.xlsx=Excel doc.type.xml=Extensible Markup Language error.no.editor=The content of the document cannot be displayed. +table.filter.edit=Edit +table.filter.read.only=Read only +table.filter.show.all=Show all +table.header.app=Editor +table.header.edit=Edit +table.header.file.name=File name +table.header.opened=Opened +table.header.username=Username diff --git a/src/main/java/org/olat/core/commons/services/doceditor/wopi/Access.java b/src/main/java/org/olat/core/commons/services/doceditor/wopi/Access.java index edbddfd13a3..61665ad6c06 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/wopi/Access.java +++ b/src/main/java/org/olat/core/commons/services/doceditor/wopi/Access.java @@ -36,6 +36,8 @@ public interface Access extends ModifiedInfo, CreateInfo { String getToken(); + String getApp(); + Date getExpiresAt(); boolean isCanEdit(); diff --git a/src/main/java/org/olat/core/commons/services/doceditor/wopi/WopiService.java b/src/main/java/org/olat/core/commons/services/doceditor/wopi/WopiService.java index 4526e7f9af5..55c3ac27719 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/wopi/WopiService.java +++ b/src/main/java/org/olat/core/commons/services/doceditor/wopi/WopiService.java @@ -21,6 +21,7 @@ package org.olat.core.commons.services.doceditor.wopi; import java.util.Collection; import java.util.Date; +import java.util.List; import org.olat.core.commons.services.doceditor.DocEditor.Mode; import org.olat.core.commons.services.doceditor.DocEditorSecurityCallback; @@ -73,6 +74,8 @@ public interface WopiService { VFSLeaf getVfsLeaf(Access access); + List<Access> getAccesses(Mode mode); + Long getAccessCount(String app, Mode mode); void deleteAccess(String accessToken); diff --git a/src/main/java/org/olat/core/commons/services/doceditor/wopi/manager/AccessDAO.java b/src/main/java/org/olat/core/commons/services/doceditor/wopi/manager/AccessDAO.java index 64b339daf07..b03de18f9a9 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/wopi/manager/AccessDAO.java +++ b/src/main/java/org/olat/core/commons/services/doceditor/wopi/manager/AccessDAO.java @@ -23,6 +23,7 @@ import java.util.Date; import java.util.List; import javax.annotation.PostConstruct; +import javax.persistence.TypedQuery; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.QueryBuilder; @@ -120,6 +121,25 @@ class AccessDAO { return accesses.isEmpty() ? null : accesses.get(0); } + public List<Access> getAccesses(Mode mode) { + QueryBuilder sb = new QueryBuilder(); + sb.append("select access"); + sb.append(" from wopiaccess access"); + sb.append(" join fetch access.metadata metadata"); + sb.append(" join fetch access.identity identity"); + sb.append(" join fetch identity.user user"); + if (mode != null) { + sb.and().append("access.canEdit = :canEdit"); + } + + TypedQuery<Access> query = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Access.class); + if (mode != null) { + query.setParameter("canEdit", Mode.EDIT == mode); + } + return query.getResultList(); + } + Long getAccessCount(String app, Mode mode) { QueryBuilder sb = new QueryBuilder(); sb.append("select count(*)"); diff --git a/src/main/java/org/olat/core/commons/services/doceditor/wopi/manager/WopiServiceImpl.java b/src/main/java/org/olat/core/commons/services/doceditor/wopi/manager/WopiServiceImpl.java index 0f368d29063..5deb17ce9db 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/wopi/manager/WopiServiceImpl.java +++ b/src/main/java/org/olat/core/commons/services/doceditor/wopi/manager/WopiServiceImpl.java @@ -171,6 +171,11 @@ public class WopiServiceImpl implements WopiService { return null; } + @Override + public List<Access> getAccesses(Mode mode) { + return accessDao.getAccesses(mode); + } + @Override public Long getAccessCount(String app, Mode mode) { return accessDao.getAccessCount(app, mode); diff --git a/src/main/java/org/olat/core/commons/services/doceditor/wopi/model/AccessImpl.java b/src/main/java/org/olat/core/commons/services/doceditor/wopi/model/AccessImpl.java index cb508ad7d94..7eceb0f8677 100644 --- a/src/main/java/org/olat/core/commons/services/doceditor/wopi/model/AccessImpl.java +++ b/src/main/java/org/olat/core/commons/services/doceditor/wopi/model/AccessImpl.java @@ -121,6 +121,7 @@ public class AccessImpl implements Access, Persistable { this.token = token; } + @Override public String getApp() { return app; } diff --git a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml index ed0568f5905..8831f335b58 100644 --- a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml +++ b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml @@ -514,6 +514,28 @@ </property> </bean> </entry> + + <entry key="org.olat.core.commons.services.doceditor.ui.DocumentsInUseListController"> + <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> + <property name="propertyHandlers"> + <list> + <ref bean="userPropertyFirstName" /> + <ref bean="userPropertyLastName" /> + <ref bean="userPropertyEmail" /> + </list> + </property> + <property name="adminViewOnlyProperties"> + <set></set> + </property> + <property name="mandatoryProperties"> + <set> + <ref bean="userPropertyFirstName" /> + <ref bean="userPropertyLastName" /> + <ref bean="userPropertyEmail" /> + </set> + </property> + </bean> + </entry> <entry key="org.olat.commons.memberlist.ui.MembersPrintController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> diff --git a/src/test/java/org/olat/core/commons/services/doceditor/wopi/manager/AccessDAOTest.java b/src/test/java/org/olat/core/commons/services/doceditor/wopi/manager/AccessDAOTest.java index 59fbc0c778e..6fa0762e10e 100644 --- a/src/test/java/org/olat/core/commons/services/doceditor/wopi/manager/AccessDAOTest.java +++ b/src/test/java/org/olat/core/commons/services/doceditor/wopi/manager/AccessDAOTest.java @@ -25,6 +25,7 @@ import static org.olat.test.JunitTestHelper.random; import java.time.Duration; import java.time.Instant; import java.util.Date; +import java.util.List; import org.assertj.core.api.SoftAssertions; import org.junit.Before; @@ -138,6 +139,26 @@ public class AccessDAOTest extends OlatTestCase { assertThat(reloadedAccess).isEqualTo(access); } + @Test + public void shouldGetAccessesBayMode() { + Identity identity1 = JunitTestHelper.createAndPersistIdentityAsRndUser("wopi"); + Identity identity2 = JunitTestHelper.createAndPersistIdentityAsRndUser("wopi2"); + Identity identity3 = JunitTestHelper.createAndPersistIdentityAsRndUser("wopi3"); + VFSMetadata vfsMetadata = vfsMetadataDAO.createMetadata(random(), "relPath", "file.name", new Date(), 1000l, false, "file://" + random(), "file", null); + boolean canEdit = true; + Access accessEdit1 = sut.createAccess(vfsMetadata, identity1, "app1", random(), canEdit, true, true, null); + Access accessEdit2 = sut.createAccess(vfsMetadata, identity2, "app1", random(), canEdit, true, true, null); + Access accessEdit3 = sut.createAccess(vfsMetadata, identity1, "app2", random(), canEdit, true, true, null); + Access accessView = sut.createAccess(vfsMetadata, identity3, "app1", random(), false, true, true, null); + dbInstance.commitAndCloseSession(); + + List<Access> accesses = sut.getAccesses(Mode.EDIT); + + assertThat(accesses) + .containsExactlyInAnyOrder(accessEdit1, accessEdit2, accessEdit3) + .doesNotContain(accessView); + } + @Test public void shouldGetAccessCount() { Identity identity1 = JunitTestHelper.createAndPersistIdentityAsRndUser("wopi"); -- GitLab