View Javadoc
1   /**
2    * Copyright (C) 2003-2007 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   **/
17  package org.exoplatform.calendar.webui;
18  
19  import org.apache.commons.lang3.StringUtils;
20  
21  import org.exoplatform.calendar.service.CalendarEvent;
22  import org.exoplatform.calendar.service.CalendarService;
23  import org.exoplatform.calendar.service.CalendarSetting;
24  import org.exoplatform.calendar.service.Utils;
25  import org.exoplatform.calendar.util.CalendarUtils;
26  import org.exoplatform.calendar.webui.popup.UIPopupAction;
27  import org.exoplatform.calendar.webui.popup.UIPopupContainer;
28  import org.exoplatform.commons.api.settings.SettingService;
29  import org.exoplatform.commons.api.settings.SettingValue;
30  import org.exoplatform.commons.api.settings.data.Context;
31  import org.exoplatform.commons.api.settings.data.Scope;
32  import org.exoplatform.commons.utils.DateUtils;
33  import org.exoplatform.commons.utils.PropertyManager;
34  import org.exoplatform.container.PortalContainer;
35  import org.exoplatform.portal.application.PortalRequestContext;
36  import org.exoplatform.portal.application.RequestNavigationData;
37  import org.exoplatform.portal.mop.SiteType;
38  import org.exoplatform.portal.webui.util.Util;
39  import org.exoplatform.services.log.ExoLogger;
40  import org.exoplatform.services.log.Log;
41  import org.exoplatform.services.organization.User;
42  import org.exoplatform.social.common.router.ExoRouter;
43  import org.exoplatform.social.core.space.SpaceUtils;
44  import org.exoplatform.social.core.space.model.Space;
45  import org.exoplatform.social.core.space.spi.SpaceService;
46  import org.exoplatform.web.application.ApplicationMessage;
47  import org.exoplatform.web.application.RequestContext;
48  import org.exoplatform.webui.application.WebuiApplication;
49  import org.exoplatform.webui.application.WebuiRequestContext;
50  import org.exoplatform.webui.config.annotation.ComponentConfig;
51  import org.exoplatform.webui.core.UIComponent;
52  import org.exoplatform.webui.core.UIConfirmation;
53  import org.exoplatform.webui.core.UIPopupWindow;
54  import org.exoplatform.webui.core.UIPortletApplication;
55  import org.exoplatform.webui.core.lifecycle.UIApplicationLifecycle;
56  import org.exoplatform.ws.frameworks.cometd.ContinuationService;
57  
58  import org.json.JSONObject;
59  import org.mortbay.cometd.continuation.EXoContinuationBayeux;
60  
61  import java.text.SimpleDateFormat;
62  import java.util.ArrayList;
63  import java.util.Calendar;
64  import java.util.Date;
65  import java.util.List;
66  import java.util.Map;
67  import java.util.ResourceBundle;
68  import java.util.TimeZone;
69  
70  import javax.portlet.ResourceRequest;
71  import javax.servlet.http.HttpServletRequest;
72  
73  /**
74   * Author : Nguyen Quang Hung
75   *          hung.nguyen@exoplatform.com
76   * Aug 01, 2007
77   */
78  @ComponentConfig(
79                   lifecycle = UIApplicationLifecycle.class, 
80                   template = "app:/templates/calendar/webui/UICalendarPortlet.gtmpl"
81      )
82  public class UICalendarPortlet extends UIPortletApplication {
83  
84    public static final String CALENDAR_APP_SETTING_SCOPE = "Calendar";
85    public static final String CALENDAR_INVISIBLE_SETTING_KEY = "InvisibleCalendars";
86  
87    private static Log log = ExoLogger.getLogger(UICalendarPortlet.class);
88  
89    private String spaceGroupId;
90  
91    public UICalendarPortlet() throws Exception {
92      addChild(UIConfirmation.class, null, null);
93      UIActionBar uiActionBar = addChild(UIActionBar.class, null, null) ;
94      uiActionBar.setCurrentView(CalendarUtils.getViewInSetting()) ;
95      addChild(UICalendarWorkingContainer.class, null, null) ;
96      UIPopupAction uiPopup =  addChild(UIPopupAction.class, null, null) ;
97      uiPopup.setId("UICalendarPopupAction") ;
98      uiPopup.getChild(UIPopupWindow.class).setId("UICalendarPopupWindow") ;
99      
100     addChild(UICalendarPortletEditMode.class, null, null);
101   }
102 
103   @Override
104   public void serveResource(WebuiRequestContext context) throws Exception {
105     super.serveResource(context);
106 
107     ResourceRequest req = context.getRequest();
108     SettingService settingService = getApplicationComponent(SettingService.class);
109     SettingValue<?> value = settingService.get(Context.USER, Scope.APPLICATION.id(CALENDAR_APP_SETTING_SCOPE), CALENDAR_INVISIBLE_SETTING_KEY);
110 
111     String invisibleCalendarIds = req.getResourceID();
112     if (invisibleCalendarIds != null) {
113       settingService.set(Context.USER, Scope.APPLICATION.id(CALENDAR_APP_SETTING_SCOPE), CALENDAR_INVISIBLE_SETTING_KEY, SettingValue.create(invisibleCalendarIds));
114     } else {
115       settingService.remove(Context.USER, Scope.APPLICATION.id(CALENDAR_APP_SETTING_SCOPE), CALENDAR_INVISIBLE_SETTING_KEY);
116     }
117   }
118 
119   public CalendarSetting getCalendarSetting() throws Exception{
120     return CalendarUtils.getCurrentUserCalendarSetting(); 
121   }
122   public void setCalendarSetting(CalendarSetting setting) throws Exception{
123     CalendarUtils.setCurrentCalendarSetting(setting); 
124   }
125 
126   /**
127    * @return a calendar that contains configuration of the user, such as: Time zone, First day of week.
128    */
129   public Calendar getUserCalendar() {    
130     return CalendarUtils.getInstanceOfCurrentCalendar();
131   }
132 
133   public String getSettingTimeZone() throws Exception {
134     TimeZone tz = DateUtils.getTimeZone(getCalendarSetting().getTimeZone());
135     //get time zone offset in a specified date to take day light saving into account
136     long timezoneOffset = tz.getOffset(Calendar.getInstance().getTimeInMillis());
137     return String.valueOf(timezoneOffset/1000/60) ;
138   }
139 
140   public String getWeekStartOn() throws Exception {
141     return getCalendarSetting().getWeekStartOn();
142   }
143 
144   /**
145    * close all popups
146    *
147    * @throws Exception
148    */
149   public void cancelAction() throws Exception {
150     WebuiRequestContext context = RequestContext.getCurrentInstance() ;
151     UIPopupAction popupAction = getChild(UIPopupAction.class) ;
152     popupAction.deActivate() ;
153     context.addUIComponentToUpdateByAjax(popupAction) ;
154   }
155 
156   public String getRemoteUser() throws Exception {
157     return CalendarUtils.getCurrentUser() ;
158   }
159   public String getUserToken()throws Exception {
160     ContinuationService continuation = CalendarUtils.getContinuationService() ;
161     try {
162       return continuation.getUserToken(this.getRemoteUser());
163     } catch (Exception e) {
164       log.debug("\n\n can not get UserToken", e);
165       return "" ;
166     }
167   }
168 
169   protected String getCometdContextName() {
170     EXoContinuationBayeux bayeux = (EXoContinuationBayeux) PortalContainer.getInstance()
171         .getComponentInstanceOfType(EXoContinuationBayeux.class);
172     return (bayeux == null ? "cometd" : bayeux.getCometdContextName());
173   }
174 
175   public String getRestContextName() {
176     return PortalContainer.getInstance().getRestContextName();
177   }
178 
179   /**
180    * get space id if the request comes from one Social space, else return empty string.
181    * @return 
182    */
183   public static String getSpaceId() {
184     String spaceIdStr = "";
185     PortalRequestContext pContext = Util.getPortalRequestContext();
186     if (!pContext.getSiteType().equals(SiteType.GROUP) ||
187         !pContext.getSiteName().startsWith(SpaceUtils.SPACE_GROUP)) {
188       return null;
189     }
190 
191     String requestPath = pContext.getControllerContext().getParameter(RequestNavigationData.REQUEST_PATH);
192     ExoRouter.Route er = ExoRouter.route(requestPath);
193     if(er == null) return spaceIdStr;
194     String spacePrettyName = er.localArgs.get("spacePrettyName");
195     SpaceService sService = (SpaceService) PortalContainer.getInstance().getComponentInstanceOfType(SpaceService.class);
196     Space space = sService.getSpaceByPrettyName(spacePrettyName);
197     if (space == null) return spaceIdStr;
198     spaceIdStr = space.getId();
199     return spaceIdStr == null ? "" : spaceIdStr;
200   }
201 
202   public static String getGroupIdOfSpace() {
203     String spaceGroupId = "";
204     PortalRequestContext pContext = Util.getPortalRequestContext();
205     String requestPath = pContext.getControllerContext().getParameter(RequestNavigationData.REQUEST_PATH);
206     ExoRouter.Route er = ExoRouter.route(requestPath);
207     if (er == null) return spaceGroupId;
208     String spacePrettyName = er.localArgs.get("spacePrettyName");
209     SpaceService sService = (SpaceService) PortalContainer.getInstance().getComponentInstanceOfType(SpaceService.class);
210     Space space = sService.getSpaceByPrettyName(spacePrettyName);
211     if (space == null) return spaceGroupId;
212     spaceGroupId = space.getGroupId();
213     return spaceGroupId == null ? "" : spaceGroupId;
214   }
215 
216   public String getSpaceGroupId() {
217     if (spaceGroupId != null) return spaceGroupId;
218 
219     String spaceIdStr = "";
220     PortalRequestContext pContext = Util.getPortalRequestContext();
221     String requestPath = pContext.getControllerContext().getParameter(RequestNavigationData.REQUEST_PATH);
222     ExoRouter.Route er = ExoRouter.route(requestPath);
223     spaceGroupId = spaceIdStr;
224     if (er == null) return spaceIdStr;
225     String spacePrettyName = er.localArgs.get("spacePrettyName");
226     SpaceService sService = (SpaceService) PortalContainer.getInstance().getComponentInstanceOfType(SpaceService.class);
227     Space space = sService.getSpaceByPrettyName(spacePrettyName);
228     spaceGroupId = spaceIdStr;
229     if (space == null) return spaceIdStr;
230     spaceIdStr = space.getGroupId();
231     spaceGroupId = (spaceIdStr == null ? "" : spaceIdStr);
232     return spaceGroupId;
233   }
234 
235 
236   public static boolean isInSpace() {
237     return StringUtils.isNotEmpty(getSpaceId());
238   }
239 
240   public boolean isInSpaceContext() {
241     return StringUtils.isNotEmpty(getSpaceGroupId());
242   }
243 
244   public void processInvitationURL(WebuiRequestContext context, PortalRequestContext pContext, String url) throws Exception
245   {
246     String isAjax = pContext.getRequestParameter("ajaxRequest");
247     if(isAjax != null && Boolean.parseBoolean(isAjax)) return;
248     String username = CalendarUtils.getCurrentUser();
249     User user = CalendarUtils.getOrganizationService().getUserHandler().findUserByName(username);
250     String formTime = CalendarUtils.getCurrentTime(this) ;
251     CalendarService calService = CalendarUtils.getCalendarService();
252     if (url.contains(CalendarUtils.INVITATION_IMPORT_URL)) {
253       // import to personal calendar
254       url = url.substring(url.indexOf(CalendarUtils.INVITATION_IMPORT_URL) + CalendarUtils.INVITATION_IMPORT_URL.length());
255       String[] params = url.split("/");
256       String inviter = params[0];
257       String eventId = params[1];
258       int calType = Integer.parseInt(params[2]);
259       CalendarEvent event = calService.getEventById(eventId);
260       if (event != null) {
261         // update status
262         event.setCalType(String.valueOf(calType));
263         calService.confirmInvitation(inviter, user.getEmail(), username, calType, event.getCalendarId(), eventId, Utils.ACCEPT);
264 
265         JSONObject evtObj = new JSONObject();
266         evtObj.put("id", event.getId());
267         evtObj.put("isOccur", Utils.isOccurrence(event));
268         evtObj.put("startTime", event.getFromDateTime().getTime());
269         evtObj.put("endTime", event.getToDateTime().getTime());
270         //
271         context.getJavascriptManager().require("SHARED/calendarEvent","calendarEvent")
272                 .addScripts("calendarEvent.openEventForm(" + evtObj.toString() + ")");
273       } else {
274         context.getUIApplication().addMessage(new ApplicationMessage("UICalendarPortlet.msg.event-was-not-found", null, ApplicationMessage.ERROR));
275       }
276       return;
277     }
278 
279     if (url.contains(CalendarUtils.INVITATION_DETAIL_URL)) {
280       // open event on source calendar to view
281       url = url.substring(url.indexOf(CalendarUtils.INVITATION_DETAIL_URL) + CalendarUtils.INVITATION_DETAIL_URL.length());
282       String[] params = url.split("/");
283       String eventId = params[1];
284       CalendarEvent event = calService.getEventById(eventId);
285       Date startDate = event.getFromDateTime();
286       Date endDate = event.getToDateTime();
287       UICalendarWorkingContainer uiCalendarWorkingContainer = this.getChild(UICalendarWorkingContainer.class);
288       UICalendarViewContainer uiCalendarViewContainer = uiCalendarWorkingContainer.getChild(UICalendarViewContainer.class);
289       uiCalendarViewContainer.setStartDate(startDate);
290       UIActionBar uiActionBar = this.getChild(UIActionBar.class);
291       if (isOneDay(startDate.toString().split(" "), endDate.toString().split(" "))) {
292         uiCalendarViewContainer.initView(UICalendarViewContainer.DAY_VIEW, true);
293         uiActionBar.setCurrentView(UICalendarViewContainer.TYPES[0]);
294       } else {
295         uiCalendarViewContainer.initView(UICalendarViewContainer.WEEK_VIEW, true);
296         uiActionBar.setCurrentView(UICalendarViewContainer.TYPES[1]);
297       }
298       openEventPreviewPopup(event, context);
299       context.addUIComponentToUpdateByAjax(uiActionBar);
300       context.addUIComponentToUpdateByAjax(uiCalendarViewContainer);
301     }
302   }
303 
304   private boolean isOneDay(String[] begin, String[] end) {
305     if (begin[1].equals(end[1])) { //month
306       if (begin[2].equals(end[2])) { //day
307         if (begin[5].equals(end[5])) { //year
308           return true;
309         }
310       }
311     }
312     return false;
313   }
314 
315 
316   /**
317    * process event details url to show a popup to display event details
318    * url like <calendar_app>/details/<event-id>
319    *
320    * @param webuiRequestContext
321    * @param eventId
322    * @throws Exception
323    */
324   private void processEventDetailsURL(WebuiRequestContext webuiRequestContext, String eventId, String recurId) throws Exception
325   {
326     CalendarService calService = CalendarUtils.getCalendarService();
327     CalendarEvent event = null ;
328     String username = CalendarUtils.getCurrentUser();
329     if(recurId != null && !recurId.isEmpty()) {
330       CalendarSetting calSetting = calService.getCalendarSetting(username);
331       String timezoneId = calSetting.getTimeZone();
332       TimeZone timezone = DateUtils.getTimeZone(timezoneId);
333       CalendarEvent orgEvent = calService.getEventById(eventId); // the repetitive event of which we need to find the occurrence
334       if(orgEvent != null) {
335         SimpleDateFormat sdf = new SimpleDateFormat(Utils.DATE_FORMAT_RECUR_ID);
336         sdf.setTimeZone(timezone);
337         Date occurDate = sdf.parse(recurId); // get the date that the occurrence appear in the time table
338         java.util.Calendar cal = java.util.Calendar.getInstance(timezone);
339         cal.setTime(occurDate);
340         java.util.Calendar from = Utils.getBeginDay(cal);
341         java.util.Calendar to = Utils.getEndDay(cal);
342         /* Here we get occurrences of the repetitive event in the occurDate 
343          * so that the result must be <recurId, occurrence> (occurrence: the occurrence event that we are searching for)
344          */
345         Map<String, CalendarEvent> occMap = calService.getOccurrenceEvents(orgEvent, from, to, timezoneId);
346         event = occMap.get(recurId);
347       }
348     } else {
349       /* find event from username and event id */
350       event = calService.getEventById(eventId) ;
351     }
352     if (event == null){
353       webuiRequestContext.getUIApplication().addMessage(new ApplicationMessage("UICalendarPortlet.msg.have-no-permission-to-view-event", null, ApplicationMessage.WARNING ));
354     } else {
355       event.setCalType(String.valueOf(calService.getTypeOfCalendar(username, event.getCalendarId())));
356       openEventPreviewPopup(event, webuiRequestContext);
357     }
358   }
359 
360   /**
361    * open an popup to display event or task details
362    *
363    * @param event
364    * @param webuiRequestContext
365    * @throws Exception
366    */
367   private void openEventPreviewPopup(CalendarEvent event, WebuiRequestContext webuiRequestContext) throws Exception
368   {
369     UIPopupAction uiPopupAction = getChild(UIPopupAction.class);
370     uiPopupAction.deActivate();
371     UIPopupContainer uiPopupContainer = uiPopupAction.activate(UIPopupContainer.class, 700);
372     uiPopupContainer.setId("UIEventPreview");
373     uiPopupAction.getChild(UIPopupWindow.class).setShowCloseButton(false);
374     UIPreview uiPreview = uiPopupContainer.addChild(UIPreview.class, null, null);
375     uiPreview.setEvent(event);
376     uiPreview.setId("UIPreviewPopup");
377     uiPreview.setShowPopup(true);
378     uiPreview.setPreviewByUrl(true);
379     webuiRequestContext.addUIComponentToUpdateByAjax(uiPopupAction);
380   }
381 
382 
383   /**
384    * process url that links to calendar application
385    * this might be an url comes from email or gadget...
386    *
387    * @param webuiRequestContext
388    * @throws Exception
389    */
390   private void processExternalUrl(WebuiRequestContext webuiRequestContext) throws Exception
391   {
392     PortalRequestContext pContext = Util.getPortalRequestContext();
393     String requestedURL = ((HttpServletRequest) pContext.getRequest()).getRequestURL().toString();
394     if (requestedURL.contains(CalendarUtils.INVITATION_URL))
395     {
396       try {
397         processInvitationURL(webuiRequestContext, pContext, requestedURL);
398       }
399       catch (Exception e) {
400         if (log.isDebugEnabled()) {
401           log.debug("Invitation url is not valid", e);
402         }
403       }
404     }
405     else if (requestedURL.contains(CalendarUtils.DETAILS_URL))
406     {
407       String eventId = requestedURL.substring(requestedURL.indexOf(CalendarUtils.DETAILS_URL) + CalendarUtils.DETAILS_URL.length());
408       if (!eventId.startsWith("Event")) return;
409       else if(eventId.endsWith("/")) eventId = eventId.substring(0, eventId.lastIndexOf("/"));
410       String occurenceId = "";
411       String[] array = eventId.split("/");
412       if(array.length >=2) {
413         eventId = array[0];
414         occurenceId = array[1];
415       }
416       processEventDetailsURL(webuiRequestContext, eventId, occurenceId);
417     }
418   }
419 
420   public void processRender(WebuiApplication app, WebuiRequestContext context) throws Exception {
421     processExternalUrl(context);
422     super.processRender(app, context);
423   }
424 
425   public void showConfirmWindow(UIComponent comp, String message) {
426     UIConfirmation uiConfirmation = getChild(UIConfirmation.class);
427     uiConfirmation.setCaller(comp);
428     uiConfirmation.setMessage(message);
429     createActionConfirms(uiConfirmation);
430     ((WebuiRequestContext) WebuiRequestContext.getCurrentInstance()).addUIComponentToUpdateByAjax(uiConfirmation);
431   }
432   public void createActionConfirms(UIConfirmation uiConfirmation) {
433     ResourceBundle resourceBundle = WebuiRequestContext.getCurrentInstance().getApplicationResourceBundle();
434     String yes;
435     try {
436       yes = resourceBundle.getString("UICalendarPortlet.confirm.yes");
437     } catch (Exception ex) {
438       log.warn("Can not find resource bundle for key: UICalendarPortlet.confirm.yes");
439       yes = "UICalendarPortlet.confirm.yes";
440     }
441 
442     String no;
443     try {
444       no = resourceBundle.getString("UICalendarPortlet.confirm.no");
445     } catch (Exception ex) {
446       log.warn("Can not find resource bundle for key: UICalendarPortlet.confirm.no");
447       no = "UICalendarPortlet.confirm.no";
448     }
449 
450     List<UIConfirmation.ActionConfirm> actionConfirms = new ArrayList<UIConfirmation.ActionConfirm>();
451     actionConfirms.add(new UIConfirmation.ActionConfirm("ConfirmClose", yes));
452     actionConfirms.add(new UIConfirmation.ActionConfirm("AbortClose", no));
453     uiConfirmation.setActions(actionConfirms);
454   }
455 
456   /**
457    * use in template
458    */
459   public int getTimeShift(){
460     int defaultTime = 2;
461     try {
462       defaultTime = Integer.parseInt(PropertyManager.getProperty("exo.calendar.default.event.suggest"));
463     } catch (NumberFormatException e) {
464       defaultTime = 1;
465       log.error("exo.calendar.default.event.suggest must be int, this setting will be reset to {}", defaultTime);
466     }
467     return defaultTime;
468   }
469 
470 }