001 /**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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 package org.kuali.rice.ken.web.spring;
017
018 import java.io.IOException;
019 import java.util.HashMap;
020 import java.util.List;
021 import java.util.Map;
022
023 import javax.servlet.ServletException;
024 import javax.servlet.http.HttpServletRequest;
025 import javax.servlet.http.HttpServletResponse;
026
027 import org.apache.log4j.Logger;
028 import org.kuali.rice.ken.bo.NotificationBo;
029 import org.kuali.rice.ken.bo.NotificationMessageDelivery;
030 import org.kuali.rice.ken.bo.NotificationRecipientBo;
031 import org.kuali.rice.ken.bo.NotificationSenderBo;
032 import org.kuali.rice.ken.service.NotificationMessageDeliveryService;
033 import org.kuali.rice.ken.service.NotificationService;
034 import org.kuali.rice.ken.service.NotificationWorkflowDocumentService;
035 import org.kuali.rice.ken.util.NotificationConstants;
036 import org.kuali.rice.ken.util.Util;
037 import org.kuali.rice.kew.api.KewApiConstants;
038 import org.kuali.rice.kim.api.identity.principal.Principal;
039 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
040 import org.springframework.web.servlet.ModelAndView;
041 import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
042
043
044 /**
045 * This class is the controller for the basic notification related actions - viewing, etc.
046 * @author Kuali Rice Team (rice.collab@kuali.org)
047 */
048 public class NotificationController extends MultiActionController {
049 /** Logger for this class and subclasses */
050 private static final Logger LOG = Logger.getLogger(NotificationController.class);
051
052 protected NotificationService notificationService;
053 protected NotificationWorkflowDocumentService notificationWorkflowDocService;
054 protected NotificationMessageDeliveryService messageDeliveryService;
055
056 /**
057 * Set the NotificationService
058 * @param notificationService
059 */
060 public void setNotificationService(NotificationService notificationService) {
061 this.notificationService = notificationService;
062 }
063
064 /**
065 * This method sets the NotificationWorkflowDocumentService
066 * @param s
067 */
068 public void setNotificationWorkflowDocumentService(NotificationWorkflowDocumentService s) {
069 this.notificationWorkflowDocService = s;
070 }
071
072 /**
073 * Sets the messageDeliveryService attribute value.
074 * @param messageDeliveryService The messageDeliveryService to set.
075 */
076 public void setMessageDeliveryService(NotificationMessageDeliveryService messageDeliveryService) {
077 this.messageDeliveryService = messageDeliveryService;
078 }
079
080 /**
081 * Handles the display of the main home page in the system.
082 * @param request : a servlet request
083 * @param response : a servlet response
084 * @throws ServletException : an exception
085 * @throws IOException : an exception
086 * @return a ModelAndView object
087 */
088 public ModelAndView displayHome(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
089 String view = "HomePage";
090 LOG.debug("remoteUser: "+request.getRemoteUser());
091 Map<String, Object> model = new HashMap<String, Object>();
092 return new ModelAndView(view, model);
093 }
094
095 /**
096 * This method handles displaying the notifications that an individual sent.
097 * @param request
098 * @param response
099 * @return ModelAndView
100 * @throws ServletException
101 * @throws IOException
102 */
103 public ModelAndView displayNotificationsSent(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
104 String view = "NotificationsSent";
105 LOG.debug("remoteUser: "+request.getRemoteUser());
106 Map<String, Object> model = new HashMap<String, Object>();
107 model.put("userId", request.getRemoteUser());
108 return new ModelAndView(view, model);
109 }
110
111 /**
112 * This method handles displaying the search screen.
113 * @param request
114 * @param response
115 * @return ModelAndView
116 * @throws ServletException
117 * @throws IOException
118 */
119 public ModelAndView displaySearch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
120 String view = "Search";
121 LOG.debug("remoteUser: "+request.getRemoteUser());
122 Map<String, Object> model = new HashMap<String, Object>();
123 return new ModelAndView(view, model);
124 }
125
126 /**
127 * This method displays the user lookup screen.
128 * @param request
129 * @param response
130 * @return
131 * @throws ServletException
132 * @throws IOException
133 */
134 public ModelAndView displayLookupUsers(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
135 String view = "LookupUsers";
136 LOG.debug("remoteUser: "+request.getRemoteUser());
137 Map<String, Object> model = new HashMap<String, Object>();
138 return new ModelAndView(view, model);
139 }
140
141 /**
142 * This method displays the workgroup lookup screen.
143 * @param request
144 * @param response
145 * @return
146 * @throws ServletException
147 * @throws IOException
148 */
149 public ModelAndView displayLookupWorkgroups(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
150 String view = "LookupWorkgroups";
151 LOG.debug("remoteUser: "+request.getRemoteUser());
152 Map<String, Object> model = new HashMap<String, Object>();
153 return new ModelAndView(view, model);
154 }
155
156
157 /**
158 * This method retrieves the NotificationMessageDelivery given an HttpServletRequest which
159 * may contain EITHER a message delivery id or a workflow doc id. Therefore, this is a
160 * "special case" for handling the workflow deliverer.
161 * @param request the incoming {@link HttpServletRequest}
162 * @return the {@link NotificationMessageDelivery} or null if not found
163 */
164 protected NotificationMessageDelivery determineMessageFromRequest(HttpServletRequest request) {
165 /**
166 * We can get the NotificationMessageDelivery object given a workflow ID or a NotificationMessageDelivery
167 * Id. This method might be called either from a workflow action list or
168 * as a link from a message deliverer endpoint such as an email message.
169 */
170 String messageDeliveryId = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.MSG_DELIVERY_ID);
171 String delivererId = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.DELIVERER_ID);
172 if (delivererId == null) {
173 delivererId = request.getParameter(KewApiConstants.DOCUMENT_ID_PARAMETER);
174 }
175
176 NotificationMessageDelivery messageDelivery;
177 if (messageDeliveryId != null) { // this means that the request came in not from the action list, but rather from a delivery end point
178 LOG.debug("Looking up notification with messageDeliveryId: "+messageDeliveryId);
179 try {
180 messageDelivery = messageDeliveryService.getNotificationMessageDelivery(new Long(messageDeliveryId));
181 } catch (Exception e) {
182 throw new RuntimeException("Error getting message with id: " + messageDeliveryId, e);
183 }
184 } else if (delivererId != null) { // this means that the request was triggered via the action list
185 LOG.debug("Looking up notification with workflowId: "+delivererId);
186 try {
187 messageDelivery = messageDeliveryService.getNotificationMessageDeliveryByDelivererId(delivererId);
188 } catch (Exception e) {
189 LOG.error("Error getting message with from deliverer id: " + delivererId, e);
190 throw new RuntimeException("Error getting message with deliverer id: " + delivererId, e);
191 }
192 } else {
193 throw new RuntimeException("Neither message ('" + NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.MSG_DELIVERY_ID
194 + "') nor deliverer id ('" + NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.DELIVERER_ID + "') were specified in the request");
195 }
196
197 return messageDelivery;
198 }
199
200 /**
201 * @param req the {@link HttpServletRequest}
202 * @return whether the incoming request was from the action list
203 */
204 protected boolean requestIsFromKEW(HttpServletRequest req) {
205 return req.getParameter(KewApiConstants.DOCUMENT_ID_PARAMETER) != null;
206 }
207
208 /**
209 * This controller handles displaying the appropriate notification details for a specific record.
210 * @param request : a servlet request
211 * @param response : a servlet response
212 * @throws ServletException : an exception
213 * @throws IOException : an exception
214 * @return a ModelAndView object
215 */
216 public ModelAndView displayNotificationDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
217 String view = "NotificationDetail"; // default to full view
218
219 String principalNm = request.getRemoteUser();
220 String command = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.COMMAND);
221 String standaloneWindow = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.STANDALONE_WINDOW);
222
223 NotificationMessageDelivery messageDelivery = determineMessageFromRequest(request);
224 // now get the notification from the message delivery object
225 NotificationBo notification = messageDelivery.getNotification();
226 boolean actionable = false;
227
228 if (requestIsFromKEW(request)) {
229 // check to see if this was a standalone window by examining the command from KEW before setting it to INLINE to force an inline view
230 if(command != null &&
231 (command.equals(NotificationConstants.NOTIFICATION_DETAIL_VIEWS.NORMAL_VIEW) ||
232 command.equals(NotificationConstants.NOTIFICATION_DETAIL_VIEWS.DOC_SEARCH_VIEW))) {
233 standaloneWindow = "true";
234 }
235
236 // we want all messages from the action list in line
237 command = NotificationConstants.NOTIFICATION_DETAIL_VIEWS.INLINE;
238 }
239
240 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalNm);
241 if (principal != null) {
242 actionable = (principal.getPrincipalId()).equals(messageDelivery.getUserRecipientId()) && NotificationConstants.MESSAGE_DELIVERY_STATUS.DELIVERED.equals(messageDelivery.getMessageDeliveryStatus());
243 } else {
244 throw new RuntimeException("There is no principal for principalNm " + principalNm);
245 }
246
247 List<NotificationSenderBo> senders = notification.getSenders();
248 List<NotificationRecipientBo> recipients = notification.getRecipients();
249
250 String contenthtml = Util.transformContent(notification);
251
252 // check to see if the details need to be rendered in line (no stuff around them)
253 if (command != null && command.equals(NotificationConstants.NOTIFICATION_DETAIL_VIEWS.INLINE)) {
254 view = "NotificationDetailInline";
255 }
256
257 Map<String, Object> model = new HashMap<String, Object>();
258 model.put("notification", notification);
259 model.put("senders", senders);
260 model.put("recipients", recipients);
261 model.put("contenthtml", contenthtml);
262 model.put("messageDeliveryId", messageDelivery.getId());
263 model.put("command", command);
264 model.put("actionable", actionable);
265 model.put(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.STANDALONE_WINDOW, standaloneWindow);
266 return new ModelAndView(view, model);
267 }
268
269 /**
270 * This method handles user dismissal of a message
271 * @param request : a servlet request
272 * @param response : a servlet response
273 * @return a ModelAndView object
274 */
275 public ModelAndView dismissMessage(HttpServletRequest request, HttpServletResponse response) {
276 String command = request.getParameter("action");
277 if (command == null) throw new RuntimeException("Dismissal command not specified");
278
279 if (NotificationConstants.ACK_CAUSE.equals(command)) {
280 return dismissMessage(command, "Notificaton acknowledged. Please refresh your action list.", request, response);
281 } else if (NotificationConstants.FYI_CAUSE.equals(command)) {
282 return dismissMessage(command, "Action Taken. Please refresh your action list.", request, response);
283 } else {
284 throw new RuntimeException("Unknown dismissal command: " + command);
285 }
286 }
287
288 /**
289 * This method takes an action on the message delivery - dismisses it with the action/cause that comes from the
290 * UI layer
291 * @param action the action or cause of the dismissal
292 * @param message the message to display to the user
293 * @param request the HttpServletRequest
294 * @param response the HttpServletResponse
295 * @return an appropriate ModelAndView
296 */
297 private ModelAndView dismissMessage(String action, String message, HttpServletRequest request, HttpServletResponse response) {
298 String view = "NotificationDetail";
299
300 String principalNm = request.getRemoteUser();
301 String messageDeliveryId = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.MSG_DELIVERY_ID);
302 String command = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.COMMAND);
303 String standaloneWindow = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.STANDALONE_WINDOW);
304
305 if (messageDeliveryId == null) {
306 throw new RuntimeException("A null messageDeliveryId was provided.");
307 }
308
309 LOG.debug("messageDeliveryId: "+messageDeliveryId);
310 LOG.debug("command: "+command);
311
312 /**
313 * We can get the notification object given a workflow ID or a notification
314 * Id. This method might be called either from a workflow action list or
315 * as a link from a message deliverer endpoint such as an email message.
316 */
317 NotificationMessageDelivery delivery = messageDeliveryService.getNotificationMessageDelivery(Long.decode(messageDeliveryId));
318 if (delivery == null) {
319 throw new RuntimeException("Could not find message delivery with id " + messageDeliveryId);
320 }
321 NotificationBo notification = delivery.getNotification();
322
323 /*
324 * dismiss the message delivery
325 */
326
327 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalNm);
328 notificationService.dismissNotificationMessageDelivery(delivery.getId(), principal.getPrincipalId(), action);
329
330 List<NotificationSenderBo> senders = notification.getSenders();
331 List<NotificationRecipientBo> recipients = notification.getRecipients();
332
333 String contenthtml = Util.transformContent(notification);
334
335 // first check to see if this is a standalone window, b/c if it is, we'll want to close
336 if(standaloneWindow != null && standaloneWindow.equals("true")) {
337 view = "NotificationActionTakenCloseWindow";
338 } else { // otherwise check to see if the details need to be rendered in line (no stuff around them)
339 if (command != null && command.equals(NotificationConstants.NOTIFICATION_DETAIL_VIEWS.INLINE)) {
340 view = "NotificationDetailInline";
341 }
342 }
343
344 Map<String, Object> model = new HashMap<String, Object>();
345 model.put("notification", notification);
346 model.put("message", message);
347 model.put("senders", senders);
348 model.put("recipients", recipients);
349 model.put("contenthtml", contenthtml);
350 model.put("messageDeliveryId", messageDeliveryId);
351 model.put("command", command);
352 model.put(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.STANDALONE_WINDOW, standaloneWindow);
353 return new ModelAndView(view, model);
354 }
355 }