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.ObservationConstants; 036import org.ametys.cms.repository.Content; 037import org.ametys.cms.repository.DefaultContent; 038import org.ametys.core.observation.AbstractNotifierAction; 039import org.ametys.core.observation.Event; 040import org.ametys.plugins.repository.AmetysObjectResolver; 041import org.ametys.plugins.repository.UnknownAmetysObjectException; 042import org.ametys.web.WebConstants; 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.ModifiablePage; 049import org.ametys.web.repository.page.ModifiableZone; 050import org.ametys.web.repository.page.ModifiableZoneItem; 051import org.ametys.web.repository.page.Page.PageType; 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 metadataSetName = (String) jsParameters.get("zoneitem-org.ametys.web.AddSharedContentAction$metadataSetName"); 087 088 try 089 { 090 // FIXME API Test if not modifiable 091 ModifiablePage page = _resolver.resolveById(pageId); 092 093 if (page.getType() != PageType.CONTAINER) 094 { 095 throw new IllegalArgumentException("Page '" + pageId + "' is not of type Container"); 096 } 097 098 ModifiableZone zone; 099 if (page.hasZone(zoneName)) 100 { 101 zone = page.getZone(zoneName); 102 } 103 else 104 { 105 zone = page.createZone(zoneName); 106 } 107 108 Content content = _resolver.resolveById(contentId); 109 String contentSiteName = null; 110 if (content instanceof WebContent) 111 { 112 contentSiteName = ((WebContent) content).getSiteName(); 113 } 114 115 Set<String> validCTypes = _cTypesAssignmentHandler.getAvailableContentTypes(page, zoneName, true); 116 Set<String> contentTypes = new HashSet<>(Arrays.asList(content.getTypes())); 117 if (!CollectionUtils.containsAny(contentTypes, validCTypes)) 118 { 119 return Collections.singletonMap("error", "invalid-content-type"); 120 } 121 122 Content newContent = null; 123 if (contentSiteName == null || page.getSiteName().equals(contentSiteName)) 124 { 125 // The content comes from the same site as the page: insert the content as a new zone item. 126 newContent = addContentReference(zone, content, metadataSetName); 127 } 128 else 129 { 130 // The content is from a different site: create a shared content in the zone. 131 if (!(content instanceof DefaultContent) || content instanceof SharedContent) 132 { 133 throw new IllegalArgumentException("The source content must be a DefaultContent but not a SharedContent."); 134 } 135 136 DefaultContent defaultContent = (DefaultContent) content; 137 138 if (!ArrayUtils.contains(defaultContent.getAllLabels(), WebConstants.LIVE_LABEL)) 139 { 140 return Collections.singletonMap("error", "content-not-validated"); 141 } 142 143 newContent = createSharedContent(zone, defaultContent, metadataSetName); 144 } 145 146 page.saveChanges(); 147 148 Map<String, Object> eventParams = new HashMap<>(); 149 eventParams.put(ObservationConstants.ARGS_CONTENT, newContent); 150 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, newContent.getId()); 151 eventParams.put(org.ametys.web.ObservationConstants.ARGS_PAGE, page); 152 153 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_ADDED, _getCurrentUser(), eventParams)); 154 } 155 catch (UnknownAmetysObjectException e) 156 { 157 throw new IllegalArgumentException("An error occurred adding the shared content '" + contentId + "' on the page '" + pageId + "'", e); 158 } 159 160 return EMPTY_MAP; 161 162 } 163 164 /** 165 * Add the given content as a zone item in the given zone. 166 * @param zone the zone to add the content in. 167 * @param content the content to add. 168 * @param metadataSetName the metadata set name. 169 * @return the same content. 170 */ 171 protected Content addContentReference(ModifiableZone zone, Content content, String metadataSetName) 172 { 173 ModifiableZoneItem zoneItem = zone.addZoneItem(); 174 zoneItem.setType(ZoneType.CONTENT); 175 176 zoneItem.setContent(content); 177 zoneItem.setMetadataSetName(metadataSetName); 178 179 return content; 180 } 181 182 /** 183 * Create a shared content referencing the given content and add the shared one to the zone. 184 * @param zone the zone to create the shared content in. 185 * @param originalContent the original content. 186 * @param metadataSetName the metadata set name. 187 * @return the created shared content. 188 */ 189 protected Content createSharedContent(ModifiableZone zone, DefaultContent originalContent, String metadataSetName) 190 { 191 ModifiableZoneItem zoneItem = zone.addZoneItem(); 192 zoneItem.setType(ZoneType.CONTENT); 193 194 DefaultSharedContent content = _sharedContentManager.createSharedContent(zone.getPage().getSite(), originalContent); 195 196 zoneItem.setContent(content); 197 zoneItem.setMetadataSetName(metadataSetName); 198 199 return content; 200 } 201}