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.ArrayList; 019import java.util.Date; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import org.ametys.core.observation.Event; 025import org.ametys.core.observation.ObservationManager; 026import org.ametys.core.user.CurrentUserProvider; 027import org.ametys.plugins.explorer.ObservationConstants; 028import org.ametys.plugins.explorer.calendars.Calendar; 029import org.ametys.plugins.explorer.calendars.CalendarEvent; 030import org.ametys.plugins.explorer.calendars.EventRecurrenceTypeEnum; 031import org.ametys.plugins.explorer.calendars.ModifiableCalendar; 032import org.ametys.plugins.explorer.calendars.ModifiableCalendarEvent; 033import org.ametys.plugins.explorer.workflow.AbstractExplorerNodeWorkflowComponent; 034import org.ametys.plugins.repository.AmetysObject; 035import org.ametys.plugins.repository.AmetysObjectResolver; 036import org.ametys.plugins.repository.AmetysRepositoryException; 037import org.ametys.plugins.workflow.support.WorkflowProvider; 038import org.ametys.runtime.parameter.ParameterHelper; 039import org.ametys.runtime.parameter.ParameterHelper.ParameterType; 040import org.apache.avalon.framework.service.ServiceException; 041import org.apache.avalon.framework.service.ServiceManager; 042import org.apache.commons.lang.IllegalClassException; 043 044import com.opensymphony.module.propertyset.PropertySet; 045import com.opensymphony.workflow.Workflow; 046import com.opensymphony.workflow.WorkflowException; 047import com.opensymphony.workflow.spi.WorkflowEntry; 048 049/** 050 * Action for editing a calendar event 051 */ 052public class EditEventFunction extends AddEventFunction 053{ 054 /** Workflow provider */ 055 protected WorkflowProvider _workflowProvider; 056 057 @Override 058 public void service(ServiceManager smanager) throws ServiceException 059 { 060 super.service(smanager); 061 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 062 _observationManager = (ObservationManager) smanager.lookup(ObservationManager.ROLE); 063 _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE); 064 _workflowProvider = (WorkflowProvider) smanager.lookup(WorkflowProvider.ROLE); 065 } 066 067 @Override 068 public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException 069 { 070 @SuppressWarnings("unchecked") 071 Map<String, Object> jsParameters = (Map<String, Object>) transientVars.get("parameters"); 072 if (jsParameters == null) 073 { 074 throw new WorkflowException("no parameters defined"); 075 } 076 077 String eventId = (String) jsParameters.get("id"); 078 CalendarEvent event = _resolver.resolveById(eventId); 079 080 String parentId = (String) jsParameters.get("parentId"); 081 Calendar calendar = _resolver.resolveById(parentId); 082 083 if (!(calendar instanceof ModifiableCalendar)) 084 { 085 throw new IllegalClassException(ModifiableCalendar.class, calendar.getClass()); 086 } 087 088 if (!(event instanceof ModifiableCalendarEvent)) 089 { 090 throw new IllegalClassException(ModifiableCalendarEvent.class, event.getClass()); 091 } 092 093 ModifiableCalendarEvent mEvent = (ModifiableCalendarEvent) event; 094 ModifiableCalendar mCalendar = (ModifiableCalendar) calendar; 095 096 String choice = (String) jsParameters.get("choice"); 097 098 @SuppressWarnings("unchecked") 099 Map<String, Object> result = (Map<String, Object>) transientVars.get("result"); 100 101 if ("unit".equals(choice)) 102 { 103 // Create a new event from the edited occurrence 104 _createEventFromOccurrence(mEvent, mCalendar, transientVars, jsParameters); 105 106 // Exclude this occurrence from the initial event 107 String occurrenceDateAsString = (String) jsParameters.get("occurrenceDate"); 108 Date occurrenceDate = (Date) ParameterHelper.castValue(occurrenceDateAsString, ParameterType.DATE); 109 _excludeOccurrence(mEvent, occurrenceDate); 110 111 mEvent.saveChanges(); 112 113 _notifyListeners(mEvent); 114 } 115 else 116 { 117 // FIXME EXPLORER-441 Remove "renameIfExists" on calendar events workflow 118 // boolean renameIfExists = (Boolean) jsParameters.get("renameIfExists"); 119 assert parentId != null; 120 121 AmetysObject object = _resolver.resolveById(parentId); 122 if (!(object instanceof ModifiableCalendar)) 123 { 124 throw new IllegalClassException(ModifiableCalendar.class, object.getClass()); 125 } 126 127 long workflowId = ((WorkflowEntry) transientVars.get("entry")).getId(); 128 event.setWorkflowId(workflowId); 129 130 // Compute the event's dates from the dates of the modified occurrence 131 Date[] dates = _computeEventDates(event, jsParameters); 132 133 _setEventData(mEvent, transientVars, jsParameters); 134 135 mEvent.setStartDate(dates[0]); 136 mEvent.setEndDate(dates[1]); 137 138 mEvent.saveChanges(); 139 140 result.put("id", event.getId()); 141 result.put("parentId", parentId); 142 143 // Notify listeners 144 _notifyListeners(mEvent); 145 } 146 } 147 148 /** 149 * Create a new event from the occurrence of a event 150 * @param initialEvent The initial event 151 * @param parentCalendar The parent calendar 152 * @param transientVars The transient variable 153 * @param jsParameters The JS parameters 154 */ 155 protected void _createEventFromOccurrence (CalendarEvent initialEvent, Calendar parentCalendar, Map transientVars, Map<String, Object> jsParameters) 156 { 157 @SuppressWarnings("unchecked") 158 Map<String, Object> result = (Map<String, Object>) transientVars.get("result"); 159 160 // Computed workflow parameters to create a new event 161 if (!jsParameters.containsKey("title")) 162 { 163 jsParameters.put("title", initialEvent.getTitle()); 164 jsParameters.put("desc", initialEvent.getDescription()); 165 jsParameters.put("fullDay", initialEvent.getFullDay()); 166 } 167 jsParameters.put("recurrenceType", EventRecurrenceTypeEnum.NEVER.toString()); 168 jsParameters.put("untilDate", null); 169 170 Map<String, Object> inputs = new HashMap<>(); 171 inputs.put("parameters", jsParameters); 172 inputs.put(AbstractExplorerNodeWorkflowComponent.EXPLORERNODE_KEY, parentCalendar); 173 inputs.put("result", result); 174 175 String workflowName = parentCalendar.getWorkflowName(); 176 try 177 { 178 // Create a new event from the edited occurrence 179 Workflow workflow = _workflowProvider.getAmetysObjectWorkflow(); 180 workflow.initialize(workflowName, 1, inputs); 181 } 182 catch (WorkflowException e) 183 { 184 throw new AmetysRepositoryException("Unable to create a new event with workflow '" + workflowName + "' and action 1'", e); 185 } 186 } 187 188 /** 189 * Exclude a occurrence of a event 190 * @param event The event 191 * @param occurrenceDate The date to exclude 192 */ 193 protected void _excludeOccurrence (ModifiableCalendarEvent event, Date occurrenceDate) 194 { 195 List<Date> excludedOccurrences = new ArrayList<>(event.getExcludedOccurences()); 196 197 java.util.Calendar gCalendar = java.util.Calendar.getInstance(); 198 gCalendar.setTime(occurrenceDate); 199 gCalendar.set(java.util.Calendar.HOUR_OF_DAY, 0); 200 gCalendar.set(java.util.Calendar.MINUTE, 0); 201 gCalendar.set(java.util.Calendar.SECOND, 0); 202 gCalendar.set(java.util.Calendar.MILLISECOND, 0); 203 204 Date dateExcluded = gCalendar.getTime(); 205 excludedOccurrences.add(dateExcluded); 206 207 // Exclude the occurrence 208 event.setExcludedOccurrences(excludedOccurrences); 209 } 210 211 /** 212 * Compute the start date and end date of the event from the edited occurrence 213 * @param event The event 214 * @param jsParameters The JS parameters 215 * @return an array with computed start and end dates 216 */ 217 protected Date[] _computeEventDates (CalendarEvent event, Map<String, Object> jsParameters) 218 { 219 // Date of the edited occurrence before edition 220 String occurrenceDateAsString = (String) jsParameters.get("occurrenceDate"); 221 Date occurrenceDate = (Date) ParameterHelper.castValue(occurrenceDateAsString, ParameterType.DATE); 222 223 // Dates of the event before edition 224 long oldStartTime = event.getStartDate().getTime(); 225 long oldEndTime = event.getEndDate().getTime(); 226 long oldDiff = oldEndTime - oldStartTime; 227 228 long startTimeOccurrence = occurrenceDate.getTime(); 229 long endTimeOccurrence = startTimeOccurrence + oldDiff; 230 231 String startDateAsString = (String) jsParameters.get("startDate"); 232 Date startDate = (Date) ParameterHelper.castValue(startDateAsString, ParameterType.DATE); 233 String endDateAsString = (String) jsParameters.get("endDate"); 234 Date endDate = (Date) ParameterHelper.castValue(endDateAsString, ParameterType.DATE); 235 236 long startDiff = startDate.getTime() - startTimeOccurrence; 237 long endDiff = endDate.getTime() - endTimeOccurrence; 238 239 // Compute the new start and end date from the edited occurrence 240 return new Date[] {new Date(oldStartTime + startDiff), new Date(oldEndTime + endDiff)}; 241 } 242 243 244 /** 245 * Notify listeners that the event has been updated 246 * @param event The updated event 247 */ 248 @Override 249 protected void _notifyListeners (CalendarEvent event) 250 { 251 Map<String, Object> eventParams = new HashMap<>(); 252 eventParams.put(ObservationConstants.ARGS_CALENDAR, event.getParent()); 253 eventParams.put(ObservationConstants.ARGS_CALENDAR_EVENT, event); 254 eventParams.put(ObservationConstants.ARGS_ID, event.getId()); 255 eventParams.put(ObservationConstants.ARGS_PARENT_ID, event.getParent().getId()); 256 257 _observationManager.notify(new Event(ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED, _currentUserProvider.getUser(), eventParams)); 258 } 259}