001/* 002 * Copyright 2017 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.frontedition; 017 018import java.util.HashMap; 019import java.util.List; 020import java.util.Map; 021 022import javax.jcr.RepositoryException; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.context.Context; 026import org.apache.avalon.framework.context.ContextException; 027import org.apache.avalon.framework.context.Contextualizable; 028import org.apache.avalon.framework.logger.AbstractLogEnabled; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.cocoon.components.ContextHelper; 033import org.apache.cocoon.environment.Request; 034 035import org.ametys.cms.repository.Content; 036import org.ametys.core.ui.Callable; 037import org.ametys.plugins.repository.AmetysObject; 038import org.ametys.plugins.repository.AmetysObjectResolver; 039import org.ametys.plugins.repository.AmetysRepositoryException; 040import org.ametys.plugins.repository.RepositoryConstants; 041import org.ametys.plugins.repository.UnknownAmetysObjectException; 042import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; 043import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector; 044import org.ametys.web.WebConstants; 045import org.ametys.web.repository.page.Page; 046import org.ametys.web.repository.page.ZoneDAO; 047import org.ametys.web.repository.page.ZoneItem; 048 049/** 050 * Various helpers for front-edition plugin 051 */ 052public class FrontEditionHelper extends AbstractLogEnabled implements Serviceable, Component, Contextualizable 053{ 054 /** Avalon Role */ 055 public static final String ROLE = FrontEditionHelper.class.getName(); 056 057 /** The Ametys object resolver */ 058 private AmetysObjectResolver _ametysObjectResolver; 059 private ZoneDAO _zoneDAO; 060 /** Context */ 061 private Context _context; 062 063 public void service(ServiceManager manager) throws ServiceException 064 { 065 _ametysObjectResolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 066 _zoneDAO = (ZoneDAO) manager.lookup(ZoneDAO.ROLE); 067 } 068 069 public void contextualize(Context context) throws ContextException 070 { 071 _context = context; 072 } 073 074 /** 075 * Get the first available parent for the current page, in the live workspace 076 * @param pageId id of the page that need to be checked 077 * @return path of the parent (can be this page if available in live) 078 */ 079 @Callable 080 public String firstAvailableParentInLivePath(String pageId) 081 { 082 AmetysObject resolveById = _ametysObjectResolver.resolveById(pageId); 083 if (resolveById instanceof Page) 084 { 085 Page page = (Page) resolveById; 086 return firstAvailableParentInLivePath(page); 087 } 088 else 089 { 090 return ""; 091 } 092 } 093 /** 094 * Get the first available parent for the requested page, in the live version 095 * @param page page to check 096 * @return path of the parent (can be this page if available in live) 097 */ 098 public String firstAvailableParentInLivePath(Page page) 099 { 100 Request request = ContextHelper.getRequest(_context); 101 if (page == null) 102 { 103 return ""; 104 } 105 AmetysObject available = page; 106 Page availablePage = null; 107 boolean found = false; 108 String forcedWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 109 try 110 { 111 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, "live"); 112 113 while (!found) 114 { 115 try 116 { 117 AmetysObject resolveById = _ametysObjectResolver.resolveById(available.getId()); 118 if (resolveById != null) 119 { 120 found = true; 121 } 122 else 123 { 124 available = available.getParent(); 125 } 126 } 127 catch (UnknownAmetysObjectException e) 128 { 129 available = available.getParent(); 130 } 131 } 132 133 if (available instanceof Page) 134 { 135 availablePage = (Page) available; 136 } 137 } 138 finally 139 { 140 //reset workspace 141 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, forcedWorkspace); 142 } 143 return availablePage == null ? "" : availablePage.getPathInSitemap(); 144 } 145 146 /** 147 * Determines if the page exists 148 * @param pageId the page id 149 * @param editionMode true if we are in edition mode 150 * @return true if the page exists 151 */ 152 @Callable 153 public boolean pageExists(String pageId, boolean editionMode) 154 { 155 Request request = ContextHelper.getRequest(_context); 156 String currentWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 157 try 158 { 159 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, editionMode ? RepositoryConstants.DEFAULT_WORKSPACE : WebConstants.LIVE_WORKSPACE); 160 return _ametysObjectResolver.hasAmetysObjectForId(pageId); 161 } 162 finally 163 { 164 //reset workspace 165 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWorkspace); 166 } 167 } 168 169 /** 170 * Get the name of a workflow action by it's id 171 * @param contentId id of the content to check if action is available 172 * @param workflowName name of the workflow checked 173 * @param actionIds actions where the name needs to be retreived 174 * @return workwflow action name 175 */ 176 @Callable 177 public Map<Integer, String> getWorkflowActionName(String contentId, String workflowName, List<Integer> actionIds) 178 { 179 Map<Integer, String> result = new HashMap<>(); 180 for (Integer actionId : actionIds) 181 { 182 boolean hasWorkflowRight = AmetysFrontEditionHelper.hasWorkflowRight(actionId, contentId, false); 183 if (hasWorkflowRight) 184 { 185 String translatedName = AmetysFrontEditionHelper.getWorkflowName(workflowName, actionId); 186 result.put(actionId, translatedName); 187 } 188 } 189 return result; 190 } 191 192 /** 193 * Check if contents are modifiable and check all attributes restriction 194 * @param actionId the edit action id 195 * @param contentIds the id of contents 196 * @param checkEditionMode Check if we are in edition mode or not 197 * @return A Map with content id as key. The value is null if content is unmodifiable or a map of content informations as an array with path of unmodifiable attributes otherwise 198 */ 199 @Callable 200 public Map<String, Object> getModifiableContents(int actionId, List<String> contentIds, boolean checkEditionMode) 201 { 202 Map<String, Object> result = new HashMap<>(); 203 for (String contentId : contentIds) 204 { 205 Content content = _ametysObjectResolver.resolveById(contentId); 206 207 Map<String, Object> contentInfo = new HashMap<>(); 208 contentInfo.put("unmodifiableAttributes", AmetysFrontEditionHelper.getUnmodifiableAttributes(content, List.of(actionId), checkEditionMode)); 209 contentInfo.put("rights", AmetysFrontEditionHelper.getRightsForContent(content)); 210 211 result.put(contentId, contentInfo); 212 } 213 214 return result; 215 } 216 217 /** 218 * Move a zone item of a page before/after another zone item of the same page 219 * @param zoneItemId zone item to move 220 * @param zoneName name of the zone 221 * @param pageId page Id 222 * @param offset how many item back/forward to move ? (negative for up, positive to down) 223 * @return true if success 224 * @throws UnknownAmetysObjectException If an error occurred 225 * @throws AmetysRepositoryException If an error occurred 226 * @throws RepositoryException If an error occurred 227 */ 228 @Callable 229 public boolean moveZoneItemId(String zoneItemId, String zoneName, String pageId, int offset) throws UnknownAmetysObjectException, AmetysRepositoryException, RepositoryException 230 { 231 ZoneItem zoneItem = _ametysObjectResolver.resolveById(zoneItemId); 232 AmetysObject parent = zoneItem.getParent(); 233 if (parent instanceof DefaultTraversableAmetysObject) 234 { 235 DefaultTraversableAmetysObject traversableParent = (DefaultTraversableAmetysObject) parent; 236 long itemPosition = traversableParent.getChildPosition(zoneItem); 237 long targetPosition = itemPosition + offset; 238 ZoneItem targetZoneItem = traversableParent.getChildAt(targetPosition); 239 return _zoneDAO.moveZoneItemTo(zoneItemId, zoneName, offset < 0, targetZoneItem.getId(), pageId); 240 } 241 return false; 242 } 243}