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.actions.project;
20  
21  import org.apache.commons.beanutils.PropertyUtils;
22  import org.apache.log4j.Logger;
23  import org.apache.struts.action.*;
24  import org.itracker.ProjectException;
25  import org.itracker.WorkflowException;
26  import org.itracker.core.resources.ITrackerResources;
27  import org.itracker.model.*;
28  import org.itracker.model.Notification.Type;
29  import org.itracker.model.util.IssueUtilities;
30  import org.itracker.model.util.ProjectUtilities;
31  import org.itracker.model.util.UserUtilities;
32  import org.itracker.model.util.WorkflowUtilities;
33  import org.itracker.services.IssueService;
34  import org.itracker.services.NotificationService;
35  import org.itracker.services.ProjectService;
36  import org.itracker.web.actions.base.ItrackerBaseAction;
37  import org.itracker.web.forms.IssueForm;
38  import org.itracker.web.util.*;
39  
40  import javax.servlet.ServletException;
41  import javax.servlet.http.HttpServletRequest;
42  import javax.servlet.http.HttpServletResponse;
43  import javax.servlet.http.HttpSession;
44  import java.io.IOException;
45  import java.util.*;
46  
47  /**
48   * This action handles the actual creation of a new issue.
49   * <p/>
50   * FIXME: There are validation issues, the createissue-form becomes invalid, missing inputs, missing options.
51   *
52   * @author ranks
53   */
54  
55  //  TODO: Action Cleanup
56  
57  public class CreateIssueAction extends ItrackerBaseAction {
58      private static final Logger log = Logger.getLogger(CreateIssueAction.class);
59  
60  
61      public ActionForward execute(ActionMapping mapping, ActionForm form,
62                                   HttpServletRequest request, HttpServletResponse response)
63              throws ServletException, IOException {
64          ActionMessages errors = new ActionMessages();
65  
66          if (!isTokenValid(request)) {
67              log.info("execute: Invalid request token while creating issue.");
68              errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
69                      "itracker.web.error.transaction"));
70              saveErrors(request, errors);
71              log.info("execute: return to edit-issue");
72              saveToken(request);
73  
74  
75              EditIssueActionUtil.setupCreateIssue(request);
76              return mapping.findForward("createissue");
77  
78          }
79          resetToken(request);
80  
81          try {
82              IssueService issueService = ServletContextUtils.getItrackerServices().getIssueService();
83              NotificationService notificationService = ServletContextUtils.getItrackerServices()
84                      .getNotificationService();
85              ProjectService projectService = ServletContextUtils.getItrackerServices()
86                      .getProjectService();
87  
88              HttpSession session = request.getSession(true);
89              User currUser = (User) session.getAttribute(Constants.USER_KEY);
90              Map<Integer, Set<PermissionType>> userPermissionsMap = RequestHelper.getUserPermissions(session);
91              Locale locale = getLocale(request);
92              Integer currUserId = currUser.getId();
93  
94              IssueForm../../../org/itracker/web/forms/IssueForm.html#IssueForm">IssueForm issueForm = (IssueForm) form;
95  
96              Integer creator = currUserId;
97  
98              Project project = null;
99              Integer projectId = issueForm.getProjectId();
100 
101             if (projectId == null) {
102                 errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
103                         "itracker.web.error.invalidproject"));
104             } else {
105                 project = projectService.getProject(projectId);
106             }
107 
108             if (errors.isEmpty() && project == null) {
109                 errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
110                         "itracker.web.error.invalidproject"));
111             } else if (errors.isEmpty() && project.getStatus() != Status.ACTIVE) {
112                 errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
113                         "itracker.web.error.projectlocked"));
114             } else if (!UserUtilities.hasPermission(userPermissionsMap,
115                     projectId, PermissionType.ISSUE_CREATE)) {
116                 return mapping.findForward("unauthorized");
117             } else {
118                 issueForm.invokeProjectScripts(project, WorkflowUtilities.EVENT_FIELD_ONPRESUBMIT, errors);
119 
120                 Issue issue = new Issue();
121                 issue.setDescription(issueForm.getDescription());
122                 issue.setSeverity(issueForm.getSeverity());
123                 issue.setStatus(IssueUtilities.STATUS_NEW);
124                 issue.setResolution("");
125 
126                 IssueHistory issueHistory = new IssueHistory(issue, currUser,
127                         issueForm.getHistory(),
128                         IssueUtilities.HISTORY_STATUS_AVAILABLE);
129                 issueHistory.setCreateDate(new Date());
130                 issue.getHistory().add(issueHistory);
131 
132                 // creating issues as another user
133 
134                 if (UserUtilities.hasPermission(userPermissionsMap,
135                         projectId, PermissionType.ISSUE_CREATE_OTHERS)) {
136                     creator = null != issueForm.getCreatorId() ? issueForm.getCreatorId() : currUserId;
137                     if (log.isDebugEnabled()) {
138                         log.debug("New issue creator set to " + creator
139                                 + ". Issue created by " + currUserId);
140                     }
141                 }
142                 // create the issue in the database
143                 ActionMessages msg = AttachmentUtilities.validate(issueForm.getAttachment(), ServletContextUtils.getItrackerServices());
144 
145                 if (!msg.isEmpty()) {
146                     log.info("execute: tried to create issue with invalid attachemnt: " + msg);
147                     errors.add(msg);
148                     saveErrors(request, errors);
149                     EditIssueActionUtil.setupCreateIssue(request);
150                     return mapping.findForward("createissue");
151                 }
152 
153                 if (log.isDebugEnabled()) {
154                     log.debug("execute: creating new issue..");
155                 }
156 
157                 issue = issueService.createIssue(issue, projectId,
158                         creator, currUserId);
159 
160                 if (log.isDebugEnabled()) {
161                     log.debug("execute: issue created: " + issue);
162                 }
163 
164                 if (issue != null) {
165                     if (!ProjectUtilities.hasOption(
166                             ProjectUtilities.OPTION_NO_ATTACHMENTS, project
167                             .getOptions())) {
168                         msg = new ActionMessages();
169                         issue = issueForm.addAttachment(issue, project, currUser, ServletContextUtils.getItrackerServices(), msg);
170 
171                         if (!msg.isEmpty()) {
172                             errors.add(msg);
173                         }
174 
175                     }
176 
177 
178                     Integer newOwner = issueForm.getOwnerId();
179 
180                     if (newOwner != null && newOwner.intValue() >= 0) {
181                         if (UserUtilities.hasPermission(userPermissionsMap,
182                                 PermissionType.ISSUE_ASSIGN_OTHERS)
183                                 || (UserUtilities.hasPermission(
184                                 userPermissionsMap,
185                                 PermissionType.ISSUE_ASSIGN_SELF) && currUserId
186                                 .equals(newOwner))) {
187                             issueService.assignIssue(issue.getId(), newOwner,
188                                     currUserId);
189                         }
190                     }
191 
192                     // TODO this is absolutely complex, unreadable code. why do it, what does it do, can we keep it simple?
193                     // it seems to set issueCustomField (issueFields), you might be able to refactor this into its own method (hiding in a method ;) )
194                     List<IssueField> issueFields = new ArrayList<IssueField>();
195                     Map<String, String> customFields = issueForm.getCustomFields();
196 
197                     if (customFields != null && customFields.size() > 0) {
198                         List<IssueField> issueFieldsVector = new ArrayList<IssueField>();
199                         ResourceBundle bundle = ITrackerResources
200                                 .getBundle(locale);
201 
202                         for (Iterator<String> iter = customFields.keySet().iterator(); iter
203                                 .hasNext(); ) {
204                             try {
205                                 Integer fieldId = Integer.valueOf(iter.next());
206                                 CustomField field = IssueUtilities
207                                         .getCustomField(fieldId);
208                                 String fieldValue = (String) PropertyUtils
209                                         .getMappedProperty(form,
210                                                 "customFields(" + fieldId + ")");
211 
212                                 if (fieldValue != null
213                                         && fieldValue.trim().length() != 0) {
214                                     IssueField issueField = new IssueField(
215                                             issue, field);
216                                     issueField.setValue(fieldValue, bundle);
217                                     issueFieldsVector.add(issueField);
218                                 }
219                             } catch (Exception e) {
220                                 log.error("execute: failed to assign issue", e);
221                             }
222                         }
223                         issueFields = issueFieldsVector;
224                     }
225                     issueService.setIssueFields(issue.getId(), issueFields);
226 
227                     HashSet<Integer> components = new HashSet<>();
228                     Integer[] componentIds = issueForm.getComponents();
229 
230 
231                     if (componentIds != null) {
232                         Collections.addAll(components, componentIds);
233                         issueService.setIssueComponents(issue.getId(),
234                                 components, creator);
235                     }
236                     HashSet<Integer> versions = new HashSet<>();
237                     Integer[] versionIds = issueForm.getVersions();
238 
239                     if (versionIds != null) {
240                         Collections.addAll(versions, versionIds);
241                         issueService.setIssueVersions(issue.getId(), versions,
242                                 creator);
243                     }
244 
245                     try {
246                         Integer relatedIssueId = issueForm.getRelatedIssueId();
247                         IssueRelation.Type relationType = issueForm.getRelationType();
248 
249                         if (relatedIssueId != null
250                                 && relatedIssueId > 0
251                                 && relationType != null
252                                 && relationType.getCode() > 0) {
253                             Issue relatedIssue = issueService
254                                     .getIssue(relatedIssueId);
255 
256                             if (relatedIssue == null) {
257                                 log.debug("Unknown relation issue, relation not created.");
258                             } else if (relatedIssue.getProject() == null
259                                     || !IssueUtilities.canEditIssue(
260                                     relatedIssue, currUserId,
261                                     userPermissionsMap)) {
262                                 log.info("User not authorized to add issue relation from issue "
263                                                 + issue.getId()
264                                                 + " to issue "
265                                                 + relatedIssueId);
266                             } else if (IssueUtilities.hasIssueRelation(issue,
267                                     relatedIssueId)) {
268                                 log.debug("Issue " + issue.getId()
269                                         + " is already related to issue "
270                                         + relatedIssueId
271                                         + ", relation ot created.");
272                             } else {
273                                 if (!issueService.addIssueRelation(issue
274                                         .getId(), relatedIssueId, relationType,
275                                         currUser.getId())) {
276                                     log.info("Error adding issue relation from issue "
277                                                     + issue.getId()
278                                                     + " to issue "
279                                                     + relatedIssueId);
280                                 }
281                             }
282                         }
283                     } catch (RuntimeException e) {
284                         log
285                                 .warn(
286                                         "execute: Exception adding new issue relation.",
287                                         e);
288                         errors.add(ActionMessages.GLOBAL_MESSAGE,
289                                 new ActionMessage("itracker.web.error.system"));
290                         saveErrors(request, errors);
291                         EditIssueActionUtil.setupCreateIssue(request);
292                         return mapping.findForward("createissue");
293                     }
294 
295                     notificationService.sendNotification(issue, Type.CREATED,
296                             getBaseURL(request));
297                 } else {
298 
299                     errors.add(ActionMessages.GLOBAL_MESSAGE,
300                             new ActionMessage("itracker.web.error.system"));
301                     saveErrors(request, errors);
302                     return mapping.findForward("createissue");
303                 }
304                 session.removeAttribute(Constants.PROJECT_KEY);
305 
306                 issueForm.invokeProjectScripts(project, WorkflowUtilities.EVENT_FIELD_ONPOSTSUBMIT, errors);
307 
308                 if (errors.isEmpty()) {
309                     return getReturnForward(issue, project, issueForm, mapping);
310                 }
311                 saveErrors(request, errors);
312                 EditIssueActionUtil.setupCreateIssue(request);
313                 return mapping.findForward("createissue");
314 
315             }
316         } catch (RuntimeException e) {
317             log.error("Exception processing form data", e);
318             errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
319                     "itracker.web.error.system"));
320         } catch (WorkflowException e) {
321             log.error("Exception processing form data", e);
322             errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
323                     "itracker.web.error.system"));
324         } catch (ProjectException e) {
325             log.error("Exception processing form data", e);
326             errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
327                     "itracker.web.error.system"));
328         }
329 
330         if (!errors.isEmpty()) {
331             saveErrors(request, errors);
332         }
333         return mapping.findForward("createissue");
334     }
335 
336     private ActionForward getReturnForward(Issue issue, Project project,
337                                            IssueForm issueForm, ActionMapping mapping) {
338         log.info("getReturnForward: listissues");
339 
340         return new ActionForward(mapping.findForward("listissues")
341                 .getPath()
342                 + "?projectId=" + project.getId());
343     }
344 
345 }