001/* 002 * Copyright 2010 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.skineditor.resources; 017 018import java.io.IOException; 019import java.nio.file.Path; 020import java.util.Map; 021 022import org.apache.avalon.framework.component.Component; 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.avalon.framework.service.Serviceable; 026import org.apache.cocoon.servlet.multipart.Part; 027import org.apache.excalibur.source.SourceResolver; 028import org.apache.excalibur.source.impl.FileSource; 029 030import org.ametys.core.file.FileHelper; 031import org.ametys.core.right.RightManager; 032import org.ametys.core.right.RightManager.RightResult; 033import org.ametys.core.ui.Callable; 034import org.ametys.core.user.CurrentUserProvider; 035import org.ametys.core.user.UserIdentity; 036import org.ametys.plugins.skincommons.SkinEditionHelper; 037import org.ametys.plugins.skincommons.SkinLockManager; 038import org.ametys.plugins.skineditor.skin.SkinDAO; 039import org.ametys.web.skin.Skin; 040import org.ametys.web.skin.SkinsManager; 041 042/** 043 * DAO for files and folders inside a skin directory 044 */ 045public class SkinResourceDAO implements Serviceable, Component 046{ 047 /** Constant for skin editor tool id */ 048 public static final String ROLE = SkinResourceDAO.class.getName(); 049 /** Constant for skin editor tool id */ 050 public static final String SKIN_EDITOR_TOOL_ID = "uitool-skineditor"; 051 052 /** The lock manager */ 053 protected SkinLockManager _lockManager; 054 /** The skin edition helper */ 055 protected SkinEditionHelper _skinHelper; 056 /** The file helper */ 057 protected FileHelper _fileHelper; 058 /** The source resolver */ 059 protected SourceResolver _srcResolver; 060 /** The current user provider */ 061 protected CurrentUserProvider _currentUserProvider; 062 /** The rights manager */ 063 protected RightManager _rightManager; 064 /** The skins manager */ 065 protected SkinsManager _skinManager; 066 067 @Override 068 public void service(ServiceManager manager) throws ServiceException 069 { 070 _skinHelper = (SkinEditionHelper) manager.lookup(SkinEditionHelper.ROLE); 071 _skinManager = (SkinsManager) manager.lookup(SkinsManager.ROLE); 072 _fileHelper = (FileHelper) manager.lookup(FileHelper.ROLE); 073 _lockManager = (SkinLockManager) manager.lookup(SkinLockManager.ROLE); 074 _srcResolver = (org.apache.excalibur.source.SourceResolver) manager.lookup(org.apache.excalibur.source.SourceResolver.ROLE); 075 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 076 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 077 } 078 079 /** 080 * Saves the text in file 081 * @param skinName The name of the skin containing the resource 082 * @param relPath the relative path of file under the skin directory 083 * @param text the file content to save 084 * @return The result map 085 * @throws IOException If an error occurred while saving 086 */ 087 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 088 public Map<String, Object> save(String skinName, String relPath, String text) throws IOException 089 { 090 _checkUserRight(skinName); 091 092 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 093 094 String fileURI = tempDirURI + (relPath.length() > 0 ? "/" + relPath : ""); 095 096 Map<String, Object> result = _fileHelper.saveFile(fileURI, text); 097 098 if (result.containsKey("isI18n")) 099 { 100 _skinHelper.invalidateTempSkinCatalogues(skinName); 101 } 102 103 Path tempDir = _skinHelper.getTempDirectory(skinName); 104 // Update lock 105 _lockManager.updateLockFile(tempDir, SKIN_EDITOR_TOOL_ID); 106 107 return result; 108 } 109 110 /** 111 * checks if the resource already exists in the parent 112 * @param skinName The name of the skin containing the resource 113 * @param parentRelPath The parent path 114 * @param fileName the file name to check 115 * @return true if the file exists 116 * @throws IOException if something goes wrong while trying to retrieve a file 117 */ 118 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 119 public boolean checkSourceExists(String skinName, String parentRelPath, String fileName) throws IOException 120 { 121 _checkUserRight(skinName); 122 123 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 124 String parentFileURI = tempDirURI + (parentRelPath.length() > 0 ? "/" + parentRelPath : ""); 125 126 return _fileHelper.hasChild(parentFileURI, fileName); 127 } 128 129 /** 130 * Copy a file or directory 131 * @param skinName the name of the current skin 132 * @param srcPath the path of the source file or directory 133 * @param parentTargetPath the new path for the source file or directory 134 * @return a map of data 135 * @throws IOException if something went wrong during the source copy processing 136 */ 137 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 138 public Map<String, Object> copySource(String skinName, String srcPath, String parentTargetPath) throws IOException 139 { 140 _checkUserRight(skinName); 141 142 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 143 144 String srcFileURI = tempDirURI + (srcPath.length() > 0 ? "/" + srcPath : ""); 145 String parentTargetURI = tempDirURI + (parentTargetPath.length() > 0 ? "/" + parentTargetPath : ""); 146 147 Map<String, Object> result = _fileHelper.copySource(srcFileURI, parentTargetURI); 148 149 // Update lock 150 FileSource rootDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 151 _lockManager.updateLockFile(rootDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 152 153 if (result.containsKey("uri")) 154 { 155 String folderUri = (String) result.get("uri"); 156 String path = folderUri.substring(rootDir.getURI().length()); 157 result.put("path", path.endsWith("/") ? path.substring(0, path.length() - 1) : path); 158 result.put("skinName", skinName); 159 } 160 161 return result; 162 } 163 164 /** 165 * Create a folder 166 * @param skinName the name of the current skin 167 * @param parentRelPath the path of the parent containing the folder 168 * @param originalName the name of the new folder 169 * @param renameIfExists if true, will generate a valid name if "originalName" already exists. 170 * @return a map of data 171 * @throws IOException if an error occurs while manipulating files 172 */ 173 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 174 public Map addFolder(String skinName, String parentRelPath, String originalName, boolean renameIfExists) throws IOException 175 { 176 _checkUserRight(skinName); 177 178 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 179 String parentURI = tempDirURI + (parentRelPath.length() > 0 ? "/" + parentRelPath : ""); 180 181 Map<String, Object> result = _fileHelper.addFolder(parentURI, originalName, renameIfExists); 182 183 // Update lock 184 FileSource rootDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 185 _lockManager.updateLockFile(rootDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 186 187 if (result.containsKey("uri")) 188 { 189 String folderUri = (String) result.get("uri"); 190 String path = folderUri.substring(rootDir.getURI().length()); 191 result.put("path", path.endsWith("/") ? path.substring(0, path.length() - 1) : path); 192 result.put("parentPath", parentRelPath.endsWith("/") ? parentRelPath.substring(0, parentRelPath.length() - 1) : parentRelPath); 193 result.put("skinName", skinName); 194 } 195 196 return result; 197 } 198 199 /** 200 * Add or update a file into a skin 201 * @param skinName the name of the skin 202 * @param part The file multipart to upload 203 * @param toPath The path of parent directory 204 * @param mode The insertion mode: 'add-rename' or 'update' or null. 205 * @param unzip true to unzip .zip file 206 * @return the result map 207 * @throws IOException If an error occurred manipulating the file 208 */ 209 public Map addOrUpdateFile(String skinName, Part part, String toPath, String mode, boolean unzip) throws IOException 210 { 211 _checkUserRight(skinName); 212 213 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 214 FileSource tempDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 215 216 String parentURI = tempDirURI + (toPath.length() > 0 ? "/" + toPath : ""); 217 FileSource parentDir = (FileSource) _srcResolver.resolveURI(parentURI); 218 219 Map<String, Object> result = _fileHelper.addOrUpdateFile(part, parentDir, mode, unzip); 220 221 // Update lock 222 _lockManager.updateLockFile(tempDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 223 224 if (result.containsKey("uri")) 225 { 226 String fileUri = (String) result.get("uri"); 227 String filePath = fileUri.substring(tempDir.getURI().length()); 228 result.put("path", filePath.endsWith("/") ? filePath.substring(0, filePath.length() - 1) : filePath); 229 String parentPath = parentDir.getURI().substring(tempDir.getURI().length()); 230 result.put("parentPath", parentPath.endsWith("/") ? parentPath.substring(0, parentPath.length() - 1) : parentPath); 231 } 232 else if (result.containsKey("unzip")) 233 { 234 String parentPath = parentDir.getURI().substring(parentDir.getURI().length()); 235 result.put("parentPath", parentPath.endsWith("/") ? parentPath.substring(0, parentPath.length() - 1) : parentPath); 236 } 237 238 return result; 239 } 240 241 242 /** 243 * Delete a file or a directory 244 * @param skinName the name of the current skin 245 * @param relPath the path of the file or directory 246 * @return a map of data 247 * @throws IOException if an error occurs while manipulating files 248 */ 249 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 250 public Map deleteFile(String skinName, String relPath) throws IOException 251 { 252 _checkUserRight(skinName); 253 254 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 255 String fileURI = tempDirURI + (relPath.length() > 0 ? "/" + relPath : ""); 256 257 Map result = _fileHelper.deleteFile(fileURI); 258 259 // Update lock 260 Path tempDir = _skinHelper.getTempDirectory(skinName); 261 _lockManager.updateLockFile(tempDir, SKIN_EDITOR_TOOL_ID); 262 263 return result; 264 } 265 266 /** 267 * Move a file or a directory 268 * @param skinName the name of current skin 269 * @param srcPath the path of the file or directory 270 * @param targetPath the targeted path 271 * @return a map of data 272 * @throws IOException if something goes wrong during the source moving process 273 */ 274 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 275 public Map<String, Object> moveSource(String skinName, String srcPath, String targetPath) throws IOException 276 { 277 _checkUserRight(skinName); 278 279 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 280 281 String srcFileURI = tempDirURI + (srcPath.length() > 0 ? "/" + srcPath : ""); 282 String parentTargetURI = tempDirURI + (targetPath.length() > 0 ? "/" + targetPath : ""); 283 284 Map<String, Object> result = _fileHelper.moveSource(srcFileURI, parentTargetURI); 285 286 // Update lock 287 FileSource rootDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 288 _lockManager.updateLockFile(rootDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 289 290 if (result.containsKey("uri")) 291 { 292 String folderUri = (String) result.get("uri"); 293 String path = folderUri.substring(rootDir.getURI().length()); 294 result.put("path", path.endsWith("/") ? path.substring(0, path.length() - 1) : path); 295 result.put("skinName", skinName); 296 } 297 298 return result; 299 } 300 301 /** 302 * Rename a file or a directory 303 * @param skinName the current skin name 304 * @param relPath the path of the file 305 * @param name the new name 306 * @return a map of data 307 * @throws IOException if something goes wrong when renaming the source 308 */ 309 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 310 public Map renameSource(String skinName, String relPath, String name) throws IOException 311 { 312 _checkUserRight(skinName); 313 314 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 315 String fileURI = tempDirURI + (relPath.length() > 0 ? "/" + relPath : ""); 316 317 Map<String, Object> result = _fileHelper.renameFile(fileURI, name); 318 319 // Update lock 320 FileSource rootDir = null; 321 try 322 { 323 rootDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 324 _lockManager.updateLockFile(rootDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 325 } 326 finally 327 { 328 _srcResolver.release(rootDir); 329 } 330 331 if (result.containsKey("uri")) 332 { 333 String newURI = (String) result.get("uri"); 334 String path = newURI.substring(rootDir.getURI().length()); 335 result.put("path", path); 336 result.put("name", name); 337 result.put("skinName", skinName); 338 } 339 340 return result; 341 } 342 343 private void _checkUserRight(String skinName) throws IllegalStateException 344 { 345 UserIdentity user = _currentUserProvider.getUser(); 346 347 Skin skin = _skinManager.getSkin(skinName); 348 if (skin == null) 349 { 350 throw new IllegalStateException("User '" + user + "' tried to modify an unknown skin '" + skinName + "'"); 351 } 352 353 if (!skin.isModifiable()) 354 { 355 throw new IllegalStateException("User '" + user + "' tried to modify an unmodifiable skin '" + skinName + "'"); 356 } 357 358 if (!(_rightManager.hasRight(user, SkinDAO.EDIT_SKINS_RIGHT_ID, "/${WorkspaceName}") == RightResult.RIGHT_ALLOW || _rightManager.hasRight(user, SkinDAO.EDIT_CURRENT_SKIN_RIGHT_ID, "/${WorkspaceName}") == RightResult.RIGHT_ALLOW && skinName.equals(_skinManager.getSkinNameFromRequest()))) 359 { 360 throw new IllegalStateException("User '" + user + "' tried to modify skin '" + skinName + "' without convenient right."); 361 } 362 } 363}