diff --git a/src/main/java/org/olat/admin/user/imp/ImportStep00.java b/src/main/java/org/olat/admin/user/imp/ImportStep00.java index a34c05f068635ad44ab24ee814c46ac4a41de334..c28b8c4f1c60851930da028b2274aea2e2a9177b 100644 --- a/src/main/java/org/olat/admin/user/imp/ImportStep00.java +++ b/src/main/java/org/olat/admin/user/imp/ImportStep00.java @@ -165,6 +165,7 @@ class ImportStep00 extends BasicStep { String defaultlang = i18nModule.getDefaultLocale().toString(); List<String> importedEmails = new ArrayList<>(); + List<String> importedInstitutionalEmails = new ArrayList<>(); boolean importDataError = false; @@ -263,7 +264,7 @@ class ImportStep00 extends BasicStep { UpdateIdentity uIdentity = new UpdateIdentity(ident, pwd, lang); - importDataError |= updateUserProperties(uIdentity, ident.getUser(), parts, i, columnId, importedEmails); + importDataError |= updateUserProperties(uIdentity, ident.getUser(), parts, i, columnId, importedEmails, importedInstitutionalEmails); if(importDataError) break; importDataError |= !validatePassword(pwd, uIdentity, i); if(importDataError) break; @@ -287,7 +288,7 @@ class ImportStep00 extends BasicStep { uIdentity.setPassword(pwd); uIdentity.setLanguage(lang); - importDataError |= updateUserProperties(uIdentity, null, parts, i, columnId, importedEmails); + importDataError |= updateUserProperties(uIdentity, null, parts, i, columnId, importedEmails, importedInstitutionalEmails); if(importDataError) break; importDataError |= !validateUsername(login, uIdentity, i); if(importDataError) break; @@ -303,7 +304,7 @@ class ImportStep00 extends BasicStep { } private boolean updateUserProperties(Identity ud, User originalUser, String[] parts, int i, int columnId, - List<String> importedEmails) { + List<String> importedEmails, List<String> importedInstitutionalEmails) { boolean importDataError = false; for (int j = 0; j < userPropertyHandlers.size(); j++) { @@ -348,28 +349,53 @@ class ImportStep00 extends BasicStep { } // check that no user with same (institutional) e-mail is already in OLAT if ( (thisKey.equals(UserConstants.INSTITUTIONALEMAIL) && !thisValue.isEmpty()) || thisKey.equals(UserConstants.EMAIL)) { - if (!UserManager.getInstance().isEmailAllowed(thisValue, originalUser)) { + if (!um.isEmailAllowed(thisValue, originalUser)) { textAreaElement.setErrorKey("error.email.exists", new String[] { String.valueOf(i + 1), thisValue }); importDataError = true; break; } } // check that no user with same email is already in list - if (thisKey.equals(UserConstants.EMAIL) && StringHelper.containsNonWhitespace(thisValue) - && userModule.isEmailUnique()) { - // check that no user with same email is already in list - Integer mailPos = importedEmails.indexOf(thisValue); - boolean duplicate = mailPos != -1; - if (duplicate) { - mailPos++; - textAreaElement.setErrorKey("error.email.douplicate", - new String[] { String.valueOf(i + 1), thisValue, mailPos.toString() }); - importDataError = true; - break; - } else { - importedEmails.add(thisValue); + if(userModule.isEmailUnique() && StringHelper.containsNonWhitespace(thisValue)) { + if (thisKey.equals(UserConstants.EMAIL)) { + // check that no user with same email is already in list + int mailPos = importedEmails.indexOf(thisValue); + if(mailPos < 0) { + mailPos = importedInstitutionalEmails.indexOf(thisValue); + if(mailPos >= 0 && thisValue.equals(ud.getUser().getProperty(UserConstants.INSTITUTIONALEMAIL, getLocale()))) { + mailPos = -1; + } + } + boolean duplicate = mailPos > -1; + if (duplicate) { + mailPos++; + textAreaElement.setErrorKey("error.email.douplicate", new String[] { String.valueOf(i + 1), thisValue, Integer.toString(mailPos) }); + importDataError = true; + break; + } else { + importedEmails.add(thisValue); + } + } else if (thisKey.equals(UserConstants.INSTITUTIONALEMAIL)) { + // check that no user with same email is already in list + int mailPos = importedInstitutionalEmails.indexOf(thisValue); + if(mailPos < 0) { + mailPos = importedEmails.indexOf(thisValue); + if(mailPos >= 0 && thisValue.equals(ud.getUser().getProperty(UserConstants.EMAIL, getLocale()))) { + mailPos = -1; + } + } + boolean duplicate = mailPos > -1; + if (duplicate) { + mailPos++; + textAreaElement.setErrorKey("error.email.douplicate", new String[] { String.valueOf(i + 1), thisValue, Integer.toString(mailPos) }); + importDataError = true; + break; + } else { + importedInstitutionalEmails.add(thisValue); + } } } + ud.getUser().setProperty(thisKey, thisValue); columnId++; } @@ -476,6 +502,5 @@ class ImportStep00 extends BasicStep { } }; } - } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/vfs/VFSManager.java b/src/main/java/org/olat/core/util/vfs/VFSManager.java index 2cb16985534473b6c2f50c20ee5928a19e14ec58..987026ccb0064e7f57ce3af4c95c838bba0bd063 100644 --- a/src/main/java/org/olat/core/util/vfs/VFSManager.java +++ b/src/main/java/org/olat/core/util/vfs/VFSManager.java @@ -729,8 +729,12 @@ public class VFSManager { successful = false; } - if(withMetadata && source.canMeta() == VFSConstants.YES && target.canMeta() == VFSConstants.YES) { - CoreSpringFactory.getImpl(VFSRepositoryService.class).copyTo(source, target, target.getParentContainer()); + if(withMetadata) { + if(source.canMeta() == VFSConstants.YES && target.canMeta() == VFSConstants.YES) { + CoreSpringFactory.getImpl(VFSRepositoryService.class).copyTo(source, target, target.getParentContainer()); + } else if(target.canMeta() == VFSConstants.YES) { + CoreSpringFactory.getImpl(VFSRepositoryService.class).getMetadataFor(target); + } } } else { // source or target is null diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonRunController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonRunController.java index 64f351a0e4a9542320d2a25a231a9e4f930cc8fb..3a2837e9aa60f133b4ded648c3da17e726ebf80c 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonRunController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonRunController.java @@ -199,9 +199,11 @@ public class BigBlueButtonRunController extends BasicController implements Activ } private void back() { - mainVC.remove(meetingCtrl.getInitialComponent()); - removeAsListenerAndDispose(meetingCtrl); - meetingCtrl = null; + if(meetingCtrl != null) { + mainVC.remove(meetingCtrl.getInitialComponent()); + removeAsListenerAndDispose(meetingCtrl); + meetingCtrl = null; + } } private void doOpenMeetings(UserRequest ureq) { diff --git a/src/main/java/org/olat/modules/video/VideoManager.java b/src/main/java/org/olat/modules/video/VideoManager.java index 40278a8eab445807180c44ff005904b108c037ac..38fdc162308e353d12f6208aab730859025c0258 100644 --- a/src/main/java/org/olat/modules/video/VideoManager.java +++ b/src/main/java/org/olat/modules/video/VideoManager.java @@ -26,6 +26,7 @@ import java.util.Map; import org.olat.core.commons.services.image.Size; import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSLeaf; import org.olat.fileresource.types.ResourceEvaluation; @@ -249,7 +250,7 @@ public interface VideoManager { * The repository entry that represents the video in the repository * @param masterVideo The video file to be added to the repository. Must be an mp4 file. */ - public VideoMeta importFromMasterFile(RepositoryEntry repoEntry, VFSLeaf masterVideo); + public VideoMeta importFromMasterFile(RepositoryEntry repoEntry, VFSLeaf masterVideo, Identity initialAuthor); /** * Import the given export archive to the resource on disk @@ -260,7 +261,7 @@ public interface VideoManager { * The archive to be added to the repository. The archive must be * created by the video export feature. */ - public VideoMeta importFromExportArchive(RepositoryEntry repoEntry, VFSLeaf exportArchive); + public VideoMeta importFromExportArchive(RepositoryEntry repoEntry, VFSLeaf exportArchive, Identity initialAuthor); /** * Update video transcoding diff --git a/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java b/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java index 8014041b254cadda33b695946ad6c0f06f95d0a8..f80edbf7c571519fe4d791df7fda6a6f68ff84d0 100644 --- a/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java +++ b/src/main/java/org/olat/modules/video/manager/VideoManagerImpl.java @@ -56,8 +56,11 @@ import org.olat.core.commons.persistence.DB; import org.olat.core.commons.services.image.Crop; import org.olat.core.commons.services.image.ImageService; import org.olat.core.commons.services.image.Size; +import org.olat.core.commons.services.vfs.VFSMetadata; +import org.olat.core.commons.services.vfs.VFSRepositoryService; import org.olat.core.commons.services.video.MovieService; import org.olat.core.gui.translator.Translator; +import org.olat.core.id.Identity; import org.olat.core.logging.Tracing; import org.olat.core.util.FileUtils; import org.olat.core.util.Formatter; @@ -152,6 +155,8 @@ public class VideoManagerImpl implements VideoManager { @Autowired private VideoMetadataDAO videoMetadataDao; @Autowired + private VFSRepositoryService vfsRepositoryService; + @Autowired private Scheduler scheduler; @Autowired private ImageService imageHelper; @@ -292,7 +297,6 @@ public class VideoManagerImpl implements VideoManager { // close everything to prevent resource leaks frameOutputStream.close(); - in.close(); return true; } catch (Exception | AssertionError e) { @@ -343,7 +347,6 @@ public class VideoManagerImpl implements VideoManager { } // close everything to prevent resource leaks frameOutputStream.close(); - in.close(); return imgBlack; } catch (Exception | AssertionError e) { @@ -665,13 +668,13 @@ public class VideoManagerImpl implements VideoManager { } @Override - public VideoMeta importFromMasterFile(RepositoryEntry repoEntry, VFSLeaf masterVideo) { + public VideoMeta importFromMasterFile(RepositoryEntry repoEntry, VFSLeaf masterVideo, Identity initialAuthor) { OLATResource videoResource = repoEntry.getOlatResource(); // 1) copy master video to final destination with standard name VFSContainer masterContainer = getMasterContainer(videoResource); VFSLeaf targetFile = VFSManager.resolveOrCreateLeafFromPath(masterContainer, FILENAME_VIDEO_MP4); - VFSManager.copyContent(masterVideo, targetFile, false); + VFSManager.copyContent(masterVideo, targetFile, true); masterVideo.delete(); // calculate video duration @@ -694,12 +697,18 @@ public class VideoManagerImpl implements VideoManager { createVideoMetadata(repoEntry, targetFile.getSize(), targetFile.getName()); dbInstance.commit(); meta = updateVideoMetadata(videoResource, targetFile); + + VFSMetadata vfsMetadata = targetFile.getMetaInfo(); + if(vfsMetadata != null) { + vfsMetadata.setAuthor(initialAuthor); + vfsRepositoryService.updateMetadata(vfsMetadata); + } } return meta; } @Override - public VideoMeta importFromExportArchive(RepositoryEntry repoEntry, VFSLeaf exportArchive) { + public VideoMeta importFromExportArchive(RepositoryEntry repoEntry, VFSLeaf exportArchive, Identity initialAuthor) { OLATResource videoResource = repoEntry.getOlatResource(); // 1) unzip archive VFSContainer baseContainer= FileResourceManager.getInstance().getFileResourceRootImpl(videoResource); @@ -746,6 +755,12 @@ public class VideoManagerImpl implements VideoManager { if(meta != null && meta.getWidth() == 800 && meta.getHeight() == 600) { meta = updateVideoMetadata(videoResource, videoFile); } + + VFSMetadata vfsMetadata = videoFile.getMetaInfo(); + if(vfsMetadata != null) { + vfsMetadata.setAuthor(initialAuthor); + vfsRepositoryService.updateMetadata(vfsMetadata); + } } return meta; } @@ -897,6 +912,9 @@ public class VideoManagerImpl implements VideoManager { VFSContainer masterContainer = getMasterContainer(entry.getOlatResource()); VFSLeaf posterFile = masterContainer.createChildLeaf(FILENAME_POSTER_JPG); + if(url.contains(" ")) { + url = url.replace(" ", "%20"); + } HttpGet get = new HttpGet(url); get.addHeader("Accept", "image/jpg"); @@ -927,6 +945,9 @@ public class VideoManagerImpl implements VideoManager { } VFSLeaf videoFile = tmpContainer.createChildLeaf(FILENAME_VIDEO_MP4); + if(url.contains(" ")) { + url = url.replace(" ", "%20"); + } HttpGet get = new HttpGet(url); get.addHeader("Accept", "video/mp4"); @@ -936,6 +957,8 @@ public class VideoManagerImpl implements VideoManager { } catch(Exception e) { log.error("", e); } + // make sure that a metadata is created + vfsRepositoryService.getMetadataFor(videoFile); return videoFile; } @@ -947,8 +970,6 @@ public class VideoManagerImpl implements VideoManager { log.error("", e); } } - - @Override public VideoTranscoding updateVideoTranscoding(VideoTranscoding videoTranscoding) { diff --git a/src/main/java/org/olat/repository/handlers/VideoHandler.java b/src/main/java/org/olat/repository/handlers/VideoHandler.java index 7f9540a1607a3cd91d596616dde10d80ab538a42..5310bfc8945709ccb56f40a6ad0cc25242827b65 100644 --- a/src/main/java/org/olat/repository/handlers/VideoHandler.java +++ b/src/main/java/org/olat/repository/handlers/VideoHandler.java @@ -172,10 +172,10 @@ public class VideoHandler extends FileHandler { VideoMeta videoMeta = null; if (fileName.endsWith(".mp4") || fileName.endsWith(".mov") || fileName.endsWith(".m4v")) { // 2a) import video from raw mp4 master video file - videoMeta = videoManager.importFromMasterFile(repoEntry, importFile); + videoMeta = videoManager.importFromMasterFile(repoEntry, importFile, initialAuthor); } else if (fileName.endsWith(".zip")) { // 2b) import video from archive from another OpenOLAT instance - videoMeta = videoManager.importFromExportArchive(repoEntry, importFile); + videoMeta = videoManager.importFromExportArchive(repoEntry, importFile, initialAuthor); } dbInstance.commit(); diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_14_2_10.java b/src/main/java/org/olat/upgrade/OLATUpgrade_14_2_10.java new file mode 100644 index 0000000000000000000000000000000000000000..faf7c023ee175d4d8a960a82be494a28533f67f0 --- /dev/null +++ b/src/main/java/org/olat/upgrade/OLATUpgrade_14_2_10.java @@ -0,0 +1,144 @@ +/** + * <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.upgrade; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.apache.logging.log4j.Logger; +import org.olat.basesecurity.manager.IdentityDAO; +import org.olat.core.commons.persistence.DB; +import org.olat.core.commons.services.vfs.VFSMetadata; +import org.olat.core.commons.services.vfs.manager.VFSRepositoryServiceImpl; +import org.olat.core.id.Identity; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.fileresource.FileResourceManager; +import org.olat.fileresource.types.VideoFileResource; +import org.olat.modules.video.VideoManager; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; +import org.olat.resource.OLATResource; +import org.olat.resource.OLATResourceManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 19 mai 2020<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class OLATUpgrade_14_2_10 extends OLATUpgrade { + + private static final Logger log = Tracing.createLoggerFor(OLATUpgrade_14_2_10.class); + + private static final String VERSION = "OLAT_14.2.10"; + private static final String VIDEO_VFS_METADATA = "VIDEO VFS METADATA"; + + @Autowired + private DB dbInstance; + @Autowired + private IdentityDAO identityDao; + @Autowired + private VideoManager videoManager; + @Autowired + private RepositoryManager repositoryManager; + @Autowired + private VFSRepositoryServiceImpl vfsRepositoryService; + + public OLATUpgrade_14_2_10() { + super(); + } + + @Override + public String getVersion() { + return VERSION; + } + + @Override + public boolean doPostSystemInitUpgrade(UpgradeManager upgradeManager) { + UpgradeHistoryData uhd = upgradeManager.getUpgradesHistory(VERSION); + if (uhd == null) { + // has never been called, initialize + uhd = new UpgradeHistoryData(); + } else if (uhd.isInstallationComplete()) { + return false; + } + + boolean allOk = true; + allOk &= createVideoVfsMetadata(upgradeManager, uhd); + + uhd.setInstallationComplete(allOk); + upgradeManager.setUpgradesHistory(uhd, VERSION); + if(allOk) { + log.info(Tracing.M_AUDIT, "Finished OLATUpgrade_14_2_10 successfully!"); + } else { + log.info(Tracing.M_AUDIT, "OLATUpgrade_14_2_10 not finished, try to restart OpenOlat!"); + } + return allOk; + } + + private boolean createVideoVfsMetadata(UpgradeManager upgradeManager, UpgradeHistoryData uhd) { + boolean allOk = true; + if (!uhd.getBooleanDataValue(VIDEO_VFS_METADATA)) { + + List<String> videoTypes = Arrays.asList(VideoFileResource.TYPE_NAME); + List<OLATResource> videos = OLATResourceManager.getInstance().findResourceByTypes(videoTypes); + log.info("Number of video to upgrade: {}", videos.size()); + for (OLATResource ores : videos) { + createVideoVfsMetadata(ores); + dbInstance.commitAndCloseSession(); + } + + uhd.setBooleanDataValue(VIDEO_VFS_METADATA, allOk); + upgradeManager.setUpgradesHistory(uhd, VERSION); + } + return allOk; + } + + private void createVideoVfsMetadata(OLATResource ores) { + try { + File resourceDir = FileResourceManager.getInstance().getFileResourceRoot(ores); + vfsRepositoryService.migrateDirectories(resourceDir); + + VFSLeaf masterFile = videoManager.getMasterVideoFile(ores); + if(masterFile == null) { + return; + } + + VFSMetadata vfsMetadata = masterFile.getMetaInfo(); + if(vfsMetadata != null && vfsMetadata.getAuthor() == null) { + RepositoryEntry entry = repositoryManager.lookupRepositoryEntry(ores, false); + if(entry != null && StringHelper.containsNonWhitespace(entry.getInitialAuthor())) { + Identity author = identityDao.findIdentityByName(entry.getInitialAuthor()); + if(author != null) { + vfsMetadata.setAuthor(author); + vfsRepositoryService.updateMetadata(vfsMetadata); + } + } + } + } catch (IOException e) { + log.error("", e); + } + } +} diff --git a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml index d7acc0fc3a8b86ff4df3f4963a106961219730e0..688a4d71ef6c85c89f43f9c3f41c175cf3979782 100644 --- a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml +++ b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml @@ -56,6 +56,7 @@ <bean id="upgrade_14_2_0" class="org.olat.upgrade.OLATUpgrade_14_2_0"/> <bean id="upgrade_14_2_6" class="org.olat.upgrade.OLATUpgrade_14_2_6"/> <bean id="upgrade_14_2_7" class="org.olat.upgrade.OLATUpgrade_14_2_7"/> + <bean id="upgrade_14_2_10" class="org.olat.upgrade.OLATUpgrade_14_2_10"/> <bean id="upgrade_15_pre_6" class="org.olat.upgrade.OLATUpgrade_15_pre_6"/><!-- because really quicker as pre.0 --> <bean id="upgrade_15_pre_8" class="org.olat.upgrade.OLATUpgrade_15_pre_8"/> <bean id="upgrade_15_pre_0" class="org.olat.upgrade.OLATUpgrade_15_pre_0"/>