/** * <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.util.List; import org.olat.admin.user.delete.service.UserDeletionManager; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.SearchIdentityParams; import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.commons.modules.bc.FolderModule; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.services.image.ImageService; import org.olat.core.commons.services.mark.MarkManager; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.User; import org.olat.core.id.UserConstants; import org.olat.core.util.DirectoryFilter; import org.olat.core.util.FileUtils; import org.olat.core.util.StringHelper; import org.olat.core.util.resource.OresHelper; import org.olat.upgrade.model.BookmarkImpl; import org.olat.user.DisplayPortraitManager; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> * upgrade code for OpenOLAT 8.3.x -> OpenOLAT 8.4.0 * - Upgrade bookmarks to new database structure * - Recalculate small user avatar images to new size * * <P> * Initial Date: 24.03.2011 <br> * * @author Roman Haag, roman.haag@frentix.com, www.frentix.com */ public class OLATUpgrade_8_4_0 extends OLATUpgrade { private static final String TASK_BOOKMARKS = "Upgrade bookmarks"; private static final String TASK_AVATARS = "Upgrade avatars"; private static final String TASK_CHECK_MAIL_DELETED_USERS = "Check the mails of deleted users"; private static final int BATCH_SIZE = 20; private static final String VERSION = "OLAT_8.4.0"; @Autowired private DB dbInstance; @Autowired private BaseSecurity securityManager; @Autowired private MarkManager markManager; @Autowired private FolderModule folderModule; // needed to initialize FolderConfig @Autowired private ImageService imageHelper; @Autowired private UserDeletionManager userDeletionManager; public OLATUpgrade_8_4_0() { super(); } @Override public String getVersion() { return VERSION; } @Override public boolean doPreSystemInitUpgrade(UpgradeManager upgradeManager) { return false; } @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 = upgradeBookmarks(upgradeManager, uhd); allOk = (allOk && upgradeAvatars(upgradeManager, uhd)); allOk &= checkMailOfDeletedUsers(upgradeManager, uhd); uhd.setInstallationComplete(allOk); upgradeManager.setUpgradesHistory(uhd, VERSION); if(allOk) { log.audit("Finished OLATUpgrade_8_4_0 successfully!"); } else { log.audit("OLATUpgrade_8_4_0 not finished, try to restart OpenOLAT!"); } return allOk; } private boolean upgradeBookmarks(UpgradeManager upgradeManager, UpgradeHistoryData uhd) { if (!uhd.getBooleanDataValue(TASK_BOOKMARKS)) { int counter = 0; List<BookmarkImpl> bookmarks; do { bookmarks = findBookmarks(counter, BATCH_SIZE); for(BookmarkImpl bookmark:bookmarks) { processBookmarks(bookmark); } counter += bookmarks.size(); log.audit("Processed context: " + bookmarks.size()); dbInstance.intermediateCommit(); } while(bookmarks.size() == BATCH_SIZE); uhd.setBooleanDataValue(TASK_BOOKMARKS, true); upgradeManager.setUpgradesHistory(uhd, VERSION); } return true; } private void processBookmarks(BookmarkImpl bookmark) { String resName = bookmark.getOlatrestype(); Long resId = bookmark.getOlatreskey(); Identity owner = bookmark.getOwner(); OLATResourceable ores = OresHelper.createOLATResourceableInstance(resName, resId); String businessPath = null; if("RepositoryEntry".equals(resName) || "CatalogEntry".equals(resName)) { businessPath = "[" + resName + ":" + resId + "]"; } markManager.setMark(ores, owner, null, businessPath); } private List<BookmarkImpl> findBookmarks(int counter, int batchSize) { StringBuilder sb = new StringBuilder(); sb.append("select bookmark from ").append(BookmarkImpl.class.getName()).append(" as bookmark") .append(" inner join fetch bookmark.owner as identity") .append(" inner join fetch identity.user as user"); return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), BookmarkImpl.class) .setFirstResult(counter) .setMaxResults(batchSize) .getResultList(); } private boolean upgradeAvatars(UpgradeManager upgradeManager, UpgradeHistoryData uhd) { boolean success = false; if (!uhd.getBooleanDataValue(TASK_AVATARS)) { // commit because this task can take a while dbInstance.intermediateCommit(); long counter = 0; File root = new File(FolderConfig.getCanonicalRoot() + FolderConfig.getUserHomePages()); if (root.exists()) { File[] users = root.listFiles(new DirectoryFilter()); log.audit("Starting with avatar images upgrade process for " + users.length + " users"); for (File homepage : users) { File portraitDir = new File(homepage, "portrait"); if (portraitDir.exists()) { File[] files = portraitDir.listFiles(); for (File file : files) { // search for large portrait file and scald down to small size, overwriting already existing files if (file.getName().startsWith("portrait_big")) { String extension = FileUtils.getFileSuffix(file.getName()); if(!StringHelper.containsNonWhitespace(extension)) { extension = "png"; } File pSmallFile = new File(portraitDir, "portrait_small" + "." + extension); imageHelper.scaleImage(file, extension, pSmallFile, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL, false); counter++; break; } } } // else skip, no portrait, nothing to do if (counter % 1000 == 0) { // log something once in a while log.audit("Upgrade avatar images: " + counter + " user processed so far, please wait"); } } log.audit("Upgrade avatar images finished, updated " + counter + " avatar images"); success = true; } else { log.warn("Root folder for user homepages not found::" + root.getAbsolutePath()); } } uhd.setBooleanDataValue(TASK_AVATARS, success); upgradeManager.setUpgradesHistory(uhd, VERSION); return success; } private boolean checkMailOfDeletedUsers(UpgradeManager upgradeManager, UpgradeHistoryData uhd) { if (!uhd.getBooleanDataValue(TASK_CHECK_MAIL_DELETED_USERS)) { int counter = 0; List<Identity> deletedIdentities; do { SearchIdentityParams params = new SearchIdentityParams(); params.setStatus(new Integer(Identity.STATUS_DELETED)); deletedIdentities = securityManager.getIdentitiesByPowerSearch(params, counter, BATCH_SIZE); for(Identity deletedIdentity:deletedIdentities) { User deletedUser = deletedIdentity.getUser(); boolean changed = processDeletedIdentityEmail(deletedUser, UserConstants.EMAIL); changed |= processDeletedIdentityEmail(deletedUser, UserConstants.INSTITUTIONALEMAIL); if(changed) { UserManager.getInstance().updateUser(deletedUser); log.audit("Update emails of deleted identity: " + deletedIdentity.getName() + " with key: " + deletedIdentity.getKey()); } } counter += deletedIdentities.size(); log.audit("Processed deleted identities: " + deletedIdentities.size()); dbInstance.intermediateCommit(); } while(deletedIdentities.size() == BATCH_SIZE); uhd.setBooleanDataValue(TASK_CHECK_MAIL_DELETED_USERS, true); upgradeManager.setUpgradesHistory(uhd, VERSION); } return true; } private boolean processDeletedIdentityEmail(User deletedUser, String property) { String email = deletedUser.getProperty(property, null); if(StringHelper.containsNonWhitespace(email)) { int indexHat = email.indexOf('@'); int indexMark = email.indexOf(UserDeletionManager.DELETED_USER_DELIMITER); if(indexHat > 0 && (indexMark < 0 || indexMark > indexHat)) { String newEmail = userDeletionManager.getBackupStringWithDate(email); deletedUser.setProperty(property, newEmail); return true; } } return false; } }