001/*
002 *  Copyright 2014 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.explorer.calendars.workflow;
017
018import java.util.Date;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.commons.lang.IllegalClassException;
026import org.apache.commons.lang.StringUtils;
027
028import org.ametys.core.observation.Event;
029import org.ametys.core.observation.ObservationManager;
030import org.ametys.core.user.CurrentUserProvider;
031import org.ametys.core.user.UserIdentity;
032import org.ametys.core.util.DateUtils;
033import org.ametys.plugins.explorer.ExplorerNode;
034import org.ametys.plugins.explorer.ObservationConstants;
035import org.ametys.plugins.explorer.calendars.CalendarEvent;
036import org.ametys.plugins.explorer.calendars.ModifiableCalendar;
037import org.ametys.plugins.explorer.calendars.ModifiableCalendarEvent;
038import org.ametys.plugins.explorer.calendars.jcr.JCRCalendarEventFactory;
039import org.ametys.plugins.explorer.workflow.AbstractExplorerNodeWorkflowComponent;
040import org.ametys.plugins.repository.AmetysObjectResolver;
041import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
042import org.ametys.plugins.workflow.store.AmetysObjectWorkflowStore;
043
044import com.opensymphony.module.propertyset.PropertySet;
045import com.opensymphony.workflow.FunctionProvider;
046import com.opensymphony.workflow.StoreException;
047import com.opensymphony.workflow.WorkflowException;
048import com.opensymphony.workflow.spi.WorkflowEntry;
049import com.opensymphony.workflow.spi.WorkflowStore;
050
051/**
052 * Action for adding a calendar event
053 */
054public class AddEventFunction extends AbstractExplorerNodeWorkflowComponent implements FunctionProvider
055{
056    /** The Ametys object resolver */
057    protected AmetysObjectResolver _resolver;
058    
059    /** Observer manager. */
060    protected ObservationManager _observationManager;
061    
062    /** The current user provider. */
063    protected CurrentUserProvider _currentUserProvider;
064    
065    @Override
066    public void service(ServiceManager smanager) throws ServiceException
067    {
068        super.service(smanager);
069        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
070        _observationManager = (ObservationManager) smanager.lookup(ObservationManager.ROLE);
071        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
072    }
073    
074    @Override
075    public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException
076    {
077        @SuppressWarnings("unchecked")
078        Map<String, Object> jsParameters = (Map<String, Object>) transientVars.get("parameters");
079        if (jsParameters == null)
080        {
081            throw new WorkflowException("Missing JS parameters");
082        }
083        
084        ExplorerNode object = getExplorerNode(transientVars);
085       
086        String parentId = (String) jsParameters.get("parentId");
087        
088        UserIdentity user = getUser(transientVars);
089        String selectedNode = (String) jsParameters.get("selectedNode");
090        
091        @SuppressWarnings("unchecked")
092        Map<String, Object> result = (Map<String, Object>) transientVars.get("result");
093        
094        // FIXME EXPLORER-441 Remove "renameIfExists" on calendar events workflow
095        // boolean renameIfExists = (Boolean) jsParameters.get("renameIfExists");
096        assert parentId != null;
097        
098        if (!(object instanceof ModifiableCalendar))
099        {
100            throw new IllegalClassException(ModifiableCalendar.class, object.getClass());
101        }
102        
103        ModifiableCalendar modifiableCalendar = (ModifiableCalendar) object;
104
105        // Create new event
106        ModifiableCalendarEvent event = ((ModifiableTraversableAmetysObject) modifiableCalendar).createChild("ametys:calendar-event", JCRCalendarEventFactory.CALENDAR_EVENT_NODETYPE);
107        event.setCreationDate(new Date());
108        event.setCreator(user);
109
110        // Set event's properties
111        _setEventData(event, transientVars, jsParameters);
112        
113        // Bind workflow store
114        _initializeWorkflow(event, transientVars, jsParameters);
115        
116        modifiableCalendar.saveChanges();
117        
118        transientVars.put("eventId", event.getId());
119        
120        result.put("id", event.getId());
121        result.put("parentId",  selectedNode == null ? parentId : selectedNode); 
122        
123        // Notify listeners
124        _notifyListeners(event);
125    }
126    
127    /**
128     * Initialize the workflow store
129     * @param event The event
130     * @param transientVars The transient variables
131     * @param jsParameters The JS parameters
132     * @throws WorkflowException if an error occurred
133     */
134    protected void _initializeWorkflow (ModifiableCalendarEvent event, Map transientVars, Map<String, Object> jsParameters) throws WorkflowException
135    {
136        long workflowId = ((WorkflowEntry) transientVars.get("entry")).getId();
137        
138        try
139        {
140            event.setWorkflowId(workflowId);
141            WorkflowStore workflowStore = (WorkflowStore) transientVars.get("store");
142            
143            if (workflowStore instanceof AmetysObjectWorkflowStore)
144            {
145                AmetysObjectWorkflowStore ametysObjectWorkflowStore = (AmetysObjectWorkflowStore) workflowStore;
146                ametysObjectWorkflowStore.bindAmetysObject(event);
147            }
148        }
149        catch (StoreException e)
150        {
151            throw new WorkflowException("Unable to link the workflow to the content", e);
152        }
153    }
154    
155    /**
156     * Set the event data
157     * @param event The event
158     * @param transientVars The transient variables
159     * @param jsParameters The JS parameters
160     * @throws WorkflowException if an error occurred
161     */
162    protected void _setEventData (ModifiableCalendarEvent event, Map transientVars, Map<String, Object> jsParameters) throws WorkflowException
163    {
164        String title = (String) jsParameters.get("title");
165        String desc = (String) jsParameters.get("description");
166        String startDateAsString = (String) jsParameters.get("startDate");
167        Date startDate = DateUtils.parse(startDateAsString);
168        String endDateAsString = (String) jsParameters.get("endDate");
169        Date endDate = DateUtils.parse(endDateAsString);
170        
171        Object rawFullDay = jsParameters.get("fullDay");
172        Boolean fullDay = rawFullDay instanceof Boolean ? (Boolean) rawFullDay : Boolean.parseBoolean((String) rawFullDay);
173        
174        String recurrenceType = (String) jsParameters.get("recurrenceType");
175        String untilDateAsString = (String) jsParameters.get("untilDate");
176        Date untilDate = DateUtils.parse(untilDateAsString);
177        
178        UserIdentity user = getUser(transientVars);
179        
180        event.setTitle(title);
181        event.setDescription(desc);
182        event.setFullDay(fullDay);
183        
184        event.setStartDate(startDate);
185        event.setLastContributor(user);
186        event.setLastModified(new Date());
187        
188        event.setRecurrenceType(recurrenceType);
189        if (untilDate !=  null)
190        {
191            event.setRepeatUntil(untilDate);
192        }
193              
194        event.setEndDate(endDate);
195        
196        String location = (String) jsParameters.get("location");
197        if (StringUtils.isNotEmpty(location))
198        {
199            event.setLocation(location);
200        }
201        
202        @SuppressWarnings("unchecked")
203        List<String> keywords = (List<String>) jsParameters.get("keywords");
204        if (keywords != null)
205        {
206            event.setKeywords(keywords.toArray(new String[keywords.size()]));
207        }
208    }
209    
210    /**
211     * Notify listeners that the event has been created
212     * @param event The created event
213     */
214    protected void _notifyListeners (CalendarEvent event)
215    {
216        Map<String, Object> eventParams = new HashMap<>();
217        eventParams.put(ObservationConstants.ARGS_CALENDAR, event.getParent());
218        eventParams.put(ObservationConstants.ARGS_CALENDAR_EVENT, event);
219        eventParams.put(ObservationConstants.ARGS_ID, event.getId());
220        eventParams.put(ObservationConstants.ARGS_PARENT_ID, event.getParent().getId());
221        
222        _observationManager.notify(new Event(ObservationConstants.EVENT_CALENDAR_EVENT_CREATED, _currentUserProvider.getUser(), eventParams));
223    }
224}