001/* 002 * Copyright 2015 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.workspaces.calendars; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import javax.jcr.Node; 024import javax.jcr.RepositoryException; 025 026import org.apache.avalon.framework.component.Component; 027import org.apache.avalon.framework.context.Context; 028import org.apache.avalon.framework.context.ContextException; 029import org.apache.avalon.framework.context.Contextualizable; 030import org.apache.avalon.framework.logger.AbstractLogEnabled; 031import org.apache.avalon.framework.service.ServiceException; 032import org.apache.avalon.framework.service.ServiceManager; 033import org.apache.avalon.framework.service.Serviceable; 034import org.apache.cocoon.components.ContextHelper; 035import org.apache.cocoon.environment.Request; 036import org.apache.commons.lang3.StringUtils; 037 038import org.ametys.core.user.User; 039import org.ametys.core.user.UserIdentity; 040import org.ametys.core.user.UserManager; 041import org.ametys.core.util.I18nUtils; 042import org.ametys.plugins.messagingconnector.MessagingConnector; 043import org.ametys.plugins.repository.AmetysObjectResolver; 044import org.ametys.plugins.repository.RepositoryConstants; 045import org.ametys.plugins.workspaces.calendars.events.CalendarEventAttendee; 046import org.ametys.plugins.workspaces.calendars.jcr.JCRCalendarEvent; 047import org.ametys.plugins.workspaces.project.objects.Project; 048import org.ametys.runtime.i18n.I18nizableText; 049 050/** 051 * Manager for manipulating messaging connector linked to calendars event of a project 052 * 053 */ 054public class MessagingConnectorCalendarManager extends AbstractLogEnabled implements Serviceable, Component, Contextualizable 055{ 056 /** Avalon Role */ 057 public static final String ROLE = MessagingConnectorCalendarManager.class.getName(); 058 059 /** Property's name for synchronized id id */ 060 public static final String PROPERTY_SYNCHRONIZED_ID = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":synchronizedId"; 061 062 private MessagingConnector _messagingConnector; 063 private UserManager _userManager; 064 private AmetysObjectResolver _resolver; 065 private I18nUtils _i18nUtils; 066 private Context _context; 067 068 @Override 069 public void contextualize(Context context) throws ContextException 070 { 071 _context = context; 072 } 073 074 @Override 075 public void service(ServiceManager manager) throws ServiceException 076 { 077 boolean hasService = manager.hasService(MessagingConnector.ROLE); 078 _messagingConnector = hasService ? (MessagingConnector) manager.lookup(MessagingConnector.ROLE) : null; 079 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 080 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 081 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 082 } 083 084 /** 085 * Set the synchronized id (for messaging connector) to the event 086 * @param event the event 087 * @param synchronizedId the synchronized id 088 */ 089 public void setSynchronizedId(JCRCalendarEvent event, String synchronizedId) 090 { 091 try 092 { 093 event.getNode().setProperty(PROPERTY_SYNCHRONIZED_ID, synchronizedId); 094 event.saveChanges(); 095 } 096 catch (RepositoryException e) 097 { 098 getLogger().error("An error occurred setting synchronized id for event " + event.getId()); 099 } 100 } 101 102 /** 103 * Get the synchronized id (for messaging connector) of the event 104 * @param event the event 105 * @return the synchronized id 106 */ 107 public String getSynchronizedId(JCRCalendarEvent event) 108 { 109 try 110 { 111 Node eventNode = event.getNode(); 112 if (eventNode.hasProperty(PROPERTY_SYNCHRONIZED_ID)) 113 { 114 return eventNode.getProperty(PROPERTY_SYNCHRONIZED_ID).getString(); 115 } 116 } 117 catch (RepositoryException e) 118 { 119 getLogger().error("An error occurred getting synchronized id for event " + event.getId()); 120 } 121 122 return null; 123 } 124 125 /** 126 * Set attendees to the event 127 * @param eventId the event id 128 * @param attendees the list of attendees 129 */ 130 public void setAttendees(String eventId, List<CalendarEventAttendee> attendees) 131 { 132 if (attendees != null) 133 { 134 JCRCalendarEvent event = (JCRCalendarEvent) _resolver.resolveById(eventId); 135 try 136 { 137 event.setAttendees(attendees); 138 } 139 catch (RepositoryException e) 140 { 141 getLogger().error("An error occurred setting attendees for event " + eventId, e); 142 } 143 } 144 } 145 146 /** 147 * Set organiser to the event 148 * @param eventId the event id 149 * @param organiser the organiser 150 */ 151 public void setOrganiser(String eventId, UserIdentity organiser) 152 { 153 JCRCalendarEvent event = (JCRCalendarEvent) _resolver.resolveById(eventId); 154 if (organiser != null) 155 { 156 event.setOrganiser(organiser); 157 } 158 } 159 160 /** 161 * Add event invitation parameters (attendees and organiser) 162 * @param parameters the map of parameters 163 * @param eventId the event id 164 */ 165 public void addEventInvitation(Map<String, Object> parameters, String eventId) 166 { 167 @SuppressWarnings("unchecked") 168 List<Map<String, Object>> attendeesList = (List<Map<String, Object>>) parameters.get("attendees"); 169 List<CalendarEventAttendee> attendees = _getAttendeeListFromParameter(attendeesList); 170 setAttendees(eventId, attendees); 171 172 @SuppressWarnings("unchecked") 173 Map<String, Object> organiserMap = (Map<String, Object>) parameters.get("organiser"); 174 UserIdentity organiser = _getUserFromParameter(organiserMap); 175 setOrganiser(eventId, organiser); 176 177 if (organiser != null) 178 { 179 JCRCalendarEvent event = _resolver.resolveById(eventId); 180 _createEvent(event, organiser, attendees); 181 } 182 } 183 184 /** 185 * Edit event invitation parameters (attendees and organiser) 186 * @param parameters the map of parameters 187 * @param eventId the event id 188 */ 189 public void editEventInvitation(Map<String, Object> parameters, String eventId) 190 { 191 JCRCalendarEvent event = _resolver.resolveById(eventId); 192 193 @SuppressWarnings("unchecked") 194 List<Map<String, Object>> attendeesList = (List<Map<String, Object>>) parameters.get("attendees"); 195 List<CalendarEventAttendee> attendees = _getAttendeeListFromParameter(attendeesList); 196 try 197 { 198 if (attendees == null) 199 { 200 attendees = event.getAttendees(); 201 } 202 } 203 catch (RepositoryException e) 204 { 205 getLogger().error("An error occurred getting attendees from repository for event " + event.getId()); 206 } 207 setAttendees(eventId, attendees); 208 209 @SuppressWarnings("unchecked") 210 Map<String, Object> organiserMap = (Map<String, Object>) parameters.get("organiser"); 211 UserIdentity organiserFromMap = _getUserFromParameter(organiserMap); 212 UserIdentity organiser = organiserFromMap != null ? organiserFromMap : event.getOrganiser(); 213 setOrganiser(eventId, organiser); 214 215 if (_messagingConnector != null) 216 { 217 String synchronizedId = getSynchronizedId(event); 218 if (StringUtils.isNotBlank(synchronizedId) && _messagingConnector.isEventExist(synchronizedId, organiser)) 219 { 220 _editEvent(event, organiser, attendees); 221 } 222 else if (organiser != null) 223 { 224 _createEvent(event, organiser, attendees); 225 } 226 } 227 } 228 229 /** 230 * Create event in the messaging connector 231 * @param event the event 232 * @param organiser the organiser 233 * @param attendees the list of attendee 234 */ 235 protected void _createEvent(JCRCalendarEvent event, UserIdentity organiser, List<CalendarEventAttendee> attendees) 236 { 237 Map<String, Boolean> attendeesForMessagingConnector = new HashMap<>(); 238 for (CalendarEventAttendee attendee : attendees) 239 { 240 if (attendee.isExternal()) 241 { 242 attendeesForMessagingConnector.put(attendee.getEmail(), attendee.isMandatory()); 243 } 244 else 245 { 246 User user = _userManager.getUser(new UserIdentity(attendee.getLogin(), attendee.getPopulationId())); 247 attendeesForMessagingConnector.put(user.getEmail(), attendee.isMandatory()); 248 } 249 } 250 251 String synchronizedId = _messagingConnector.createEvent(_getEventTitle(event), event.getDescription(), event.getLocation(), event.getFullDay(), event.getStartDate(), event.getEndDate(), event.getRecurrenceType(), event.getRepeatUntil(), attendeesForMessagingConnector, event.getOrganiser()); 252 setSynchronizedId(event, synchronizedId); 253 } 254 255 /** 256 * Delete event in the messaging connector 257 * @param event the event 258 */ 259 public void deleteEvent(JCRCalendarEvent event) 260 { 261 if (isEventSynchronized(event.getId())) 262 { 263 String synchronizedId = getSynchronizedId(event); 264 _messagingConnector.deleteEvent(synchronizedId, event.getOrganiser()); 265 } 266 } 267 268 /** 269 * True if the event is synchronized in the messaging connector 270 * @param eventId the event id 271 * @return true if the event exist 272 */ 273 public boolean isEventSynchronized(String eventId) 274 { 275 if (_messagingConnector == null) 276 { 277 return false; 278 } 279 JCRCalendarEvent event = _resolver.resolveById(eventId); 280 String synchronizedId = getSynchronizedId(event); 281 282 if (StringUtils.isBlank(synchronizedId)) 283 { 284 return false; 285 } 286 287 try 288 { 289 return _messagingConnector.isEventExist(synchronizedId, event.getOrganiser()); 290 } 291 catch (UnsupportedOperationException e) 292 { 293 getLogger().error("An error occurred while checking if event " + eventId + " exists", e); 294 return false; 295 } 296 } 297 298 /** 299 * Edit event in the messaging connector 300 * @param event the event 301 * @param organiser the organiser 302 * @param attendees the list of attendee 303 */ 304 protected void _editEvent(JCRCalendarEvent event, UserIdentity organiser, List<CalendarEventAttendee> attendees) 305 { 306 String synchronizedId = getSynchronizedId(event); 307 Map<String, Boolean> attendeesForMessagingConnector = null; 308 if (attendees != null) 309 { 310 attendeesForMessagingConnector = new HashMap<>(); 311 for (CalendarEventAttendee attendee : attendees) 312 { 313 if (attendee.isExternal()) 314 { 315 attendeesForMessagingConnector.put(attendee.getEmail(), attendee.isMandatory()); 316 } 317 else 318 { 319 User user = _userManager.getUser(new UserIdentity(attendee.getLogin(), attendee.getPopulationId())); 320 attendeesForMessagingConnector.put(user.getEmail(), attendee.isMandatory()); 321 } 322 } 323 } 324 325 _messagingConnector.updateEvent(synchronizedId, _getEventTitle(event), event.getDescription(), event.getLocation(), event.getFullDay(), event.getStartDate(), event.getEndDate(), event.getRecurrenceType(), event.getRepeatUntil(), attendeesForMessagingConnector, event.getOrganiser()); 326 } 327 328 /** 329 * Get the computed title of the event 330 * @param event the event 331 * @return the computed title of the event 332 */ 333 protected String _getEventTitle(JCRCalendarEvent event) 334 { 335 Calendar calendar = event.getParent(); 336 Project project = calendar.getProject(); 337 338 List<String> parameters = new ArrayList<>(); 339 parameters.add(project.getTitle()); 340 parameters.add(event.getTitle()); 341 I18nizableText titleI18n = new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_PROJECT_SERVICE_MODULE_CALENDAR_ADD_EVENT_MESSAGING_CONNECTOR_TITLE", parameters); 342 343 Request request = ContextHelper.getRequest(_context); 344 String lang = (String) request.getAttribute("sitemapLanguage"); 345 346 return _i18nUtils.translate(titleI18n, lang); 347 } 348 349 350 /** 351 * Get user from the user parameter 352 * @param userMap the user map from parameters 353 * @return the user 354 */ 355 protected UserIdentity _getUserFromParameter(Map<String, Object> userMap) 356 { 357 if (userMap != null) 358 { 359 String login = (String) userMap.get("login"); 360 String populationId = (String) userMap.get("populationId"); 361 362 return new UserIdentity(login, populationId); 363 } 364 365 return null; 366 } 367 368 /** 369 * Get attendees list from the attendees parameter 370 * @param attendeesList the attendees list from parameters 371 * @return the attendees list 372 */ 373 protected List<CalendarEventAttendee> _getAttendeeListFromParameter(List<Map<String, Object>> attendeesList) 374 { 375 if (attendeesList != null) 376 { 377 List<CalendarEventAttendee> attendees = new ArrayList<>(); 378 for (Map<String, Object> attendee : attendeesList) 379 { 380 CalendarEventAttendee calendarEventAttendee = new CalendarEventAttendee(); 381 boolean isExternal = (boolean) attendee.get("external"); 382 if (isExternal) 383 { 384 calendarEventAttendee.setEmail((String) attendee.get("email")); 385 } 386 else 387 { 388 calendarEventAttendee.setPopulationId((String) attendee.get("populationId")); 389 calendarEventAttendee.setLogin((String) attendee.get("login")); 390 } 391 392 calendarEventAttendee.setIsExternal(isExternal); 393 calendarEventAttendee.setIsMandatory((boolean) attendee.get("mandatory")); 394 395 attendees.add(calendarEventAttendee); 396 } 397 return attendees; 398 } 399 400 return null; 401 } 402 403}