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