View Javadoc

1   /*
2    * This software was designed and created by Jason Carroll.
3    * Copyright (c) 2002, 2003, 2004 Jason Carroll.
4    * The author can be reached at jcarroll@cowsultants.com
5    * ITracker website: http://www.cowsultants.com
6    * ITracker forums: http://www.cowsultants.com/phpBB/index.php
7    *
8    * This program is free software; you can redistribute it and/or modify
9    * it only under the terms of the GNU General Public License as published by
10   * the Free Software Foundation; either version 2 of the License, or
11   * (at your option) any later version.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU General Public License for more details.
17   */
18  
19  package org.itracker.web.forms;
20  
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Locale;
25  import java.util.ResourceBundle;
26  
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpSession;
29  
30  import org.apache.log4j.Logger;
31  import org.apache.struts.action.ActionErrors;
32  import org.apache.struts.action.ActionMapping;
33  import org.apache.struts.action.ActionMessage;
34  import org.apache.struts.action.ActionMessages;
35  import org.apache.struts.upload.FormFile;
36  import org.itracker.core.resources.ITrackerResources;
37  import org.itracker.model.CustomField;
38  import org.itracker.model.Issue;
39  import org.itracker.model.NameValuePair;
40  import org.itracker.model.Project;
41  import org.itracker.model.ProjectScript;
42  import org.itracker.model.Status;
43  import org.itracker.model.User;
44  import org.itracker.services.ITrackerServices;
45  import org.itracker.services.exceptions.IssueException;
46  import org.itracker.services.exceptions.WorkflowException;
47  import org.itracker.services.util.CustomFieldUtilities;
48  import org.itracker.services.util.UserUtilities;
49  import org.itracker.services.util.WorkflowUtilities;
50  import org.itracker.web.actions.project.EditIssueActionUtil;
51  import org.itracker.web.ptos.CreateIssuePTO;
52  import org.itracker.web.util.AttachmentUtilities;
53  import org.itracker.web.util.Constants;
54  import org.itracker.web.util.RequestHelper;
55  
56  /**
57   * This form is by the struts actions to pass issue data.
58   */
59  public class IssueForm extends ITrackerForm {
60  
61  	/**
62  	 * 
63  	 */
64  	private static final long serialVersionUID = 1L;
65  
66  	private static final Logger log = Logger.getLogger(IssueForm.class);
67  
68  	private Integer id = null;
69  	private String caller = null;
70  	private Integer projectId = null;
71  	private Integer creatorId = null;
72  	private Integer ownerId = null;
73  	private String description = null;
74  	private Integer severity = null;
75  	private Integer status = null;
76  	private Integer prevStatus = null;
77  	private String resolution = null;
78  	private Integer targetVersion = null;
79  	private Integer[] components = new Integer[0];
80  	private Integer[] versions = new Integer[0];
81  	private String attachmentDescription = null;
82  	transient private FormFile attachment = null;
83  	private String history = null;
84  	// lets try to put Integer,String here:
85  	private HashMap<String, String> customFields = new HashMap<String, String>();
86  	private Integer relationType = null;
87  	private Integer relatedIssueId = null;
88  
89  	public FormFile getAttachment() {
90  		return attachment;
91  	}
92  
93  	public void setAttachment(FormFile attachment) {
94  		this.attachment = attachment;
95  	}
96  
97  	public String getAttachmentDescription() {
98  		return attachmentDescription;
99  	}
100 
101 	public void setAttachmentDescription(String attachmentDescription) {
102 		this.attachmentDescription = attachmentDescription;
103 	}
104 
105 	public String getCaller() {
106 		return caller;
107 	}
108 
109 	public void setCaller(String caller) {
110 		this.caller = caller;
111 	}
112 
113 	public Integer[] getComponents() {
114 		if (null == components)
115 			return null;
116 		return components.clone();
117 	}
118 
119 	public void setComponents(Integer[] components) {
120 		if (null == components)
121 			this.components = null;
122 		else
123 			this.components = components.clone();
124 	}
125 
126 	public Integer getCreatorId() {
127 		return creatorId;
128 	}
129 
130 	public void setCreatorId(Integer creatorId) {
131 		this.creatorId = creatorId;
132 	}
133 
134 	// let's try to put Integer,String here:
135 	public HashMap<String, String> getCustomFields() {
136 		return customFields;
137 	}
138 
139 	// let's try to put Integer,String here:
140 	public void setCustomFields(HashMap<String, String> customFields) {
141 		this.customFields = customFields;
142 	}
143 
144 	public String getDescription() {
145 		return description;
146 	}
147 
148 	public void setDescription(String description) {
149 		this.description = description;
150 	}
151 
152 	public String getHistory() {
153 		return history;
154 	}
155 
156 	public void setHistory(String history) {
157 		this.history = history;
158 	}
159 
160 	public Integer getId() {
161 		return id;
162 	}
163 
164 	public void setId(Integer id) {
165 		this.id = id;
166 	}
167 
168 	public Integer getOwnerId() {
169 		return ownerId;
170 	}
171 
172 	public void setOwnerId(Integer ownerId) {
173 		this.ownerId = ownerId;
174 	}
175 
176 	public Integer getPrevStatus() {
177 		return prevStatus;
178 	}
179 
180 	public void setPrevStatus(Integer prevStatus) {
181 		this.prevStatus = prevStatus;
182 	}
183 
184 	public Integer getProjectId() {
185 		return projectId;
186 	}
187 
188 	public void setProjectId(Integer projectId) {
189 		this.projectId = projectId;
190 	}
191 
192 	public Integer getRelatedIssueId() {
193 		return relatedIssueId;
194 	}
195 
196 	public void setRelatedIssueId(Integer relatedIssueId) {
197 		this.relatedIssueId = relatedIssueId;
198 	}
199 
200 	public Integer getRelationType() {
201 		return relationType;
202 	}
203 
204 	public void setRelationType(Integer relationType) {
205 		this.relationType = relationType;
206 	}
207 
208 	public String getResolution() {
209 		return resolution;
210 	}
211 
212 	public void setResolution(String resolution) {
213 		this.resolution = resolution;
214 	}
215 
216 	public Integer getSeverity() {
217 		return severity;
218 	}
219 
220 	public void setSeverity(Integer severity) {
221 		this.severity = severity;
222 	}
223 
224 	public Integer getStatus() {
225 		return status;
226 	}
227 
228 	public void setStatus(Integer status) {
229 		this.status = status;
230 	}
231 
232 	public Integer getTargetVersion() {
233 		return targetVersion;
234 	}
235 
236 	public void setTargetVersion(Integer targetVersion) {
237 		this.targetVersion = targetVersion;
238 	}
239 
240 	public Integer[] getVersions() {
241 		if (null == versions)
242 			return null;
243 		return versions.clone();
244 	}
245 
246 	public void setVersions(Integer[] versions) {
247 		if (null == versions)
248 			this.versions = null;
249 		else
250 			this.versions = versions.clone();
251 	}
252 
253 	/**
254 	 * This methods adds in validation for custom fields. It makes sure the
255 	 * datatype matches and also that all required fields have been populated.
256 	 * 
257 	 * @param mapping
258 	 *            the ActionMapping object
259 	 * @param request
260 	 *            the current HttpServletRequest object
261 	 * @return an ActionErrors object containing any validation errors
262 	 */
263 	public ActionErrors validate(ActionMapping mapping,
264 			HttpServletRequest request) {
265 		if (log.isDebugEnabled()) {
266 			log.debug("validate called: mapping: " + mapping + ", request: "
267 					+ request);
268 		}
269 		ActionErrors errors = super.validate(mapping, request);
270 
271 		if (log.isDebugEnabled()) {
272 			log.debug("validate called: mapping: " + mapping + ", request: "
273 					+ request + ", errors: " + errors);
274 		}
275 
276 		try {
277 			if (null != getId()) {
278 				Issue issue = getITrackerServices().getIssueService().getIssue(
279 						getId());
280 
281 				Locale locale = (Locale) request.getSession().getAttribute(
282 						Constants.LOCALE_KEY);
283 				User currUser = (User) request.getSession().getAttribute(
284 						Constants.USER_KEY);
285 				List<NameValuePair> ownersList = UserUtilities
286 						.getAssignableIssueOwnersList(issue,
287 								issue.getProject(), currUser, locale,
288 								getITrackerServices().getUserService(),
289 								RequestHelper.getUserPermissions(request
290 										.getSession()));
291 
292 				EditIssueActionUtil.setupJspEnv(mapping, this, request, issue,
293 						getITrackerServices().getIssueService(),
294 						getITrackerServices().getUserService(), RequestHelper
295 								.getUserPermissions(request.getSession()),
296 						EditIssueActionUtil.getListOptions(request, issue,
297 								ownersList, RequestHelper
298 										.getUserPermissions(request
299 												.getSession()), issue
300 										.getProject(), currUser), errors);
301 
302 				if (errors.isEmpty() && issue.getProject() == null) {
303 					if (log.isDebugEnabled()) {
304 						log.debug("validate: issue project is null: " + issue);
305 					}
306 					errors.add(ActionMessages.GLOBAL_MESSAGE,
307 							new ActionMessage(
308 									"itracker.web.error.invalidproject"));
309 				} else if (errors.isEmpty()
310 						&& issue.getProject().getStatus() != Status.ACTIVE) {
311 					if (log.isDebugEnabled()) {
312 						log.debug("validate: issue project is not active: " + issue);
313 					}
314 					errors.add(ActionMessages.GLOBAL_MESSAGE,
315 							new ActionMessage(
316 									"itracker.web.error.projectlocked"));
317 				} else if (errors.isEmpty()) {
318 					if (log.isDebugEnabled()) {
319 						log.debug("validate: validation had errors for " + issue + ": " + errors);
320 					}
321 					validateProjectScripts(issue.getProject(), errors, this);
322 					validateAttachment(this.getAttachment(), getITrackerServices(), errors);
323 				}
324 			} else {
325 				CreateIssuePTO.setupCreateIssue(request);
326 				HttpSession session = request.getSession();
327 				Project project = (Project) session
328 						.getAttribute(Constants.PROJECT_KEY);
329 				if (log.isDebugEnabled()) {
330 					log.debug("validate: validating create new issue for project: " + page);
331 				}
332 				validateProjectFields(project, request, errors);
333 				validateProjectScripts(project, errors, this);
334 				validateAttachment(this.getAttachment(), getITrackerServices(), errors);
335 			}
336 		} catch (Exception e) {
337 			e.printStackTrace();
338 			log.error("validate: unexpected exception", e);
339 			errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
340 					"itracker.web.error.system"));
341 		}
342 		if (log.isDebugEnabled()) {
343 			log.debug("validate: returning errors: " + errors);
344 		}
345 		return errors;
346 	}
347 
348 	private static void validateAttachment(FormFile attachment, ITrackerServices services, ActionMessages errors) {
349 		if (null != attachment) {
350 			ActionMessages msg = AttachmentUtilities.validate(attachment, services);
351 			if (!msg.isEmpty()) {
352 				if (log.isDebugEnabled()) {
353 					log.debug("validateAttachment: failed to validate, " + msg);
354 				}
355 				errors.add(msg);
356 			}
357 		}
358 	}
359 
360 	private static void validateProjectFields(Project project,
361 			HttpServletRequest request, ActionErrors errors) {
362 		List<CustomField> projectFields = project.getCustomFields();
363 		if (null != projectFields && projectFields.size() > 0) {
364 			HttpSession session = request.getSession();
365 
366 			Locale locale = ITrackerResources.getLocale();
367 			if (session != null) {
368 				locale = (Locale) session.getAttribute(Constants.LOCALE_KEY);
369 			}
370 
371 			ResourceBundle bundle = ITrackerResources.getBundle(locale);
372 			Iterator<CustomField> it = projectFields.iterator();
373 			while (it.hasNext()) {
374 				CustomField customField = it.next();
375 				String fieldValue = request.getParameter("customFields("
376 						+ customField.getId() + ")");
377 				if (fieldValue != null && !fieldValue.equals("")) {
378 
379 					// Don't create an IssueField only so that we can call
380 					// setValue to validate the value!
381 					// IssueField issueField = new
382 					// IssueField(projectFields.get(i));
383 					try {
384 						customField.checkAssignable(fieldValue, locale, bundle);
385 					} catch (IssueException ie) {
386 						String label = CustomFieldUtilities.getCustomFieldName(
387 								customField.getId(), locale);
388 						errors.add(ActionMessages.GLOBAL_MESSAGE,
389 								new ActionMessage(ie.getType(), label));
390 					}
391 				} else if (customField.isRequired()) {
392 					String label = CustomFieldUtilities.getCustomFieldName(
393 							customField.getId(), locale);
394 					errors.add(ActionMessages.GLOBAL_MESSAGE,
395 							new ActionMessage(IssueException.TYPE_CF_REQ_FIELD,
396 									label));
397 				}
398 			}
399 		}
400 	}
401 
402 	private static void validateProjectScripts(Project project, ActionErrors errors, IssueForm form)
403 			throws WorkflowException {
404 
405 		List<ProjectScript> scripts = project.getScripts();
406 		WorkflowUtilities.processFieldScripts(scripts,
407 				WorkflowUtilities.EVENT_FIELD_ONVALIDATE, null, errors, form);
408 	}
409 
410 }