diff --git a/src/main/java/org/olat/core/commons/services/webdav/WebDAVModule.java b/src/main/java/org/olat/core/commons/services/webdav/WebDAVModule.java index a60d92bfa9c05b1ec3b7f4124883bf39f41b840e..b50815d428210b35aad4b154a694bac47358936d 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/WebDAVModule.java +++ b/src/main/java/org/olat/core/commons/services/webdav/WebDAVModule.java @@ -49,6 +49,7 @@ public class WebDAVModule extends AbstractSpringModule implements ConfigOnOff { private static final String LEARNERS_PARTICIPATING_COURSES = "webdav.learners.participating.courses"; private static final String PREPEND_COURSE_REFERENCE_TO_TITLE = "webdav.prepend.course.reference.to.title"; private static final String CURRICULUM_ELEMENTS_FOLDERS_ENABLED = "webdav.curriculumelements.folders.enabled"; + private static final String MANAGED_FOLDERS_ENABLED = "webdav.managed.folders.enabled"; @Autowired private List<WebDAVProvider> webdavProviders; @@ -61,6 +62,8 @@ public class WebDAVModule extends AbstractSpringModule implements ConfigOnOff { private boolean digestAuthenticationEnabled; @Value("${webdav.termsfolders.enabled:true}") private boolean termsFoldersEnabled; + @Value("${webdav.managed.folders.enabled:false}") + private boolean managedFoldersEnabled; @Value("${webdav.curriculumelements.folders.enabled:false}") private boolean curriculumElementFoldersEnabled; @Value("${webdav.prepend.course.reference.to.title:false}") @@ -102,6 +105,11 @@ public class WebDAVModule extends AbstractSpringModule implements ConfigOnOff { termsFoldersEnabled = "true".equals(termsFoldersEnabledObj); } + String managedFoldersEnabledObj = getStringPropertyValue(MANAGED_FOLDERS_ENABLED, true); + if(StringHelper.containsNonWhitespace(managedFoldersEnabledObj)) { + managedFoldersEnabled = "true".equals(managedFoldersEnabledObj); + } + String curriculumElementsFoldersEnabledObj = getStringPropertyValue(CURRICULUM_ELEMENTS_FOLDERS_ENABLED, true); if(StringHelper.containsNonWhitespace(curriculumElementsFoldersEnabledObj)) { curriculumElementFoldersEnabled = "true".equals(curriculumElementsFoldersEnabledObj); @@ -167,6 +175,14 @@ public class WebDAVModule extends AbstractSpringModule implements ConfigOnOff { setStringProperty(TERMS_FOLDERS_ENABLED, enabledStr, true); } + public boolean isManagedFoldersEnabled() { + return managedFoldersEnabled; + } + + public void setManagedFoldersEnabled(boolean enabled) { + managedFoldersEnabled = enabled; + setStringProperty(MANAGED_FOLDERS_ENABLED, Boolean.toString(enabled), true); + } public boolean isCurriculumElementFoldersEnabled() { return curriculumElementFoldersEnabled; diff --git a/src/main/java/org/olat/core/commons/services/webdav/ui/WebDAVAdminController.java b/src/main/java/org/olat/core/commons/services/webdav/ui/WebDAVAdminController.java index 55f9c1fd03bbd0a490068c2c293172c72e109d13..457f814f10773b80f20a3804872de8a77ee6c00b 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/ui/WebDAVAdminController.java +++ b/src/main/java/org/olat/core/commons/services/webdav/ui/WebDAVAdminController.java @@ -43,6 +43,7 @@ public class WebDAVAdminController extends FormBasicController { private MultipleSelectionElement enableLinkEl; private MultipleSelectionElement enableDigestEl; private MultipleSelectionElement enableTermsFoldersEl; + private MultipleSelectionElement enableManagedFoldersEl; private MultipleSelectionElement enableCurriculumElementFoldersEl; private MultipleSelectionElement learnersAsParticipantEl; private MultipleSelectionElement learnersBookmarkEl; @@ -92,6 +93,11 @@ public class WebDAVAdminController extends FormBasicController { enableCurriculumElementFoldersEl.addActionListener(FormEvent.ONCHANGE); enableCurriculumElementFoldersEl.setEnabled(enabled); + enableManagedFoldersEl = uifactory.addCheckboxesHorizontal("webdavManagedFolders", "webdav.managedfolders", formLayout, onKeys, values); + enableManagedFoldersEl.select("xx", webDAVModule.isManagedFoldersEnabled()); + enableManagedFoldersEl.addActionListener(FormEvent.ONCHANGE); + enableManagedFoldersEl.setEnabled(enabled); + prependReferenceEl = uifactory.addCheckboxesHorizontal("webdavPrepend", "webdav.prepend.reference", formLayout, onKeys, values); prependReferenceEl.select("xx", webDAVModule.isPrependCourseReferenceToTitle()); prependReferenceEl.addActionListener(FormEvent.ONCHANGE); @@ -146,6 +152,9 @@ public class WebDAVAdminController extends FormBasicController { } else if(source == prependReferenceEl) { boolean enabled = prependReferenceEl.isAtLeastSelected(1); webDAVModule.setPrependCourseReferenceToTitle(enabled); + } else if(source == enableManagedFoldersEl) { + boolean enabled = enableManagedFoldersEl.isAtLeastSelected(1); + webDAVModule.setManagedFoldersEnabled(enabled); } super.formInnerEvent(ureq, source, event); } diff --git a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_de.properties index b2dde1627107816c12da2f0c317baa5122804e2b..34719874e0f98ed7cca677c2777fe1661b9fcdbd 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_de.properties @@ -8,6 +8,7 @@ webdav.digest=Digest Authentication bei HTTP Zugang verwenden webdav.for.learners.bookmarks=Zugriff f\u00FCr Studenten / Betreuer Favoriten webdav.for.learners.participants=Zugriff f\u00FCr Studenten / Betreuer Kurse webdav.link=WebDAV Links anzeigen +webdav.managedfolders="Managed" Kurse gruppieren webdav.module=WebDAV Zugang webdav.on=ein webdav.prepend.reference=Kennzeichen dem Titel voranstellen diff --git a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_en.properties index b17b91bc6516c31697f202441bff6ad24e6a1610..35ab4d095c10f69fd770d50928cd188ebc898e6e 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_en.properties @@ -8,6 +8,7 @@ webdav.digest=Digest Authentication for HTTP access webdav.for.learners.bookmarks=Enable access for courses that users marked as favorite webdav.for.learners.participants=Enable access for courses where user is participant or coach webdav.link=Show WebDAV links +webdav.managedfolders=Group "managed" courses webdav.module=WebDAV access webdav.on=enabled webdav.prepend.reference=Prepend external course reference to title diff --git a/src/main/java/org/olat/course/CoursefolderWebDAVMergeSource.java b/src/main/java/org/olat/course/CoursefolderWebDAVMergeSource.java index 8f8beb9029ecad28319b9b8462d1332831919f90..7eb9b2ca030d0b389da4d3a6b2e4cb28be7b9e6a 100644 --- a/src/main/java/org/olat/course/CoursefolderWebDAVMergeSource.java +++ b/src/main/java/org/olat/course/CoursefolderWebDAVMergeSource.java @@ -65,48 +65,55 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource { curriculumService = CoreSpringFactory.getImpl(CurriculumService.class); } + /* + * _others + * _managed + * _closed + * _manually + * _closed + * + * (non-Javadoc) + * @see org.olat.core.commons.services.webdav.manager.WebDAVMergeSource#loadMergedContainers() + */ @Override protected List<VFSContainer> loadMergedContainers() { List<VFSContainer> containers = new ArrayList<>(); - Map<String, VFSContainer> terms = new HashMap<>(); - VirtualContainer noTermContainer = new VirtualContainer("_other"); - VirtualContainer finishedContainer = null; - + boolean useSemestersTerms = webDAVModule.isTermsFoldersEnabled(); boolean useCurriculumElementsTerms = webDAVModule.isCurriculumElementFoldersEnabled(); boolean prependReference = webDAVModule.isPrependCourseReferenceToTitle(); + boolean useManaged = webDAVModule.isManagedFoldersEnabled(); - NamingAndGrouping namingAndGrouping = new NamingAndGrouping(useSemestersTerms, useCurriculumElementsTerms); + NamingAndGrouping namingAndGrouping = new NamingAndGrouping(prependReference, useManaged, useSemestersTerms, useCurriculumElementsTerms); if(useCurriculumElementsTerms) { namingAndGrouping.setCurriculumElementInfos(getCurriculumElementWebDAVInfosMap()); } - if(!useSemestersTerms && !useCurriculumElementsTerms) { - finishedContainer = new VirtualContainer("_finished"); - } + + NoTermContainer noTermContainer = new NoTermContainer(namingAndGrouping); List<RepositoryEntry> editorEntries = repositoryManager.queryByOwner(getIdentity(), true, "CourseModule"); - appendCourses(editorEntries, true, containers, terms, noTermContainer, finishedContainer, prependReference, namingAndGrouping); + appendCourses(editorEntries, containers, terms, noTermContainer, namingAndGrouping, true); //add courses as participant and coaches if(webDAVModule.isEnableLearnersParticipatingCourses()) { List<RepositoryEntry> entries = repositoryManager.getLearningResourcesAsParticipantAndCoach(getIdentity(), "CourseModule"); - appendCourses(entries, false, containers, terms, noTermContainer, finishedContainer, prependReference, namingAndGrouping); + appendCourses(entries, containers, terms, noTermContainer, namingAndGrouping, false); } //add bookmarked courses if(webDAVModule.isEnableLearnersBookmarksCourse()) { List<RepositoryEntry> bookmarkedEntries = repositoryManager.getLearningResourcesAsBookmark(getIdentity(), identityEnv.getRoles(), "CourseModule", 0, -1); - appendCourses(bookmarkedEntries, false, containers, terms, noTermContainer, finishedContainer, prependReference, namingAndGrouping); + appendCourses(bookmarkedEntries, containers, terms, noTermContainer, namingAndGrouping, false); } if (useSemestersTerms || useCurriculumElementsTerms) { // add no-terms folder if any have been found - if (!noTermContainer.getItems().isEmpty()) { - addContainerToList(noTermContainer, containers); + if (noTermContainer.hasNoTerms()) { + addContainerToList(noTermContainer.computeNoTermContainer(), containers); } - } else if(!finishedContainer.getItems().isEmpty()) { - addContainerToList(finishedContainer, containers); + } else if(noTermContainer.hasFinished()) { + addContainerToList(noTermContainer.getFinishedContainer(), containers); } return containers; @@ -125,9 +132,9 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource { return infoMap; } - private void appendCourses(List<RepositoryEntry> courseEntries, boolean editor, List<VFSContainer> containers, - Map<String, VFSContainer> terms, VirtualContainer noTermContainer, VirtualContainer finishedContainer, - boolean prependReference, NamingAndGrouping namingAndGrouping) { + private void appendCourses(List<RepositoryEntry> courseEntries, List<VFSContainer> containers, + Map<String, VFSContainer> terms, NoTermContainer noTermContainer, + NamingAndGrouping namingAndGrouping, boolean editor) { // Add all found repo entries to merge source int count = 0; @@ -136,60 +143,15 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource { continue; } - if(finishedContainer != null && re.getEntryStatus() == RepositoryEntryStatusEnum.closed) { - String courseTitle = getCourseTitle(re, prependReference); + if(namingAndGrouping.isUseFinished() && re.getEntryStatus() == RepositoryEntryStatusEnum.closed) { + String courseTitle = getCourseTitle(re, namingAndGrouping.isPrependReference()); String name = namingAndGrouping.getFinishedUniqueName(courseTitle); NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv); - finishedContainer.getItems().add(cfContainer); + noTermContainer.addToFinished(cfContainer); } else if (namingAndGrouping.isUseSemesterTerms() || namingAndGrouping.isUseCurriculumElementsTerms()) { - RepositoryEntryLifecycle lc = re.getLifecycle(); - - boolean termed = false; - if (namingAndGrouping.isUseSemesterTerms() && lc != null && !lc.isPrivateCycle()) { - // when a semester term info is found, add it to corresponding term folder - String termSoftKey = lc.getSoftKey(); - VFSContainer termContainer = terms.computeIfAbsent(termSoftKey, term -> { - String normalizedKey = RequestUtil.normalizeFilename(term); - VirtualContainer container = new VirtualContainer(normalizedKey); - addContainerToList(container, containers); - return container; - }); - - String courseTitle = getCourseTitle(re, prependReference); - String name = namingAndGrouping.getTermUniqueName(termSoftKey, courseTitle); - NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv); - termContainer.getItems().add(cfContainer); - termed = true; - } - - if(namingAndGrouping.isUseCurriculumElementsTerms() && namingAndGrouping.hasCurriculumElements(re)) { - List<CurriculumElementWebDAVInfos> elements = namingAndGrouping.getCurriculumElementInfos().get(re.getKey()); - for(CurriculumElementWebDAVInfos element:elements) { - String termSoftKey = getTermSoftKey(element); - VFSContainer termContainer = terms.computeIfAbsent(termSoftKey, term -> { - String normalizedKey = RequestUtil.normalizeFilename(term); - VirtualContainer container = new VirtualContainer(normalizedKey); - addContainerToList(container, containers); - return container; - }); - - String courseTitle = getCourseTitle(re, false); - String name = namingAndGrouping.getTermUniqueName(termSoftKey, courseTitle); - NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv); - termContainer.getItems().add(cfContainer); - termed = true; - } - } - - if(!termed) { - // no semester term found, add to no-term folder - String courseTitle = getCourseTitle(re, prependReference); - String name = namingAndGrouping.getNoTermUniqueName(courseTitle); - NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv); - noTermContainer.getItems().add(cfContainer); - } + appendCoursesWithTerms(re, containers, noTermContainer, terms, namingAndGrouping, editor); } else { - String courseTitle = getCourseTitle(re, prependReference); + String courseTitle = getCourseTitle(re, namingAndGrouping.isPrependReference()); String name = namingAndGrouping.getContainersUniqueName(courseTitle); NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv); addContainerToList(cfContainer, containers); @@ -200,17 +162,66 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource { } } + private void appendCoursesWithTerms(RepositoryEntry re, List<VFSContainer> containers, NoTermContainer noTermContainer, + Map<String, VFSContainer> terms, NamingAndGrouping namingAndGrouping, boolean editor) { + RepositoryEntryLifecycle lc = re.getLifecycle(); + + boolean termed = false; + if (namingAndGrouping.isUseSemesterTerms() && lc != null && !lc.isPrivateCycle()) { + // when a semester term info is found, add it to corresponding term folder + String termSoftKey = lc.getSoftKey(); + VFSContainer termContainer = terms.computeIfAbsent(termSoftKey, term -> { + String normalizedKey = RequestUtil.normalizeFilename(term); + VirtualContainer container = new VirtualContainer(normalizedKey); + addContainerToList(container, containers); + return container; + }); + + String courseTitle = getCourseTitle(re, namingAndGrouping.isPrependReference()); + String name = namingAndGrouping.getTermUniqueName(termSoftKey, courseTitle); + NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv); + termContainer.getItems().add(cfContainer); + termed = true; + } + + if(namingAndGrouping.isUseCurriculumElementsTerms() && namingAndGrouping.hasCurriculumElements(re)) { + List<CurriculumElementWebDAVInfos> elements = namingAndGrouping.getCurriculumElementInfos().get(re.getKey()); + for(CurriculumElementWebDAVInfos element:elements) { + String termSoftKey = getTermSoftKey(element); + VFSContainer termContainer = terms.computeIfAbsent(termSoftKey, term -> { + String normalizedKey = RequestUtil.normalizeFilename(term); + VirtualContainer container = new VirtualContainer(normalizedKey); + addContainerToList(container, containers); + return container; + }); + + String courseTitle = getCourseTitle(re, false); + String name = namingAndGrouping.getTermUniqueName(termSoftKey, courseTitle); + NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv); + termContainer.getItems().add(cfContainer); + termed = true; + } + } + + if(!termed) { + // no semester term found, add to no-term folder + String courseTitle = getCourseTitle(re, namingAndGrouping.isPrependReference()); + String name = namingAndGrouping.getNoTermUniqueName(courseTitle); + NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv); + noTermContainer.add(re, cfContainer); + } + } + private String getCourseTitle(RepositoryEntry re, boolean prependReference) { String displayName = re.getDisplayname(); if(prependReference && StringHelper.containsNonWhitespace(re.getExternalRef())) { displayName = re.getExternalRef() + " " + displayName; } return RequestUtil.normalizeFilename(displayName); - } private String getTermSoftKey(CurriculumElementWebDAVInfos element) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(64); if(StringHelper.containsNonWhitespace(element.getParentCurriculumElementDisplayName())) { if(StringHelper.containsNonWhitespace(element.getParentCurriculumElementIdentifier())) { sb.append(element.getParentCurriculumElementIdentifier()).append(" "); @@ -225,8 +236,98 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource { return sb.toString(); } + private static class NoTermContainer { + + private final VirtualContainer noTermContainer = new VirtualContainer("_other"); + private final VirtualContainer finishedContainer = new VirtualContainer("_finished"); + + + private VirtualContainer managedContainer; + private VirtualContainer managedAndClosedContainer; + private VirtualContainer manuallyContainer; + private VirtualContainer manuallyAndClosedContainer; + + private final NamingAndGrouping namingAndGrouping; + + public NoTermContainer(NamingAndGrouping namingAndGrouping) { + this.namingAndGrouping = namingAndGrouping; + } + + public boolean hasNoTerms() { + return !noTermContainer.getItems().isEmpty(); + } + + public VFSContainer computeNoTermContainer() { + return noTermContainer; + } + + public boolean hasFinished() { + return !finishedContainer.getItems().isEmpty(); + } + + public VFSContainer getFinishedContainer() { + return finishedContainer; + } + + public void addToFinished(VFSContainer container) { + finishedContainer.getItems().add(container); + } + + public void addToManagedAndClosed(VFSContainer container) { + if(managedAndClosedContainer == null) { + managedAndClosedContainer = new VirtualContainer("_closed"); + addToManaged(managedAndClosedContainer); + } + managedAndClosedContainer.getItems().add(container); + } + + public void addToManaged(VFSContainer container) { + if(managedContainer == null) { + managedContainer = new VirtualContainer("_managed"); + noTermContainer.getItems().add(managedContainer); + } + managedContainer.getItems().add(container); + } + + public void addToManuualyAndClosed(VFSContainer container) { + if(manuallyAndClosedContainer == null) { + manuallyAndClosedContainer = new VirtualContainer("_closed"); + addToManually(manuallyAndClosedContainer); + } + manuallyAndClosedContainer.getItems().add(container); + } + + public void addToManually(VFSContainer container) { + if(manuallyContainer == null) { + manuallyContainer = new VirtualContainer("_manually"); + noTermContainer.getItems().add(manuallyContainer); + } + manuallyContainer.getItems().add(container); + } + + public void add(RepositoryEntry entry, VFSContainer container) { + if(namingAndGrouping.isUseManaged()) { + if(StringHelper.containsNonWhitespace(entry.getManagedFlagsString())) { + if(entry.getEntryStatus() == RepositoryEntryStatusEnum.closed) { + addToManagedAndClosed(container); + } else { + addToManaged(container); + } + } else if(entry.getEntryStatus() == RepositoryEntryStatusEnum.closed) { + addToManuualyAndClosed(container); + } else { + addToManually(container); + } + } else { + noTermContainer.getItems().add(container); + } + } + } + private static class NamingAndGrouping { + private final boolean useManaged; + private final boolean prependReference; private final boolean useSemesterTerms; private final boolean useCurriculumElementsTerms; @@ -238,11 +339,18 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource { private Map<Long,List<CurriculumElementWebDAVInfos>> curriculumElementInfos; - public NamingAndGrouping(boolean useSemesterTerms, boolean useCurriculumElementsTerms) { + public NamingAndGrouping(boolean prependReference, boolean useManaged, + boolean useSemesterTerms, boolean useCurriculumElementsTerms) { + this.prependReference = prependReference; + this.useManaged = useManaged; this.useSemesterTerms = useSemesterTerms; this.useCurriculumElementsTerms = useCurriculumElementsTerms; } + public boolean isUseManaged() { + return useManaged; + } + public boolean isUseSemesterTerms() { return useSemesterTerms; } @@ -250,6 +358,14 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource { public boolean isUseCurriculumElementsTerms() { return useCurriculumElementsTerms; } + + public boolean isPrependReference() { + return prependReference; + } + + public boolean isUseFinished() { + return !useSemesterTerms && !useSemesterTerms && !useManaged; + } public Map<Long, List<CurriculumElementWebDAVInfos>> getCurriculumElementInfos() { return curriculumElementInfos;