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 */ 016 017package org.ametys.web.repository.page.actions; 018 019import java.util.Arrays; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.Map; 024import java.util.Set; 025 026import org.apache.avalon.framework.parameters.Parameters; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.cocoon.environment.ObjectModelHelper; 030import org.apache.cocoon.environment.Redirector; 031import org.apache.cocoon.environment.SourceResolver; 032import org.apache.commons.collections.CollectionUtils; 033import org.apache.commons.lang.ArrayUtils; 034 035import org.ametys.cms.CmsConstants; 036import org.ametys.cms.ObservationConstants; 037import org.ametys.cms.repository.Content; 038import org.ametys.cms.repository.DefaultContent; 039import org.ametys.core.observation.AbstractNotifierAction; 040import org.ametys.core.observation.Event; 041import org.ametys.plugins.repository.AmetysObjectResolver; 042import org.ametys.plugins.repository.UnknownAmetysObjectException; 043import org.ametys.web.repository.content.SharedContent; 044import org.ametys.web.repository.content.WebContent; 045import org.ametys.web.repository.content.jcr.DefaultSharedContent; 046import org.ametys.web.repository.content.shared.SharedContentManager; 047import org.ametys.web.repository.page.ContentTypesAssignmentHandler; 048import org.ametys.web.repository.page.ModifiableSitemapElement; 049import org.ametys.web.repository.page.ModifiableZone; 050import org.ametys.web.repository.page.ModifiableZoneItem; 051import org.ametys.web.repository.page.SitemapElement; 052import org.ametys.web.repository.page.ZoneItem.ZoneType; 053 054/** 055 * This action add an existing content to a zone of a page 056 */ 057public class AddSharedContentAction extends AbstractNotifierAction 058{ 059 /** The shared content manager. */ 060 protected SharedContentManager _sharedContentManager; 061 062 /** The content types assignment handler. */ 063 protected ContentTypesAssignmentHandler _cTypesAssignmentHandler; 064 065 /** Ametys object resolver */ 066 protected AmetysObjectResolver _resolver; 067 068 @Override 069 public void service(ServiceManager serviceManager) throws ServiceException 070 { 071 super.service(serviceManager); 072 _sharedContentManager = (SharedContentManager) serviceManager.lookup(SharedContentManager.ROLE); 073 _cTypesAssignmentHandler = (ContentTypesAssignmentHandler) serviceManager.lookup(ContentTypesAssignmentHandler.ROLE); 074 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 075 } 076 077 @Override 078 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 079 { 080 @SuppressWarnings("unchecked") 081 Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 082 083 String pageId = (String) jsParameters.get("zoneitem-org.ametys.web.AddSharedContentAction$pageId"); 084 String zoneName = (String) jsParameters.get("zoneitem-org.ametys.web.AddSharedContentAction$zoneName"); 085 String contentId = (String) jsParameters.get("zoneitem-org.ametys.web.AddSharedContentAction$contentId"); 086 String viewName = (String) jsParameters.get("zoneitem-org.ametys.web.AddSharedContentAction$viewName"); 087 088 try 089 { 090 SitemapElement pc = _resolver.resolveById(pageId); 091 092 if (!(pc instanceof ModifiableSitemapElement sitemapElement)) 093 { 094 throw new IllegalArgumentException("Page '" + pageId + "' is not modifiable"); 095 } 096 097 if (sitemapElement.getTemplate() == null) 098 { 099 throw new IllegalArgumentException("Page '" + pageId + "' is not of type Container"); 100 } 101 102 ModifiableZone zone; 103 if (sitemapElement.hasZone(zoneName)) 104 { 105 zone = sitemapElement.getZone(zoneName); 106 } 107 else 108 { 109 zone = sitemapElement.createZone(zoneName); 110 } 111 112 Content content = _resolver.resolveById(contentId); 113 String contentSiteName = null; 114 if (content instanceof WebContent) 115 { 116 contentSiteName = ((WebContent) content).getSiteName(); 117 } 118 119 Set<String> validCTypes = _cTypesAssignmentHandler.getAvailableContentTypes(sitemapElement, zoneName, true); 120 Set<String> contentTypes = new HashSet<>(Arrays.asList(content.getTypes())); 121 if (!CollectionUtils.containsAny(contentTypes, validCTypes)) 122 { 123 return Collections.singletonMap("error", "invalid-content-type"); 124 } 125 126 Content newContent = null; 127 if (contentSiteName == null || sitemapElement.getSiteName().equals(contentSiteName)) 128 { 129 // The content comes from the same site as the page: insert the content as a new zone item. 130 newContent = addContentReference(zone, content, viewName); 131 } 132 else 133 { 134 // The content is from a different site: create a shared content in the zone. 135 if (!(content instanceof DefaultContent) || content instanceof SharedContent) 136 { 137 throw new IllegalArgumentException("The source content must be a DefaultContent but not a SharedContent."); 138 } 139 140 DefaultContent defaultContent = (DefaultContent) content; 141 142 if (!ArrayUtils.contains(defaultContent.getAllLabels(), CmsConstants.LIVE_LABEL)) 143 { 144 return Collections.singletonMap("error", "content-not-validated"); 145 } 146 147 newContent = createSharedContent(zone, defaultContent, viewName); 148 } 149 150 sitemapElement.saveChanges(); 151 152 Map<String, Object> eventParams = new HashMap<>(); 153 eventParams.put(ObservationConstants.ARGS_CONTENT, newContent); 154 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, newContent.getId()); 155 eventParams.put(org.ametys.web.ObservationConstants.ARGS_SITEMAP_ELEMENT, sitemapElement); 156 157 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_ADDED, _getCurrentUser(), eventParams)); 158 } 159 catch (UnknownAmetysObjectException e) 160 { 161 throw new IllegalArgumentException("An error occurred adding the shared content '" + contentId + "' on the page '" + pageId + "'", e); 162 } 163 164 return EMPTY_MAP; 165 166 } 167 168 /** 169 * Add the given content as a zone item in the given zone. 170 * @param zone the zone to add the content in. 171 * @param content the content to add. 172 * @param viewName the view name. 173 * @return the same content. 174 */ 175 protected Content addContentReference(ModifiableZone zone, Content content, String viewName) 176 { 177 ModifiableZoneItem zoneItem = zone.addZoneItem(); 178 zoneItem.setType(ZoneType.CONTENT); 179 180 zoneItem.setContent(content); 181 zoneItem.setViewName(viewName); 182 183 return content; 184 } 185 186 /** 187 * Create a shared content referencing the given content and add the shared one to the zone. 188 * @param zone the zone to create the shared content in. 189 * @param originalContent the original content. 190 * @param viewName the view name. 191 * @return the created shared content. 192 */ 193 protected Content createSharedContent(ModifiableZone zone, DefaultContent originalContent, String viewName) 194 { 195 ModifiableZoneItem zoneItem = zone.addZoneItem(); 196 zoneItem.setType(ZoneType.CONTENT); 197 198 DefaultSharedContent content = _sharedContentManager.createSharedContent(zone.getSitemapElement().getSite(), originalContent); 199 200 zoneItem.setContent(content); 201 zoneItem.setViewName(viewName); 202 203 return content; 204 } 205}