View Javadoc

1   package org.itracker.web.actions.project;
2   
3   import java.io.IOException;
4   import java.util.ArrayList;
5   import java.util.Arrays;
6   import java.util.Collection;
7   import java.util.Collections;
8   import java.util.Date;
9   import java.util.HashMap;
10  import java.util.HashSet;
11  import java.util.Iterator;
12  import java.util.List;
13  import java.util.Locale;
14  import java.util.Map;
15  import java.util.MissingResourceException;
16  import java.util.ResourceBundle;
17  import java.util.Set;
18  
19  import javax.servlet.ServletException;
20  import javax.servlet.http.HttpServletRequest;
21  import javax.servlet.http.HttpSession;
22  
23  import org.apache.log4j.Logger;
24  import org.apache.struts.action.ActionForward;
25  import org.apache.struts.action.ActionMapping;
26  import org.apache.struts.action.ActionMessages;
27  import org.itracker.core.resources.ITrackerResources;
28  import org.itracker.model.Component;
29  import org.itracker.model.CustomField;
30  import org.itracker.model.Issue;
31  import org.itracker.model.IssueField;
32  import org.itracker.model.IssueHistory;
33  import org.itracker.model.IssueRelation;
34  import org.itracker.model.NameValuePair;
35  import org.itracker.model.Notification;
36  import org.itracker.model.PermissionType;
37  import org.itracker.model.Project;
38  import org.itracker.model.ProjectScript;
39  import org.itracker.model.Status;
40  import org.itracker.model.User;
41  import org.itracker.model.Version;
42  import org.itracker.model.Notification.Role;
43  import org.itracker.model.Notification.Type;
44  import org.itracker.services.IssueService;
45  import org.itracker.services.NotificationService;
46  import org.itracker.services.ProjectService;
47  import org.itracker.services.UserService;
48  import org.itracker.services.exceptions.WorkflowException;
49  import org.itracker.services.util.Convert;
50  import org.itracker.services.util.HTMLUtilities;
51  import org.itracker.services.util.IssueUtilities;
52  import org.itracker.services.util.NotificationUtilities;
53  import org.itracker.services.util.ProjectUtilities;
54  import org.itracker.services.util.UserUtilities;
55  import org.itracker.services.util.WorkflowUtilities;
56  import org.itracker.web.forms.IssueForm;
57  import org.itracker.web.util.AttachmentUtilities;
58  import org.itracker.web.util.Constants;
59  import org.itracker.web.util.LoginUtilities;
60  import org.itracker.web.util.ServletContextUtils;
61  
62  public class EditIssueActionUtil {
63  	private static final Logger log = Logger.getLogger(EditIssueActionUtil.class);
64  	
65  	public static final Issue processFullEdit(Issue issue, Project project, User user,
66  			Map<Integer, Set<PermissionType>> userPermissions, Locale locale,
67  			IssueForm form, IssueService issueService, ActionMessages errors) throws Exception {
68  		int previousStatus = issue.getStatus();		
69  		boolean needReloadIssue = false;		
70  		ActionMessages msg = new ActionMessages();
71  		issue = AttachmentUtilities.addAttachment(issue, project, user, form, ServletContextUtils.getItrackerServices(), msg);
72  		
73  		if (!msg.isEmpty()) {
74  			// Validation of attachment failed
75  			errors.add(msg);
76  			return issue;
77  		}
78  		
79  		needReloadIssue = issueService.setIssueVersions(issue.getId(), 
80  				new HashSet<Integer>(Arrays.asList(form.getVersions())), 
81  				user.getId());
82  				
83  		needReloadIssue = needReloadIssue | issueService.setIssueComponents(issue.getId(), 
84  				new HashSet<Integer>(Arrays.asList(form.getComponents())), 
85  				user.getId());
86  		// save attachment and reload updated issue
87  
88  //		needReloadIssue = needReloadIssue | addAttachment(issue, project, user, form, issueService, errors);
89  
90  		// reload issue for further updates
91  		if (needReloadIssue) {
92  			if (log.isDebugEnabled()) {
93  				log.debug("processFullEdit: updating issue from session: " + issue);
94  			}
95  			issue = issueService.getIssue(issue.getId());
96  		}
97  		
98  		Integer targetVersion = form.getTargetVersion();
99  		if (targetVersion != null && targetVersion != -1) {
100 			ProjectService projectService = ServletContextUtils.getItrackerServices()
101 					.getProjectService();
102 			Version version = projectService.getProjectVersion(targetVersion);
103 			if (version == null) {
104 				throw new RuntimeException("No version with Id "
105 						+ targetVersion);
106 			}
107 			issue.setTargetVersion(version);
108 		}
109 
110 		issue.setResolution(form.getResolution());
111 		issue.setSeverity(form.getSeverity());
112 		
113 		applyLimitedFields(issue, project, user, userPermissions, locale, form, issueService);
114 		
115 		Integer formStatus = form.getStatus();
116 		issue.setStatus(formStatus);
117 		if (formStatus != null) {
118 			if (log.isDebugEnabled()) {
119 				log.debug("processFullEdit: processing status: " + formStatus);
120 			}			
121 			if (previousStatus != -1) {
122 				// Reopened the issue. Reset the resolution field.
123 				if ((previousStatus >= IssueUtilities.STATUS_ASSIGNED && previousStatus < IssueUtilities.STATUS_RESOLVED)
124 						&& (previousStatus >= IssueUtilities.STATUS_RESOLVED && previousStatus < IssueUtilities.STATUS_END)) {
125 					issue.setResolution("");
126 				}
127 	
128 				if (previousStatus >= IssueUtilities.STATUS_CLOSED
129 						&& !UserUtilities.hasPermission(userPermissions, project
130 								.getId(), UserUtilities.PERMISSION_CLOSE)) {
131 					if (previousStatus < IssueUtilities.STATUS_CLOSED) {
132 						issue.setStatus(previousStatus);
133 					} else {
134 						issue.setStatus(IssueUtilities.STATUS_RESOLVED);
135 					}
136 				}
137 	
138 				if (issue.getStatus() < IssueUtilities.STATUS_NEW
139 						|| issue.getStatus() >= IssueUtilities.STATUS_END) {
140 					issue.setStatus(previousStatus);
141 				}	
142 			} else if (issue.getStatus() >= IssueUtilities.STATUS_CLOSED
143 					&& !UserUtilities.hasPermission(userPermissions, project
144 							.getId(), UserUtilities.PERMISSION_CLOSE)) {
145 				issue.setStatus(IssueUtilities.STATUS_RESOLVED);
146 			}
147 		}
148 
149 		if (issue.getStatus() < IssueUtilities.STATUS_NEW) {
150 			if (log.isDebugEnabled()) {
151 				log.debug("processFullEdit: status < STATUS_NEW: " + issue.getStatus());
152 			}
153 			issue.setStatus(IssueUtilities.STATUS_NEW);
154 			if (log.isDebugEnabled()) {
155 				log.debug("processFullEdit: updated to: " + issue.getStatus());
156 			}
157 		} else if (issue.getStatus() >= IssueUtilities.STATUS_END) {
158 			if (log.isDebugEnabled()) {
159 				log.debug("processFullEdit: status >= STATUS_END: " + issue.getStatus());
160 			}
161 			if (!UserUtilities.hasPermission(userPermissions, project.getId(),
162 					UserUtilities.PERMISSION_CLOSE)) {
163 				issue.setStatus(IssueUtilities.STATUS_RESOLVED);
164 			} else {
165 				issue.setStatus(IssueUtilities.STATUS_CLOSED);
166 			}
167 			if (log.isDebugEnabled()) {
168 				log.debug("processFullEdit: status updated to: " + issue.getStatus());
169 			}
170 		}
171 		if (log.isDebugEnabled()) {
172 			log.debug("processFullEdit: updating issue " + issue);
173 		}
174 		return issueService.updateIssue(issue, user.getId());
175 	}
176 
177 	public static final void applyLimitedFields(Issue issue, Project project,
178 			User user, Map<Integer, Set<PermissionType>> userPermissionsMap,
179 			Locale locale, IssueForm form, IssueService issueService) throws Exception {
180 				
181 		issue.setDescription(form.getDescription());
182 
183 		setIssueFields(issue, user, locale, form, issueService);
184 		setOwner(issue, user, userPermissionsMap, form, issueService);
185 		addHistoryEntry(issue, user, form, issueService);
186 	}
187 
188 	private static void setIssueFields(Issue issue, User user, Locale locale,
189 			IssueForm form, IssueService issueService) throws Exception {
190 		if (log.isDebugEnabled()) {
191 			log.debug("setIssueFields: called");
192 		}
193 		List<CustomField> projectCustomFields = issue.getProject()
194 				.getCustomFields();
195 		if (log.isDebugEnabled()) {
196 			log.debug("setIssueFields: got project custom fields: " + projectCustomFields);
197 		}
198 
199 		if (projectCustomFields == null || projectCustomFields.size() == 0) {
200 			log.debug("setIssueFields: no custom fields, returning...");
201 			return;
202 		}
203 		
204 		
205 		// here you see some of the ugly side of Struts 1.3 - the forms... they
206 		// can only contain Strings and some simple objects types...
207 		HashMap<String, String> formCustomFields = form.getCustomFields();
208 		
209 		if (log.isDebugEnabled()) {
210 			log.debug("setIssueFields: got form custom fields: " + formCustomFields);
211 		}
212 		
213 		if (formCustomFields == null || formCustomFields.size() == 0) {
214 			log.debug("setIssueFields: no form custom fields, returning..");
215 			return;
216 		}
217 		
218 		ResourceBundle bundle = ITrackerResources.getBundle(locale);
219 //		List<IssueField> issueFieldsList = new ArrayList<IssueField>(projectCustomFields.size());
220 		Iterator<CustomField> customFieldsIt = projectCustomFields.iterator();
221 		// declare iteration fields
222 		CustomField field;
223 		String fieldValue;
224 		IssueField issueField;
225 		try {
226 			if (log.isDebugEnabled()) {
227 				log.debug("setIssueFields: processing project fields");
228 			}
229 			// set values to issue-fields and add if needed
230 			while (customFieldsIt.hasNext()) {
231 
232 				field = customFieldsIt.next();
233 				fieldValue = (String) formCustomFields.get(String.valueOf(field
234 						.getId()));
235 
236 				// remove the existing field for re-setting 
237 				issueField = getIssueField(issue, field);
238 				
239 
240 				if (fieldValue != null && fieldValue.trim().length() > 0) {
241 					if (null == issueField) {
242 						issueField = new IssueField(issue, field);
243 						issue.getFields().add(issueField);
244 					}
245 					
246 					issueField.setValue(fieldValue, bundle);
247 				} else {
248 					if (null != issueField) {
249 						issue.getFields().remove(issueField);
250 					}
251 				}
252 			}
253 			
254 			// set new issue fields for later saving
255 //			issue.setFields(issueFieldsList);
256 			
257 //			issueService.setIssueFields(issue.getId(), issueFieldsList);
258 		} catch (Exception e) {
259 			log.error("setIssueFields: failed to process custom fields", e);
260 			throw e;
261 		}
262 	}
263 
264 	private static IssueField getIssueField(Issue issue, CustomField field) {
265 		Iterator<IssueField> it = issue.getFields().iterator();
266 		IssueField issueField = null;
267 		while (it.hasNext()) {
268 			issueField = it.next();
269 			if (issueField.getCustomField().equals(field)) {
270 				return issueField;
271 			}
272 		}
273 		return null;
274 		
275 	}
276 
277 	private static void setOwner(Issue issue, User user,
278 			Map<Integer, Set<PermissionType>> userPermissionsMap,
279 			IssueForm form, IssueService issueService) throws Exception {
280 		if (log.isDebugEnabled()) {
281 			log.debug("setOwner: called to " + form.getOwnerId());
282 		}
283 		Integer currentOwner = (issue.getOwner() == null) ? null : issue
284 				.getOwner().getId();
285 
286 		Integer ownerId = form.getOwnerId();
287 
288 		if (ownerId == null || ownerId.equals(currentOwner)) {
289 			if (log.isDebugEnabled()) {
290 				log.debug("setOwner: returning, existing owner is the same: " + issue.getOwner());
291 			}
292 			return;
293 		}
294 
295 		if (UserUtilities.hasPermission(userPermissionsMap,
296 				UserUtilities.PERMISSION_ASSIGN_OTHERS)
297 				|| (UserUtilities.hasPermission(userPermissionsMap,
298 						UserUtilities.PERMISSION_ASSIGN_SELF) && user.getId()
299 						.equals(ownerId))
300 				|| (UserUtilities.hasPermission(userPermissionsMap,
301 						UserUtilities.PERMISSION_UNASSIGN_SELF)
302 						&& user.getId().equals(currentOwner) && ownerId
303 						.intValue() == -1)) {
304 			User newOwner = ServletContextUtils.getItrackerServices().getUserService().getUser(ownerId);
305 			if (log.isDebugEnabled()) {
306 				log.debug("setOwner: setting new owner " + newOwner + " to " + issue);
307 			}
308 			issue.setOwner(newOwner);
309 //			issueService.assignIssue(issue.getId(), ownerId, user.getId());
310 		}
311 
312 	}
313 
314 	private static void addHistoryEntry(Issue issue, User user, IssueForm form,
315 			IssueService issueService) throws Exception {
316 			try {
317 				String history = form.getHistory();
318 	
319 				if (history == null || history.equals("")) {
320 					if (log.isDebugEnabled()) {
321 						log.debug("addHistoryEntry: skip history to " + issue);
322 					}
323 					return;
324 				}
325 				
326 
327 		        if (ProjectUtilities.hasOption(ProjectUtilities.OPTION_SURPRESS_HISTORY_HTML, issue.getProject().getOptions())) {
328 	            	history = HTMLUtilities.removeMarkup(history);
329 	            } else if(ProjectUtilities.hasOption(ProjectUtilities.OPTION_LITERAL_HISTORY_HTML, issue.getProject().getOptions())) {
330 	            	history = HTMLUtilities.escapeTags(history);
331 	            } else {
332 	            	history = HTMLUtilities.newlinesToBreaks(history);
333 	            }
334 				
335 				
336 				if (log.isDebugEnabled()) {
337 					log.debug("addHistoryEntry: adding history to " + issue);
338 				}
339 				IssueHistory issueHistory = new IssueHistory(issue, user, history,
340 					IssueUtilities.HISTORY_STATUS_AVAILABLE);
341 	
342 				issueHistory.setDescription(((IssueForm) form).getHistory());
343 				issueHistory.setCreateDate(new Date());
344 			
345 				issueHistory.setLastModifiedDate(new Date());
346 				issue.getHistory().add(issueHistory);
347 
348 
349 	            
350 //  TODO why do we need to updateIssue here, and can not later?
351 //			issueService.updateIssue(issue, user.getId());
352 		} catch (Exception e) {
353 			log.error("addHistoryEntry: failed to add", e);
354 			throw e;
355 		}
356 //		issueService.addIssueHistory(issueHistory);
357 		if (log.isDebugEnabled()) {
358 			log.debug("addHistoryEntry: added history for issue " + issue);
359 		}
360 	}
361 
362 	public static final Issue processLimitedEdit(Issue issue, Project project,
363 			User user, Map<Integer, Set<PermissionType>> userPermissionsMap,
364 			Locale locale, IssueForm form, IssueService issueService, ActionMessages messages)
365 			throws Exception {
366 		ActionMessages msg = new ActionMessages();
367 		issue = AttachmentUtilities.addAttachment(issue, project, user, form, ServletContextUtils.getItrackerServices(), msg);
368 		
369 		if (!msg.isEmpty()) {
370 			messages.add(msg);
371 			return issue;
372 		}
373 		
374 		Integer formStatus = form.getStatus();
375 
376 		if (formStatus != null) {
377 
378 			if (issue.getStatus() >= IssueUtilities.STATUS_RESOLVED
379 					&& formStatus >= IssueUtilities.STATUS_CLOSED
380 					&& UserUtilities.hasPermission(userPermissionsMap,
381 							UserUtilities.PERMISSION_CLOSE)) {
382 
383 				issue.setStatus(formStatus);
384 			}
385 
386 		}
387 		
388 		EditIssueActionUtil.applyLimitedFields(issue, project, user, userPermissionsMap, locale, form, issueService);
389 		return issueService.updateIssue(issue, user.getId());
390 		
391 	}
392 	
393 	public static final void sendNotification(Integer issueId, int previousStatus,
394 			String baseURL, NotificationService notificationService) {
395 		Type notificationType = Type.UPDATED;
396 
397 		Issue issue = ServletContextUtils.getItrackerServices().getIssueService().getIssue(issueId);
398 
399 		if ((previousStatus < IssueUtilities.STATUS_CLOSED)
400 				&& issue.getStatus() >= IssueUtilities.STATUS_CLOSED) {
401 			notificationType = Type.CLOSED;
402 		}
403 
404 		if (log.isDebugEnabled()) {
405 			log.debug("notificationService: before send");
406 		}
407 		notificationService.sendNotification(issue, notificationType, baseURL);
408 
409 		if (log.isDebugEnabled()) {
410 			log.debug("notificationService: after send");
411 		}
412 	}
413 
414 	public static final ActionForward getReturnForward(Issue issue, Project project,
415 			IssueForm form, ActionMapping mapping) throws Exception {
416 		if ("index".equals(form.getCaller())) {
417 			log.info("EditIssueAction: Forward: index");
418 			return mapping.findForward("index");
419 		} else if ("viewissue".equals(form.getCaller()) && issue.getStatus() >= IssueUtilities.STATUS_CLOSED) {
420 			log.info("EditIssueAction: Forward: viewissue");
421 			return new ActionForward(mapping.findForward("viewissue").getPath()
422 					+ "?id=" + issue.getId());
423 		} else {
424 			log.info("EditIssueAction: Forward: listissues");			
425 			return new ActionForward(mapping.findForward("listissues")
426 					.getPath()
427 					+ "?projectId=" + project.getId());
428 		}
429 	}
430 
431 	/**
432 	 * method needed to prepare request for edit_issue.jsp
433 	 * 
434 	 * @throws WorkflowException
435 	 */
436 	public static final void setupJspEnv(ActionMapping mapping,
437 			IssueForm issueForm, HttpServletRequest request, Issue issue,
438 			IssueService issueService, UserService userService,
439 			Map<Integer, Set<PermissionType>> userPermissions,
440 			Map<Integer, List<NameValuePair>> listOptions, ActionMessages errors)
441 			throws ServletException, IOException, WorkflowException {
442 		
443 		if (log.isDebugEnabled()) {
444 			log.debug("setupJspEnv: for issue " + issue);
445 		}
446 		
447 		NotificationService notificationService = ServletContextUtils
448 		.getItrackerServices().getNotificationService();
449 		String pageTitleKey = "itracker.web.editissue.title";
450 		String pageTitleArg = request.getParameter("id");
451 		Locale locale = LoginUtilities.getCurrentLocale(request);
452 		User um = LoginUtilities.getCurrentUser(request);
453 		List<NameValuePair> statuses = WorkflowUtilities.getListOptions(
454 				listOptions, IssueUtilities.FIELD_STATUS);
455 		String statusName = IssueUtilities.getStatusName(issue.getStatus(),locale);
456 		boolean hasFullEdit = UserUtilities.hasPermission(userPermissions,
457 				issue.getProject().getId(), UserUtilities.PERMISSION_EDIT_FULL);
458 		List<NameValuePair> resolutions = WorkflowUtilities.getListOptions(
459 				listOptions, IssueUtilities.FIELD_RESOLUTION);
460 		String severityName = IssueUtilities.getSeverityName(issue
461 				.getSeverity(),locale);
462 		List<NameValuePair> components = WorkflowUtilities.getListOptions(
463 				listOptions, IssueUtilities.FIELD_COMPONENTS);
464 		List<NameValuePair> versions = WorkflowUtilities.getListOptions(
465 				listOptions, IssueUtilities.FIELD_VERSIONS);
466 		List<NameValuePair> targetVersion = WorkflowUtilities.getListOptions(
467 				listOptions, IssueUtilities.FIELD_TARGET_VERSION);
468 		List<Component> issueComponents = issue.getComponents();
469 		Collections.sort(issueComponents);
470 		List<Version> issueVersions = issue.getVersions();
471 		Collections.sort(issueVersions, new Version.VersionComparator());
472 		/* Get project fields and put name and value in map */
473 		setupProjectFieldsMapJspEnv(issue.getProject().getCustomFields(), issue.getFields(), request);
474 
475 		setupRelationsRequestEnv(issue.getRelations(), request);
476 		
477 
478 		request.setAttribute("pageTitleKey", pageTitleKey);
479 		request.setAttribute("pageTitleArg", pageTitleArg);
480 //		request.setAttribute("wrap", wrap);
481 		request.getSession().setAttribute(Constants.LIST_OPTIONS_KEY,
482 				listOptions);
483 		request.setAttribute("targetVersions", targetVersion);
484 		request.setAttribute("components", components);
485 		request.setAttribute("versions", versions);
486 		request.setAttribute("hasIssueNotification", !notificationService
487 				.hasIssueNotification(issue, um.getId()));
488 		request.setAttribute("hasEditIssuePermission", UserUtilities
489 				.hasPermission(userPermissions, issue.getProject().getId(),
490 						UserUtilities.PERMISSION_EDIT));
491 		request.setAttribute("canCreateIssue",
492 				issue.getProject().getStatus() == Status.ACTIVE
493 						&& UserUtilities.hasPermission(userPermissions, issue
494 								.getProject().getId(),
495 								UserUtilities.PERMISSION_CREATE));
496 		request.setAttribute("issueComponents", issueComponents);
497 		request.setAttribute("issueVersions",
498 				issueVersions == null ? new ArrayList<Version>()
499 						: issueVersions);
500 		request.setAttribute("statuses", statuses);
501 		request.setAttribute("statusName", statusName);
502 		request.setAttribute("hasFullEdit", hasFullEdit);
503 		request.setAttribute("resolutions", resolutions);
504 		request.setAttribute("severityName", severityName);
505 		request.setAttribute("hasPredefinedResolutionsOption", ProjectUtilities
506 				.hasOption(ProjectUtilities.OPTION_PREDEFINED_RESOLUTIONS,
507 						issue.getProject().getOptions()));
508 		request.setAttribute("issueOwnerName",
509 				(issue.getOwner() == null ? ITrackerResources.getString(
510 						"itracker.web.generic.unassigned",locale)
511 						: issue.getOwner().getFirstName() + " "
512 								+ issue.getOwner().getLastName()));
513 		request.setAttribute("isStatusResolved",
514 				issue.getStatus() >= IssueUtilities.STATUS_RESOLVED);
515 		
516 
517 		request.setAttribute("fieldSeverity", WorkflowUtilities.getListOptions(
518 				listOptions, IssueUtilities.FIELD_SEVERITY));
519 		request.setAttribute("possibleOwners", WorkflowUtilities
520 				.getListOptions(listOptions, IssueUtilities.FIELD_OWNER));
521 
522 		request.setAttribute("hasNoViewAttachmentOption", ProjectUtilities
523 				.hasOption(ProjectUtilities.OPTION_NO_ATTACHMENTS, issue
524 						.getProject().getOptions()));
525 		
526 		if (log.isDebugEnabled()) {
527 			log.debug("setupJspEnv: options " + issue.getProject().getOptions() + ", hasNoViewAttachmentOption: " + request.getAttribute("hasNoViewAttachmentOption"));
528 		}
529 		
530 		setupNotificationsInRequest(request, issue, notificationService);
531 
532 		// setup issue to request, as it's needed by the jsp.
533 		request.setAttribute(Constants.ISSUE_KEY, issue);
534 		request.setAttribute("issueForm", issueForm);
535 		request.setAttribute(Constants.PROJECT_KEY, issue.getProject());
536 		List<IssueHistory> issueHistory = issueService.getIssueHistory(issue
537 				.getId());
538 		Collections.sort(issueHistory, IssueHistory.CREATE_DATE_COMPARATOR);
539 		request.setAttribute("issueHistory", issueHistory);
540 
541 
542 	}
543 	
544 	/**
545 	 *  Get project fields and put name and value in map 
546 	 *  TODO: simplify this code, it's not readable, unsave yet.
547 	 */
548 	protected static final void setupProjectFieldsMapJspEnv(List<CustomField> projectFields, Collection<IssueField> issueFields, HttpServletRequest request) {
549 		Map<CustomField,String> projectFieldsMap = new HashMap<CustomField, String>();
550 
551 		if (projectFields != null && projectFields.size() > 0) {
552 			Collections.sort(projectFields, CustomField.ID_COMPARATOR);
553 			
554 			HashMap<String, String> fieldValues = new HashMap<String, String>();
555 			Iterator<IssueField> issueFieldsIt = issueFields.iterator();
556 			while (issueFieldsIt.hasNext()) {
557 				IssueField issueField = (IssueField) issueFieldsIt.next();
558 			
559 				if (issueField.getCustomField() != null
560 						&& issueField.getCustomField().getId() > 0) {
561 					if (issueField.getCustomField().getFieldType() == CustomField.Type.DATE) {
562 						Locale locale = LoginUtilities.getCurrentLocale(request);
563 						String value = issueField.getValue(locale);
564 						fieldValues.put(issueField.getCustomField().getId()
565 								.toString(), value);
566 					} else {
567 						fieldValues.put(issueField.getCustomField().getId()
568 							.toString(), issueField
569 							.getStringValue());
570 					}
571 				}
572 			}
573 			Iterator<CustomField> fieldsIt = projectFields.iterator();
574 			CustomField field;
575 			while (fieldsIt.hasNext()) {
576 				
577 				field = fieldsIt.next();
578 				
579 				String fieldValue = fieldValues.get(String.valueOf(field
580 						.getId()));
581 				if (null == fieldValue) {
582 					fieldValue = "";
583 				}
584 //				if (fieldValue != null && field.getFieldType() == CustomField.Type.LIST) { 
585 //					fieldValue = CustomFieldUtilities.getCustomFieldOptionName(field, 
586 //							fieldValue, LoginUtilities.getCurrentLocale(request)); 
587 ////					projectFields.get(i).getOptionNameByValue(fieldValue));
588 //	        	} 
589 				projectFieldsMap.put(field, fieldValue);
590 				
591 			}
592 			
593 			request.setAttribute("projectFieldsMap", projectFieldsMap);
594 		}
595 	}
596 
597 	
598 	protected static final void setupRelationsRequestEnv(List<IssueRelation> relations, HttpServletRequest request) {
599         Collections.sort(relations, IssueRelation.LAST_MODIFIED_DATE_COMPARATOR);
600         request.setAttribute("issueRelations", relations);
601 
602 	}
603 	
604 	
605 	public static final void setupNotificationsInRequest(
606 			HttpServletRequest request, Issue issue,
607 			NotificationService notificationService) {
608 		List<Notification> notifications = notificationService
609 				.getIssueNotifications(issue);
610 
611 		Collections.sort(notifications, Notification.TYPE_COMPARATOR);
612 
613 		request.setAttribute("notifications", notifications);
614 		Map<User, Set<Role>> notificationMap = NotificationUtilities
615 				.mappedRoles(notifications);
616 		request.setAttribute("notificationMap", notificationMap);
617 		request.setAttribute("notifiedUsers", notificationMap.keySet());
618 	}
619 
620 	public static Map<Integer, List<NameValuePair>> getListOptions(
621 			HttpServletRequest request, Issue issue,
622 			List<NameValuePair> ownersList,
623 			Map<Integer, Set<PermissionType>> userPermissions, Project project,
624 			User currUser) {
625 		Map<Integer, List<NameValuePair>> listOptions = new HashMap<Integer, List<NameValuePair>>();
626 
627 		Locale locale = (Locale) request.getSession().getAttribute(
628 				Constants.LOCALE_KEY);
629 
630 		if (ownersList != null && ownersList.size() > 0) {
631 			listOptions.put(IssueUtilities.FIELD_OWNER, ownersList);
632 		}
633 
634 		boolean hasFullEdit = UserUtilities.hasPermission(userPermissions,
635 				project.getId(), UserUtilities.PERMISSION_EDIT_FULL);
636 
637 		List<NameValuePair> allStatuses = IssueUtilities.getStatuses(locale);
638 		List<NameValuePair> statusList = new ArrayList<NameValuePair>();
639 
640 		if (!hasFullEdit) {
641 
642 			if (issue.getStatus() >= IssueUtilities.STATUS_RESOLVED
643 					&& UserUtilities.hasPermission(userPermissions, project
644 							.getId(), UserUtilities.PERMISSION_CLOSE)) {
645 				for (int i = 0; i < allStatuses.size(); i++) {
646 					int statusNumber = Integer.parseInt(allStatuses.get(i)
647 							.getValue());
648 					if (issue.getStatus() >= IssueUtilities.STATUS_CLOSED
649 							&& statusNumber >= IssueUtilities.STATUS_CLOSED) {
650 						statusList.add(allStatuses.get(i));
651 					} else if (issue.getStatus() >= IssueUtilities.STATUS_RESOLVED
652 							&& statusNumber >= IssueUtilities.STATUS_RESOLVED) {
653 						statusList.add(allStatuses.get(i));
654 					}
655 				}
656 			} else {
657 				// Can't change
658 			}
659 
660 		} else {
661 
662 			if (currUser.isSuperUser()) {
663 				for (int i = 0; i < allStatuses.size(); i++) {
664 					statusList.add(allStatuses.get(i));
665 				}
666 			} else if (issue.getStatus() >= IssueUtilities.STATUS_ASSIGNED
667 					&& issue.getStatus() < IssueUtilities.STATUS_RESOLVED) {
668 				for (int i = 0; i < allStatuses.size(); i++) {
669 					int statusNumber = Integer.parseInt(allStatuses.get(i)
670 							.getValue());
671 					if (statusNumber >= IssueUtilities.STATUS_ASSIGNED
672 							&& statusNumber < IssueUtilities.STATUS_CLOSED) {
673 						statusList.add(allStatuses.get(i));
674 					} else if (statusNumber >= IssueUtilities.STATUS_CLOSED
675 							&& ProjectUtilities
676 									.hasOption(
677 											ProjectUtilities.OPTION_ALLOW_ASSIGN_TO_CLOSE,
678 											project.getOptions())
679 							&& UserUtilities.hasPermission(userPermissions,
680 									project.getId(),
681 									UserUtilities.PERMISSION_CLOSE)) {
682 						statusList.add(allStatuses.get(i));
683 					}
684 				}
685 			} else if (issue.getStatus() >= IssueUtilities.STATUS_RESOLVED
686 					&& issue.getStatus() < IssueUtilities.STATUS_CLOSED) {
687 				for (int i = 0; i < allStatuses.size(); i++) {
688 					int statusNumber = Integer.parseInt(allStatuses.get(i)
689 							.getValue());
690 					if (statusNumber >= IssueUtilities.STATUS_ASSIGNED
691 							&& statusNumber < IssueUtilities.STATUS_CLOSED) {
692 						statusList.add(allStatuses.get(i));
693 					} else if (statusNumber >= IssueUtilities.STATUS_CLOSED
694 							&& UserUtilities.hasPermission(userPermissions,
695 									project.getId(),
696 									UserUtilities.PERMISSION_CLOSE)) {
697 						statusList.add(allStatuses.get(i));
698 					}
699 				}
700 			} else if (issue.getStatus() >= IssueUtilities.STATUS_CLOSED) {
701 				for (int i = 0; i < allStatuses.size(); i++) {
702 					int statusNumber = Integer.parseInt(allStatuses.get(i)
703 							.getValue());
704 					if ((statusNumber >= IssueUtilities.STATUS_ASSIGNED && statusNumber < IssueUtilities.STATUS_RESOLVED)
705 							|| statusNumber >= IssueUtilities.STATUS_CLOSED) {
706 						statusList.add(allStatuses.get(i));
707 					}
708 				}
709 			} else {
710 				// Can't change
711 			}
712 
713 		}
714 		// sort by status code so it will be ascending output.
715 		Collections.sort(statusList, NameValuePair.VALUE_COMPARATOR);
716 		listOptions.put(IssueUtilities.FIELD_STATUS, statusList);
717 
718 		List<NameValuePair> severities = IssueUtilities.getSeverities(locale);
719 		// sort by severity code so it will be ascending output.
720 		Collections.sort(severities, NameValuePair.VALUE_COMPARATOR);
721 		listOptions.put(IssueUtilities.FIELD_SEVERITY, severities);
722 
723 		List<NameValuePair> resolutions = IssueUtilities.getResolutions(locale);
724 		listOptions.put(IssueUtilities.FIELD_RESOLUTION, resolutions);
725 
726 		List<Component> components = project.getComponents();
727 		Collections.sort(components, Component.NAME_COMPARATOR);
728 		listOptions.put(IssueUtilities.FIELD_COMPONENTS, Convert
729 				.componentsToNameValuePairs(components));
730 
731 		List<Version> versions = project.getVersions();
732 		// Collections.sort(versions, new Version());
733 		listOptions.put(IssueUtilities.FIELD_VERSIONS, Convert
734 				.versionsToNameValuePairs(versions));
735 		listOptions.put(IssueUtilities.FIELD_TARGET_VERSION, Convert
736 				.versionsToNameValuePairs(versions));
737 
738 		List<CustomField> projectFields = project.getCustomFields();
739 		for (int i = 0; i < projectFields.size(); i++) {
740 			if (projectFields.get(i).getFieldType() == CustomField.Type.LIST) {
741 //				projectFields.get(i).setLabels(locale);
742 				listOptions.put(projectFields.get(i).getId(), Convert
743 						.customFieldOptionsToNameValuePairs(projectFields
744 								.get(i).getOptions()));
745 			}
746 		}
747 
748 		return listOptions;
749 	}
750 
751 	public static final void setupIssueForm(IssueForm issueForm, Issue issue,
752 			Map<Integer, List<NameValuePair>> listOptions,
753 			HttpServletRequest request, ActionMessages errors)
754 			throws WorkflowException {
755 		HttpSession session = request.getSession(true);
756 
757 		IssueService issueService = ServletContextUtils.getItrackerServices()
758 				.getIssueService();
759 		Locale locale = (Locale) session.getAttribute(Constants.LOCALE_KEY);
760 		issueForm.setId(issue.getId());
761 		issueForm.setProjectId(issue.getProject().getId());
762 		issueForm.setPrevStatus(issue.getStatus());
763 		issueForm.setCaller(request.getParameter("caller"));
764 
765 		issueForm.setDescription(HTMLUtilities.handleQuotes(issue
766 				.getDescription()));
767 		issueForm.setStatus(issue.getStatus());
768 
769 		if (!ProjectUtilities.hasOption(
770 				ProjectUtilities.OPTION_PREDEFINED_RESOLUTIONS, issue
771 						.getProject().getOptions())) {
772 			try {
773 				issue.setResolution(IssueUtilities.checkResolutionName(issue
774 						.getResolution(), locale));
775 			} catch (MissingResourceException mre) {
776 				log.error(mre.getMessage());
777 			} catch (NumberFormatException nfe) {
778 				log.error(nfe.getMessage());
779 			}
780 		}
781 
782 		issueForm.setResolution(HTMLUtilities.handleQuotes(issue
783 				.getResolution()));
784 		issueForm.setSeverity(issue.getSeverity());
785 
786 		issueForm.setTargetVersion(issue.getTargetVersion() == null ? -1
787 				: issue.getTargetVersion().getId());
788 
789 		issueForm.setOwnerId((issue.getOwner() == null ? -1 : issue.getOwner()
790 				.getId()));
791 
792 		List<IssueField> fields = issue.getFields();
793 		HashMap<String, String> customFields = new HashMap<String, String>();
794 		for (int i = 0; i < fields.size(); i++) {
795 			customFields.put(fields.get(i).getCustomField().getId().toString(),
796 					fields.get(i).getValue(locale));
797 		}
798 
799 		issueForm.setCustomFields(customFields);
800 
801 		HashSet<Integer> selectedComponents = issueService
802 				.getIssueComponentIds(issue.getId());
803 		if (selectedComponents != null) {
804 			Integer[] componentIds = null;
805 			ArrayList<Integer> components = new ArrayList<Integer>(
806 					selectedComponents);
807 			componentIds = components.toArray(new Integer[] {});
808 			issueForm.setComponents(componentIds);
809 		}
810 
811 		HashSet<Integer> selectedVersions = issueService
812 				.getIssueVersionIds(issue.getId());
813 		if (selectedVersions != null) {
814 			Integer[] versionIds = null;
815 			ArrayList<Integer> versions = new ArrayList<Integer>(
816 					selectedVersions);
817 			versionIds = versions.toArray(new Integer[] {});
818 			issueForm.setVersions(versionIds);
819 		}
820 
821 		List<ProjectScript> scripts = issue.getProject().getScripts();
822 		WorkflowUtilities.processFieldScripts(scripts,
823 				WorkflowUtilities.EVENT_FIELD_ONPOPULATE, listOptions, errors,
824 				issueForm);
825 		WorkflowUtilities.processFieldScripts(scripts,
826 				WorkflowUtilities.EVENT_FIELD_ONSETDEFAULT, null, errors,
827 				issueForm);
828 
829 	}
830 	
831 }