Something went wrong on our end
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CoursefolderWebDAVMergeSource.java 16.65 KiB
/**
* <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;
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.CoreSpringFactory;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.commons.services.webdav.WebDAVModule;
import org.olat.core.commons.services.webdav.manager.WebDAVMergeSource;
import org.olat.core.commons.services.webdav.servlets.RequestUtil;
import org.olat.core.id.IdentityEnvironment;
import org.olat.core.util.StringHelper;
import org.olat.core.util.vfs.NamedContainerImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VirtualContainer;
import org.olat.modules.curriculum.CurriculumService;
import org.olat.modules.curriculum.model.CurriculumElementWebDAVInfos;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryEntryStatusEnum;
import org.olat.repository.RepositoryManager;
import org.olat.repository.model.RepositoryEntryLifecycle;
/**
* This WebDAV provider delivery all folders in courses where the user
* is owner or is editor via a right group.
*
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*/
class CoursefolderWebDAVMergeSource extends WebDAVMergeSource {
private final IdentityEnvironment identityEnv;
private final WebDAVModule webDAVModule;
private final RepositoryManager repositoryManager;
private final CurriculumService curriculumService;
public CoursefolderWebDAVMergeSource(IdentityEnvironment identityEnv) {
super(identityEnv.getIdentity());
this.identityEnv = identityEnv;
webDAVModule = CoreSpringFactory.getImpl(WebDAVModule.class);
repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
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<>();
boolean useSemestersTerms = webDAVModule.isTermsFoldersEnabled();
boolean useCurriculumElementsTerms = webDAVModule.isCurriculumElementFoldersEnabled();
boolean prependReference = webDAVModule.isPrependCourseReferenceToTitle();
boolean useManaged = webDAVModule.isManagedFoldersEnabled();
NamingAndGrouping namingAndGrouping = new NamingAndGrouping(prependReference, useManaged, useSemestersTerms, useCurriculumElementsTerms);
if(useCurriculumElementsTerms) {
namingAndGrouping.setCurriculumElementInfos(getCurriculumElementWebDAVInfosMap());
}
NoTermContainer noTermContainer = new NoTermContainer(namingAndGrouping);
List<RepositoryEntry> editorEntries = repositoryManager.queryByOwner(getIdentity(), true, "CourseModule");
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, containers, terms, noTermContainer, namingAndGrouping, false);
}
//add bookmarked courses
if(webDAVModule.isEnableLearnersBookmarksCourse()) {
List<RepositoryEntry> bookmarkedEntries = repositoryManager.getLearningResourcesAsBookmark(getIdentity(), identityEnv.getRoles(), "CourseModule", 0, -1);
appendCourses(bookmarkedEntries, containers, terms, noTermContainer, namingAndGrouping, false);
}
if (useSemestersTerms || useCurriculumElementsTerms) {
// add no-terms folder if any have been found
if (noTermContainer.hasNoTerms()) {
addContainerToList(noTermContainer.computeNoTermContainer(), containers);
}
} else if(noTermContainer.hasFinished()) {
addContainerToList(noTermContainer.getFinishedContainer(), containers);
}
return containers;
}
private Map<Long,List<CurriculumElementWebDAVInfos>> getCurriculumElementWebDAVInfosMap() {
List<CurriculumElementWebDAVInfos> infos = curriculumService.getCurriculumElementInfosForWebDAV(getIdentity());
Map<Long,List<CurriculumElementWebDAVInfos>> infoMap = new HashMap<>();
for(CurriculumElementWebDAVInfos info:infos) {
List<CurriculumElementWebDAVInfos> repoInfos = infoMap
.computeIfAbsent(info.getRepositoryEntryKey(), i -> new ArrayList<>());
if(!repoInfos.contains(info)) {
repoInfos.add(info);
}
}
return infoMap;
}
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;
for (RepositoryEntry re:courseEntries) {
if(namingAndGrouping.isDuplicate(re)) {
continue;
}
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);
noTermContainer.addToFinished(cfContainer);
} else if (namingAndGrouping.isUseSemesterTerms() || namingAndGrouping.isUseCurriculumElementsTerms()) {
appendCoursesWithTerms(re, containers, noTermContainer, terms, namingAndGrouping, editor);
} else {
String courseTitle = getCourseTitle(re, namingAndGrouping.isPrependReference());
String name = namingAndGrouping.getContainersUniqueName(courseTitle);
NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv);
addContainerToList(cfContainer, containers);
}
if(++count % 5 == 0) {
DBFactory.getInstance().commitAndCloseSession();
}
}
}
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.isUseManaged() && re.getEntryStatus() == RepositoryEntryStatusEnum.closed) {
String courseTitle = getCourseTitle(re, namingAndGrouping.isPrependReference());
String name = namingAndGrouping.getNoTermUniqueName(courseTitle);
NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv);
noTermContainer.add(re, cfContainer);
termed = true;
} else 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(64);
if(StringHelper.containsNonWhitespace(element.getParentCurriculumElementDisplayName())) {
if(StringHelper.containsNonWhitespace(element.getParentCurriculumElementIdentifier())) {
sb.append(element.getParentCurriculumElementIdentifier()).append(" ");
}
sb.append(element.getParentCurriculumElementDisplayName());
} else if(StringHelper.containsNonWhitespace(element.getCurriculumElementDisplayName())) {
if(StringHelper.containsNonWhitespace(element.getCurriculumElementIdentifier())) {
sb.append(element.getCurriculumElementIdentifier()).append(" ");
}
sb.append(element.getCurriculumElementDisplayName());
}
return sb.toString();
}
private static class NoTermContainer {
private final Set<RepositoryEntry> entriesSet = new HashSet<>();
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(entriesSet.contains(entry)) {
return;
} else {
entriesSet.add(entry);
}
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;
private final Set<RepositoryEntry> duplicates = new HashSet<>();
private final Set<String> containers = new HashSet<>();
private final Set<String> noTermContainer = new HashSet<>();
private final Set<String> finishedContainer = new HashSet<>();
private final Map<String,Set<String>> termContainers = new HashMap<>();
private Map<Long,List<CurriculumElementWebDAVInfos>> curriculumElementInfos;
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;
}
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;
}
public void setCurriculumElementInfos(Map<Long, List<CurriculumElementWebDAVInfos>> curriculumElementInfos) {
this.curriculumElementInfos = curriculumElementInfos;
}
public boolean hasCurriculumElements(RepositoryEntry re) {
return curriculumElementInfos != null && curriculumElementInfos.containsKey(re.getKey());
}
public boolean isDuplicate(RepositoryEntry re) {
boolean duplicate = duplicates.contains(re);
if(!duplicate) {
duplicates.add(re);
}
return duplicate;
}
private String getTermUniqueName(String term, String courseTitle) {
String name = courseTitle;
if(termContainers.containsKey(term)) {
Set<String> termContainer = termContainers.get(term);
name = getUniqueName(courseTitle, termContainer);
} else {
Set<String> termContainer = new HashSet<>();
termContainer.add(courseTitle);
termContainers.put(term, termContainer);
}
return name;
}
private String getNoTermUniqueName(String courseTitle) {
return getUniqueName(courseTitle, noTermContainer);
}
private String getFinishedUniqueName(String courseTitle) {
return getUniqueName(courseTitle, finishedContainer);
}
private String getContainersUniqueName(String courseTitle) {
return getUniqueName(courseTitle, containers);
}
private String getUniqueName(String name, Set<String> set) {
String uniqueName = name;
if(set.contains(name)) {
// attach a serial to the group name to avoid duplicate mount points...
int serial = 1;
while (set.contains(name + " " + serial) && serial < 255) {
serial++;
}
uniqueName = name + " " + serial;
}
set.add(uniqueName);
return uniqueName;
}
}
}