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.skin; 017 018import java.io.IOException; 019import java.nio.file.Files; 020import java.nio.file.Path; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026import java.util.function.Predicate; 027import java.util.stream.Collectors; 028 029import org.apache.avalon.framework.component.Component; 030import org.apache.avalon.framework.service.ServiceException; 031import org.apache.avalon.framework.service.ServiceManager; 032import org.apache.avalon.framework.service.Serviceable; 033 034import org.ametys.core.right.RightManager; 035import org.ametys.core.right.RightManager.RightResult; 036import org.ametys.core.ui.Callable; 037import org.ametys.core.user.CurrentUserProvider; 038import org.ametys.core.user.UserIdentity; 039import org.ametys.core.util.path.PathUtils; 040import org.ametys.plugins.skincommons.SkinEditionHelper; 041import org.ametys.plugins.skincommons.SkinLockManager; 042import org.ametys.runtime.i18n.I18nizableText; 043import org.ametys.web.repository.site.Site; 044import org.ametys.web.repository.site.SiteManager; 045import org.ametys.web.skin.Skin; 046import org.ametys.web.skin.SkinsManager; 047 048/** 049 * DAO for files and folders inside a skin directory 050 */ 051public class SkinDAO implements Serviceable, Component 052{ 053 /** The Avalon role */ 054 public static final String ROLE = SkinDAO.class.getName(); 055 056 /** Constant for the id of right to edit all skins */ 057 public static final String EDIT_SKINS_RIGHT_ID = "Plugins_SkinEditor_EditAllSkin"; 058 /** Constant for the id of right to edit teh current skin */ 059 public static final String EDIT_CURRENT_SKIN_RIGHT_ID = "Plugins_SkinEditor_EditCurrentSkin"; 060 061 /** Constant for skin editor tool id */ 062 public static final String SKIN_EDITOR_TOOL_ID = "uitool-skineditor"; 063 064 private static final String __WORK_MODE = "work"; 065 private static final String __PROD_MODE = "prod"; 066 067 /** The lock manager */ 068 protected SkinLockManager _lockManager; 069 /** The skin edition helper */ 070 protected SkinEditionHelper _skinHelper; 071 072 private SkinsManager _skinManager; 073 074 private CurrentUserProvider _userProvider; 075 076 private RightManager _rightManager; 077 078 private SiteManager _siteManager; 079 080 @Override 081 public void service(ServiceManager manager) throws ServiceException 082 { 083 _skinHelper = (SkinEditionHelper) manager.lookup(SkinEditionHelper.ROLE); 084 _lockManager = (SkinLockManager) manager.lookup(SkinLockManager.ROLE); 085 _skinManager = (SkinsManager) manager.lookup(SkinsManager.ROLE); 086 _userProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 087 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 088 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 089 } 090 091 /** 092 * Get the list of available and modifiable skins for a site 093 * @param siteName The site name 094 * @return the list of skins 095 */ 096 @Callable 097 public List<Object> getSkinsList(String siteName) 098 { 099 Site site = _siteManager.getSite(siteName); 100 String currentSkinId = site.getSkinId(); 101 102 Set<String> skins = new HashSet<>(); 103 104 UserIdentity user = _userProvider.getUser(); 105 if (_rightManager.hasRight(user, EDIT_SKINS_RIGHT_ID, "/${WorkspaceName}") == RightResult.RIGHT_ALLOW) 106 { 107 skins.addAll(_skinManager.getSkins()); 108 } 109 else if (_rightManager.hasRight(user, EDIT_CURRENT_SKIN_RIGHT_ID, "/${WorkspaceName}") == RightResult.RIGHT_ALLOW) 110 { 111 skins.add(currentSkinId); 112 } 113 114 return skins.stream() 115 .map(id -> _skinManager.getSkin(id)) 116 .filter(Skin::isModifiable) 117 .filter(Predicate.not(Skin::isAbstract)) 118 .map(s -> _skin2JsonObject(s, s.getId().equals(currentSkinId))) 119 .collect(Collectors.toList()); 120 } 121 122 private Map<String, Object> _skin2JsonObject (Skin skin, boolean current) 123 { 124 Map<String, Object> jsonObject = new HashMap<>(); 125 126 I18nizableText label = skin.getLabel(); 127 String icon = skin.getLargeImage(); 128 129 jsonObject.put("id", skin.getId()); 130 jsonObject.put("current", current); 131 jsonObject.put("label", label); 132 jsonObject.put("icon", icon); 133 134 return jsonObject; 135 } 136 137 /** 138 * Open a skin for editing 139 * @param skinId the skin id 140 * @param mode the edition mode 141 * @param unlinkModel True to remove any existing change 142 * @return the skin id 143 * @throws Exception if an error occurs during the skin opening process 144 */ 145 @Callable 146 public String openSkin(String skinId, String mode, boolean unlinkModel) throws Exception 147 { 148 Skin skin = _skinManager.getSkin(skinId); 149 if (!skin.isModifiable()) 150 { 151 throw new IllegalStateException("The skin '" + skinId + "' is not modifiable and thus cannot be opened in skin editor."); 152 } 153 154 Path tempDir = _skinHelper.getTempDirectory(skinId); 155 Path workDir = _skinHelper.getWorkDirectory(skinId); 156 Path skinDir = _skinHelper.getSkinDirectory(skinId); 157 158 if (unlinkModel) 159 { 160 unlinkModel (skinDir); 161 unlinkModel(workDir); 162 unlinkModel(tempDir); 163 } 164 165 if (__PROD_MODE.equals(mode) || __WORK_MODE.equals(mode)) 166 { 167 // Delete temp directory if exists 168 if (Files.exists(tempDir)) 169 { 170 _skinHelper.deleteQuicklyDirectory(tempDir); 171 } 172 173 if (__PROD_MODE.equals(mode)) 174 { 175 // Delete work directory if exists 176 if (Files.exists(workDir)) 177 { 178 _skinHelper.deleteQuicklyDirectory(workDir); 179 } 180 181 // Copy from skin 182 PathUtils.copyDirectory(skinDir, workDir); 183 } 184 185 // Copy work in temp 186 PathUtils.copyDirectory(workDir, tempDir); 187 188 // Create .lock file 189 _lockManager.updateLockFile(tempDir, SKIN_EDITOR_TOOL_ID); 190 } 191 else 192 { 193 // Update .lock file 194 _lockManager.updateLockFile(tempDir, SKIN_EDITOR_TOOL_ID); 195 } 196 197 return skinId; 198 } 199 200 /** 201 * Unlink model 202 * @param skinDir The skin directory 203 * @throws IOException If an error occurred 204 */ 205 protected void unlinkModel (Path skinDir) throws IOException 206 { 207 Path modelFile = skinDir.resolve("model.xml"); 208 Path bakFile = skinDir.resolve("model.xml.bak"); 209 210 if (Files.exists(bakFile)) 211 { 212 // Delete old bak file if exists 213 PathUtils.deleteQuietly(bakFile); 214 } 215 216 if (Files.exists(modelFile)) 217 { 218 Files.move(modelFile, bakFile); 219 } 220 } 221}