001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.ui; 029 030import com.alkacon.simapi.IdentIcon; 031import com.alkacon.simapi.Simapi; 032 033import org.opencms.cache.CmsVfsNameBasedDiskCache; 034import org.opencms.file.CmsFile; 035import org.opencms.file.CmsObject; 036import org.opencms.file.CmsProject; 037import org.opencms.file.CmsProperty; 038import org.opencms.file.CmsPropertyDefinition; 039import org.opencms.file.CmsResource; 040import org.opencms.file.CmsResourceFilter; 041import org.opencms.file.CmsUser; 042import org.opencms.file.types.CmsResourceTypeImage; 043import org.opencms.loader.CmsImageScaler; 044import org.opencms.main.CmsException; 045import org.opencms.main.CmsLog; 046import org.opencms.main.OpenCms; 047import org.opencms.security.CmsRole; 048import org.opencms.util.CmsStringUtil; 049import org.opencms.workplace.CmsWorkplace; 050 051import java.awt.Color; 052import java.awt.image.BufferedImage; 053import java.io.IOException; 054import java.util.Collections; 055import java.util.List; 056 057import org.apache.commons.logging.Log; 058 059/** 060 * Generates user ident-icons.<p> 061 */ 062public class CmsUserIconHelper { 063 064 /** The color reserved for admin users. */ 065 public static final Color ADMIN_COLOR = new Color(0x00, 0x30, 0x82); 066 067 /** The big icon suffix. */ 068 public static final String BIG_ICON_SUFFIX = "_big_icon.png"; 069 070 /** The target folder name. */ 071 public static final String ICON_FOLDER = "user_icons"; 072 073 /** The small icon suffix. */ 074 public static final String SMALL_ICON_SUFFIX = "_small_icon.png"; 075 076 /** The temp folder name. */ 077 public static final String TEMP_FOLDER = "temp/"; 078 079 /** The user image folder. */ 080 public static final String USER_IMAGE_FOLDER = "/system/userimages/"; 081 082 /** The user image additional info key. */ 083 public static final String USER_IMAGE_INFO = "USER_IMAGE"; 084 085 /** Logger instance for this class. */ 086 private static final Log LOG = CmsLog.getLog(CmsUserIconHelper.class); 087 088 /** The admin cms context. */ 089 private CmsObject m_adminCms; 090 091 /** The image cache. */ 092 private CmsVfsNameBasedDiskCache m_cache; 093 094 /** The icon renderer. */ 095 private IdentIcon m_renderer; 096 097 /** 098 * Constructor.<p> 099 * 100 * @param adminCms the admin cms context 101 */ 102 public CmsUserIconHelper(CmsObject adminCms) { 103 m_adminCms = adminCms; 104 m_renderer = new IdentIcon(); 105 m_renderer.setReservedColor(ADMIN_COLOR); 106 107 m_cache = new CmsVfsNameBasedDiskCache( 108 OpenCms.getSystemInfo().getWebApplicationRfsPath() + "/" + CmsWorkplace.RFS_PATH_RESOURCES, 109 ICON_FOLDER); 110 } 111 112 /** 113 * Checks whether the given user has an individual user image.<p> 114 * 115 * @param user the user 116 * 117 * @return <code>true</code> if the given user has an individual user image 118 */ 119 public static boolean hasUserImage(CmsUser user) { 120 121 return CmsStringUtil.isNotEmptyOrWhitespaceOnly((String)user.getAdditionalInfo(USER_IMAGE_INFO)); 122 } 123 124 /** 125 * Deletes the user image of the current user.<p> 126 * 127 * @param cms the cms context 128 */ 129 public void deleteUserImage(CmsObject cms) { 130 131 CmsUser user = cms.getRequestContext().getCurrentUser(); 132 String userIconPath = (String)user.getAdditionalInfo(USER_IMAGE_INFO); 133 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(userIconPath)) { 134 try { 135 CmsObject adminCms = OpenCms.initCmsObject(m_adminCms); 136 if (adminCms.existsResource(userIconPath)) { 137 138 CmsProject tempProject = adminCms.createTempfileProject(); 139 adminCms.getRequestContext().setCurrentProject(tempProject); 140 adminCms.lockResource(userIconPath); 141 adminCms.deleteResource(userIconPath, CmsResource.DELETE_REMOVE_SIBLINGS); 142 } 143 user.deleteAdditionalInfo(CmsUserIconHelper.USER_IMAGE_INFO); 144 adminCms.writeUser(user); 145 146 try { 147 OpenCms.getPublishManager().publishProject(adminCms); 148 } catch (Exception e) { 149 LOG.error("Error publishing user image resources.", e); 150 } 151 } catch (CmsException e) { 152 LOG.error("Error deleting previous user image.", e); 153 } 154 } 155 } 156 157 /** 158 * Returns the big ident-icon path for the given user.<p> 159 * 160 * @param cms the cms context 161 * @param user the user 162 * 163 * @return the icon path 164 */ 165 public String getBigIconPath(CmsObject cms, CmsUser user) { 166 167 return getIconPath(cms, user, true); 168 } 169 170 /** 171 * Returns the small ident-icon path for the given user.<p> 172 * 173 * @param cms the cms context 174 * @param user the user 175 * 176 * @return the icon path 177 */ 178 public String getSmallIconPath(CmsObject cms, CmsUser user) { 179 180 return getIconPath(cms, user, false); 181 } 182 183 /** 184 * Handles a user image upload. 185 * The uploaded file will be scaled and save as a new file beneath /system/userimages/, the original file will be deleted.<p> 186 * 187 * @param cms the cms context 188 * @param user the user 189 * @param uploadedFile the uploaded file 190 * 191 * @return <code>true</code> in case the image was set successfully 192 */ 193 public boolean handleImageUpload(CmsObject cms, CmsUser user, String uploadedFile) { 194 195 boolean result = false; 196 try { 197 setUserImage(cms, user, uploadedFile); 198 result = true; 199 } catch (CmsException e) { 200 LOG.error("Error setting user image.", e); 201 } 202 try { 203 cms.lockResource(uploadedFile); 204 cms.deleteResource(uploadedFile, CmsResource.DELETE_REMOVE_SIBLINGS); 205 } catch (CmsException e) { 206 LOG.error("Error deleting user image temp file.", e); 207 } 208 return result; 209 } 210 211 /** 212 * Handles a user image upload. 213 * The uploaded file will be scaled and save as a new file beneath /system/userimages/, the original file will be deleted.<p> 214 * 215 * @param cms the cms context 216 * @param uploadedFiles the uploaded file paths 217 * 218 * @return <code>true</code> in case the image was set successfully 219 */ 220 public boolean handleImageUpload(CmsObject cms, List<String> uploadedFiles) { 221 222 boolean result = false; 223 if (uploadedFiles.size() == 1) { 224 String tempFile = CmsStringUtil.joinPaths(USER_IMAGE_FOLDER, TEMP_FOLDER, uploadedFiles.get(0)); 225 result = handleImageUpload(cms, cms.getRequestContext().getCurrentUser(), tempFile); 226 } 227 return result; 228 } 229 230 /** 231 * Sets the user image for the given user.<p> 232 * 233 * @param cms the cms context 234 * @param user the user 235 * @param rootPath the image root path 236 * 237 * @throws CmsException in case anything goes wrong 238 */ 239 public void setUserImage(CmsObject cms, CmsUser user, String rootPath) throws CmsException { 240 241 CmsFile tempFile = cms.readFile(cms.getRequestContext().removeSiteRoot(rootPath)); 242 CmsImageScaler scaler = new CmsImageScaler(tempFile.getContents(), tempFile.getRootPath()); 243 244 if (scaler.isValid()) { 245 scaler.setType(2); 246 scaler.setHeight(192); 247 scaler.setWidth(192); 248 byte[] content = scaler.scaleImage(tempFile); 249 String previousImage = (String)user.getAdditionalInfo(CmsUserIconHelper.USER_IMAGE_INFO); 250 String newFileName = USER_IMAGE_FOLDER 251 + user.getId().toString() 252 + "_" 253 + System.currentTimeMillis() 254 + getSuffix(tempFile.getName()); 255 CmsObject adminCms = OpenCms.initCmsObject(m_adminCms); 256 CmsProject tempProject = adminCms.createTempfileProject(); 257 adminCms.getRequestContext().setCurrentProject(tempProject); 258 if (adminCms.existsResource(newFileName)) { 259 // a user image of the given name already exists, just write the new content 260 CmsFile imageFile = adminCms.readFile(newFileName); 261 adminCms.lockResource(imageFile); 262 imageFile.setContents(content); 263 adminCms.writeFile(imageFile); 264 adminCms.writePropertyObject( 265 newFileName, 266 new CmsProperty(CmsPropertyDefinition.PROPERTY_IMAGE_SIZE, null, "w:192,h:192")); 267 268 } else { 269 // create a new user image file 270 adminCms.createResource( 271 newFileName, 272 OpenCms.getResourceManager().getResourceType(CmsResourceTypeImage.getStaticTypeName()), 273 content, 274 Collections.singletonList( 275 new CmsProperty(CmsPropertyDefinition.PROPERTY_IMAGE_SIZE, null, "w:192,h:192"))); 276 } 277 if (newFileName.equals(previousImage)) { 278 previousImage = null; 279 } 280 281 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(previousImage)) { 282 previousImage = (String)user.getAdditionalInfo(CmsUserIconHelper.USER_IMAGE_INFO); 283 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(previousImage) 284 && cms.existsResource(newFileName, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) { 285 try { 286 adminCms.lockResource(previousImage); 287 adminCms.deleteResource(previousImage, CmsResource.DELETE_REMOVE_SIBLINGS); 288 } catch (CmsException e) { 289 LOG.error("Error deleting previous user image.", e); 290 } 291 } 292 } 293 user.setAdditionalInfo(CmsUserIconHelper.USER_IMAGE_INFO, newFileName); 294 adminCms.writeUser(user); 295 296 try { 297 OpenCms.getPublishManager().publishProject(adminCms); 298 } catch (Exception e) { 299 LOG.error("Error publishing user image resources.", e); 300 } 301 302 } 303 } 304 305 /** 306 * Returns the ident-icon path for the given user.<p> 307 * 308 * @param cms the cms context 309 * @param user the user 310 * @param big <code>true</code> to retrieve the big icon 311 * 312 * @return the icon path 313 */ 314 private String getIconPath(CmsObject cms, CmsUser user, boolean big) { 315 316 String userIconPath = (String)user.getAdditionalInfo(USER_IMAGE_INFO); 317 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(userIconPath)) { 318 userIconPath += big ? "" : "?__scale=h:32,w:32,t:2"; 319 return OpenCms.getLinkManager().substituteLinkForRootPath(cms, userIconPath); 320 } 321 322 boolean isAdmin = OpenCms.getRoleManager().hasRole(cms, user.getName(), CmsRole.ADMINISTRATOR); 323 String name = user.getName() + Boolean.toString(isAdmin); 324 String rfsName = toRfsName(name, big); 325 String path = toPath(name, big); 326 if (!m_cache.hasCacheContent(rfsName)) { 327 328 BufferedImage icon = m_renderer.render(name, isAdmin, big ? 96 : 32); 329 try { 330 m_cache.saveCacheFile(rfsName, getImageBytes(icon)); 331 } catch (Exception e) { 332 LOG.error(e.getLocalizedMessage(), e); 333 } 334 } 335 return path; 336 } 337 338 /** 339 * Returns the image data 340 * @param image the image 341 * 342 * @return the data 343 * 344 * @throws IOException in case writing to the output stream failed 345 */ 346 private byte[] getImageBytes(BufferedImage image) throws IOException { 347 348 return Simapi.getImageBytes(image, Simapi.TYPE_PNG); 349 } 350 351 /** 352 * Returns the file suffix.<p> 353 * 354 * @param fileName the file name 355 * 356 * @return the suffix 357 */ 358 private String getSuffix(String fileName) { 359 360 int index = fileName.lastIndexOf("."); 361 if (index > 0) { 362 return fileName.substring(index); 363 } else { 364 return fileName; 365 } 366 } 367 368 /** 369 * Transforms user name and icon size into the image path. 370 * 371 * @param name the user name 372 * @param big <code>true</code> in case of big icons 373 * 374 * @return the path 375 */ 376 private String toPath(String name, boolean big) { 377 378 String result = CmsStringUtil.joinPaths(CmsWorkplace.getSkinUri(), ICON_FOLDER, "" + name.hashCode()); 379 if (big) { 380 result += BIG_ICON_SUFFIX; 381 } else { 382 result += SMALL_ICON_SUFFIX; 383 } 384 return result; 385 } 386 387 /** 388 * Transforms user name and icon size into the rfs image path. 389 * 390 * @param name the user name 391 * @param big <code>true</code> in case of big icons 392 * 393 * @return the path 394 */ 395 private String toRfsName(String name, boolean big) { 396 397 String result = CmsStringUtil.joinPaths(m_cache.getRepositoryPath(), "" + name.hashCode()); 398 if (big) { 399 result += BIG_ICON_SUFFIX; 400 } else { 401 result += SMALL_ICON_SUFFIX; 402 } 403 return result; 404 } 405}