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 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 119 public boolean checkSourceExists(String skinName, String parentRelPath, String fileName) throws IOException 120 { 121 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 122 String parentFileURI = tempDirURI + (parentRelPath.length() > 0 ? "/" + parentRelPath : ""); 123 124 return _fileHelper.hasChild(parentFileURI, fileName); 125 } 126 127 /** 128 * Copy a file or directory 129 * @param skinName the name of the current skin 130 * @param srcPath the path of the source file or directory 131 * @param parentTargetPath the new path for the source file or directory 132 * @return a map of data 133 * @throws IOException if something went wrong during the source copy processing 134 */ 135 @Callable 136 public Map<String, Object> copySource(String skinName, String srcPath, String parentTargetPath) throws IOException 137 { 138 _checkUserRight(skinName); 139 140 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 141 142 String srcFileURI = tempDirURI + (srcPath.length() > 0 ? "/" + srcPath : ""); 143 String parentTargetURI = tempDirURI + (parentTargetPath.length() > 0 ? "/" + parentTargetPath : ""); 144 145 Map<String, Object> result = _fileHelper.copySource(srcFileURI, parentTargetURI); 146 147 // Update lock 148 FileSource rootDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 149 _lockManager.updateLockFile(rootDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 150 151 if (result.containsKey("uri")) 152 { 153 String folderUri = (String) result.get("uri"); 154 String path = folderUri.substring(rootDir.getURI().length()); 155 result.put("path", path.endsWith("/") ? path.substring(0, path.length() - 1) : path); 156 result.put("skinName", skinName); 157 } 158 159 return result; 160 } 161 162 /** 163 * Create a folder 164 * @param skinName the name of the current skin 165 * @param parentRelPath the path of the parent containing the folder 166 * @param originalName the name of the new folder 167 * @param renameIfExists if true, will generate a valid name if "originalName" already exists. 168 * @return a map of data 169 * @throws IOException if an error occurs while manipulating files 170 */ 171 @Callable 172 public Map addFolder(String skinName, String parentRelPath, String originalName, boolean renameIfExists) throws IOException 173 { 174 _checkUserRight(skinName); 175 176 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 177 String parentURI = tempDirURI + (parentRelPath.length() > 0 ? "/" + parentRelPath : ""); 178 179 Map<String, Object> result = _fileHelper.addFolder(parentURI, originalName, renameIfExists); 180 181 // Update lock 182 FileSource rootDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 183 _lockManager.updateLockFile(rootDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 184 185 if (result.containsKey("uri")) 186 { 187 String folderUri = (String) result.get("uri"); 188 String path = folderUri.substring(rootDir.getURI().length()); 189 result.put("path", path.endsWith("/") ? path.substring(0, path.length() - 1) : path); 190 result.put("parentPath", parentRelPath.endsWith("/") ? parentRelPath.substring(0, parentRelPath.length() - 1) : parentRelPath); 191 result.put("skinName", skinName); 192 } 193 194 return result; 195 } 196 197 /** 198 * Add or update a file into a skin 199 * @param skinName the name of the skin 200 * @param part The file multipart to upload 201 * @param toPath The path of parent directory 202 * @param mode The insertion mode: 'add-rename' or 'update' or null. 203 * @param unzip true to unzip .zip file 204 * @return the result map 205 * @throws IOException If an error occurred manipulating the file 206 */ 207 public Map addOrUpdateFile(String skinName, Part part, String toPath, String mode, boolean unzip) throws IOException 208 { 209 _checkUserRight(skinName); 210 211 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 212 FileSource tempDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 213 214 String parentURI = tempDirURI + (toPath.length() > 0 ? "/" + toPath : ""); 215 FileSource parentDir = (FileSource) _srcResolver.resolveURI(parentURI); 216 217 Map<String, Object> result = _fileHelper.addOrUpdateFile(part, parentDir, mode, unzip); 218 219 // Update lock 220 _lockManager.updateLockFile(tempDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 221 222 if (result.containsKey("uri")) 223 { 224 String fileUri = (String) result.get("uri"); 225 String filePath = fileUri.substring(tempDir.getURI().length()); 226 result.put("path", filePath.endsWith("/") ? filePath.substring(0, filePath.length() - 1) : filePath); 227 String parentPath = parentDir.getURI().substring(tempDir.getURI().length()); 228 result.put("parentPath", parentPath.endsWith("/") ? parentPath.substring(0, parentPath.length() - 1) : parentPath); 229 } 230 else if (result.containsKey("unzip")) 231 { 232 String parentPath = parentDir.getURI().substring(parentDir.getURI().length()); 233 result.put("parentPath", parentPath.endsWith("/") ? parentPath.substring(0, parentPath.length() - 1) : parentPath); 234 } 235 236 return result; 237 } 238 239 240 /** 241 * Delete a file or a directory 242 * @param skinName the name of the current skin 243 * @param relPath the path of the file or directory 244 * @return a map of data 245 * @throws IOException if an error occurs while manipulating files 246 */ 247 @Callable 248 public Map deleteFile(String skinName, String relPath) throws IOException 249 { 250 _checkUserRight(skinName); 251 252 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 253 String fileURI = tempDirURI + (relPath.length() > 0 ? "/" + relPath : ""); 254 255 Map result = _fileHelper.deleteFile(fileURI); 256 257 // Update lock 258 Path tempDir = _skinHelper.getTempDirectory(skinName); 259 _lockManager.updateLockFile(tempDir, SKIN_EDITOR_TOOL_ID); 260 261 return result; 262 } 263 264 /** 265 * Move a file or a directory 266 * @param skinName the name of current skin 267 * @param srcPath the path of the file or directory 268 * @param targetPath the targeted path 269 * @return a map of data 270 * @throws IOException if something goes wrong during the source moving process 271 */ 272 @Callable 273 public Map<String, Object> moveSource(String skinName, String srcPath, String targetPath) throws IOException 274 { 275 _checkUserRight(skinName); 276 277 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 278 279 String srcFileURI = tempDirURI + (srcPath.length() > 0 ? "/" + srcPath : ""); 280 String parentTargetURI = tempDirURI + (targetPath.length() > 0 ? "/" + targetPath : ""); 281 282 Map<String, Object> result = _fileHelper.moveSource(srcFileURI, parentTargetURI); 283 284 // Update lock 285 FileSource rootDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 286 _lockManager.updateLockFile(rootDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 287 288 if (result.containsKey("uri")) 289 { 290 String folderUri = (String) result.get("uri"); 291 String path = folderUri.substring(rootDir.getURI().length()); 292 result.put("path", path.endsWith("/") ? path.substring(0, path.length() - 1) : path); 293 result.put("skinName", skinName); 294 } 295 296 return result; 297 } 298 299 /** 300 * Rename a file or a directory 301 * @param skinName the current skin name 302 * @param relPath the path of the file 303 * @param name the new name 304 * @return a map of data 305 * @throws IOException if something goes wrong when renaming the source 306 */ 307 @Callable 308 public Map renameSource(String skinName, String relPath, String name) throws IOException 309 { 310 _checkUserRight(skinName); 311 312 String tempDirURI = _skinHelper.getTempDirectoryURI(skinName); 313 String fileURI = tempDirURI + (relPath.length() > 0 ? "/" + relPath : ""); 314 315 Map<String, Object> result = _fileHelper.renameFile(fileURI, name); 316 317 // Update lock 318 FileSource rootDir = null; 319 try 320 { 321 rootDir = (FileSource) _srcResolver.resolveURI(tempDirURI); 322 _lockManager.updateLockFile(rootDir.getFile().toPath(), SKIN_EDITOR_TOOL_ID); 323 } 324 finally 325 { 326 _srcResolver.release(rootDir); 327 } 328 329 if (result.containsKey("uri")) 330 { 331 String newURI = (String) result.get("uri"); 332 String path = newURI.substring(rootDir.getURI().length()); 333 result.put("path", path); 334 result.put("name", name); 335 result.put("skinName", skinName); 336 } 337 338 return result; 339 } 340 341 private void _checkUserRight(String skinName) throws IllegalStateException 342 { 343 UserIdentity user = _currentUserProvider.getUser(); 344 345 Skin skin = _skinManager.getSkin(skinName); 346 if (skin == null) 347 { 348 throw new IllegalStateException("User '" + user + "' tried to modify an unknown skin '" + skinName + "'"); 349 } 350 351 if (!skin.isModifiable()) 352 { 353 throw new IllegalStateException("User '" + user + "' tried to modify an unmodifiable skin '" + skinName + "'"); 354 } 355 356 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()))) 357 { 358 throw new IllegalStateException("User '" + user + "' tried to modify skin '" + skinName + "' without convenient right."); 359 } 360 } 361}