BrightSide Workbench Full Report + Source Code
CreateIssueCtrl.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2015 Lluis TurrĂ³ Cutiller <http://www.turro.org/>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 package org.turro.dossier.www;
20 
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.Date;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27 import javax.servlet.ServletContext;
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30 import org.turro.string.Strings;
31 import org.apache.commons.fileupload.FileItemIterator;
32 import org.apache.commons.fileupload.FileItemStream;
33 import org.apache.commons.fileupload.FileUploadException;
34 import org.apache.commons.fileupload.servlet.ServletFileUpload;
35 import org.apache.commons.fileupload.util.Streams;
36 import org.apache.commons.lang3.math.NumberUtils;
37 import org.turro.attach.db.AttachPU;
38 import org.turro.attach.entity.AttachContent;
39 import org.turro.attach.entity.Attachment;
40 import org.turro.auth.Authentication;
41 import org.turro.contacts.Contact;
42 import org.turro.describeit.DescribeItUtil;
43 import org.turro.dossier.db.DossierPU;
44 import org.turro.dossier.dossier.ProjectContext;
45 import org.turro.dossier.dw.DossierDWReport;
46 import org.turro.dossier.entity.Dossier;
47 import org.turro.dossier.entity.Issue;
48 import org.turro.dossier.entity.IssueComment;
49 import org.turro.dossier.entity.IssueParticipant;
50 import org.turro.dossier.entity.IssuePriority;
51 import org.turro.dossier.entity.IssueResolution;
52 import org.turro.dossier.entity.IssueType;
53 import org.turro.dossier.issue.IssueMail;
54 import org.turro.dossier.issue.IssueWrapper;
55 import org.turro.dossier.project.AbstractDossierNotification;
56 import org.turro.dossier.search.DossierResults;
57 import org.turro.elephant.context.Application;
58 import org.turro.elephant.context.ElephantContext;
59 import org.turro.elephant.context.IConstructor;
60 import org.turro.elephant.direct.DirectContent;
61 import org.turro.elephant.direct.DirectContents;
62 import org.turro.elephant.direct.IDirectContent;
63 import org.turro.html.HTMLEntities;
64 import org.turro.i18n.I_;
65 import org.turro.jpa.Dao;
66 import org.turro.log.SystemLogType;
67 import org.turro.log.SystemLogger;
68 import org.turro.marker.ElephantMarker;
69 import org.turro.plugin.contacts.IContact;
70 import org.turro.registry.ChangeCategory;
71 import org.turro.registry.Changes;
72 import org.turro.registry.EnumChange;
73 import org.turro.registry.StringChange;
74 import org.turro.registry.UniqueString;
75 
80 @DirectContent(identifier="issue-create")
81 public class CreateIssueCtrl implements IDirectContent {
82 
83  //TODO: process all parameters
84  public static String linkToCreateIssue(String link, String dossierId, String template) {
85  return "/user/newissue?dossierId=" + dossierId;
86  }
87 
88  public static String createIssue(String link, String dossierId, String template) {
90  if(constructor.isInRole("issue:edit")) {
91  ElephantMarker marker = new ElephantMarker(constructor);
92  marker.put("projectContext", new ProjectContext());
93  marker.put("action", DirectContents.createRelativeURL(getIdentifier()));
94  marker.put("redirect", link);
95  if(Long.valueOf(dossierId) > 0) {
96  marker.put("dossierId", dossierId);
98  dr.setReportValues(null, null, Long.valueOf(dossierId));
99  marker.put("dossierData", dr.getData());
100  } else {
101  marker.put("dossiers", new DossierResults().getDossierList());
102  }
103  return marker.parse("issue", Strings.isBlank(template) ? "create" : template);
104  }
105  return "";
106  }
107 
108  public static String getIdentifier() {
109  return CreateIssueCtrl.class.getAnnotation(DirectContent.class).identifier();
110  }
111 
112  @Override
113  public boolean itsMe(String id) {
114  return getIdentifier().equals(id);
115  }
116 
117  @Override
118  public boolean myTurn(HttpServletRequest request) {
119  return DirectContents.isYourTurn(request, getIdentifier());
120  }
121 
122  @Override
123  public void execute(ServletContext context, HttpServletRequest request, HttpServletResponse response) {
124  if(ServletFileUpload.isMultipartContent(request)) {
125  try {
126  processInformation(request, response);
127  } catch (FileUploadException | IOException ex) {
128  Logger.getLogger(CreateIssueCtrl.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
129  }
130  }
131  }
132 
133  private void processInformation(HttpServletRequest request, HttpServletResponse response) throws FileUploadException, IOException {
135  Dao dao = new DossierPU();
136  IContact contact = Authentication.getIContact();
137  Issue issue = null;
138  if(contact == null || !contact.isValid()) {
139  return;
140  }
141  Changes changes = new Changes();
142  ChangeCategory issueCat = new ChangeCategory(2, I_.get("Changes"));
143  ChangeCategory attachCat = new ChangeCategory(3, I_.get("Attachments"));
144  ChangeCategory commentCat = new ChangeCategory(5, I_.get("Comment"));
145  Long dossierId = null;
146  String redirect = null, comment = null, description = null, webDefault = null, grouping = null;
147  Double hours = 0.0d, expenses = 0.0d, price = 0.0d;
148  IssuePriority priority = null;
149  IssueType type = null;
150  Boolean cancelEmails = false, responsibleIsReporter = false;
151  ServletFileUpload upload = new ServletFileUpload();
152  upload.setHeaderEncoding(ElephantContext.getEncoding());
153  FileItemIterator iter = upload.getItemIterator(request);
154  while(iter.hasNext()) {
155  FileItemStream item = iter.next();
156  String name = item.getFieldName();
157  InputStream stream = item.openStream();
158  if(item.isFormField()) {
159  switch(name) {
160  case "dossierId":
161  dossierId = Long.valueOf(Streams.asString(stream));
162  if(dossierId > 0) {
163  Dossier dossier = dao.find(Dossier.class, dossierId);
164  issue = Issue.getDefaultIssue();
165  issue.setDossier(dossier);
166  issue.setModification(new Date());
167  }
168  break;
169  case "redirect":
170  redirect = Streams.asString(stream, ElephantContext.getEncoding());
171  break;
172  case "description":
173  description = Streams.asString(stream, ElephantContext.getEncoding());
174  if(!Strings.isBlank(description)) {
175  description = HTMLEntities.plainWhenPossible(description);
176  changes.addChange(new StringChange(issueCat, I_.get("Description"),
177  "", description));
178  issue.setDescription(description);
179  }
180  break;
181  case "comment":
182  comment = Streams.asString(stream, ElephantContext.getEncoding());
183  if(!Strings.isBlank(comment)) {
184  comment = HTMLEntities.plainWhenPossible(comment);
185  changes.addComment(commentCat, comment);
186  }
187  break;
188  case "priority":
189  String p = Streams.asString(stream, ElephantContext.getEncoding());
190  if("p1".equals(p)) {
191  priority = IssuePriority.PRIORITY_CANT_CONTINUE;
192  } else if("p2".equals(p)) {
193  priority = IssuePriority.PRIORITY_WORKAROUND_IMPRACTICAL;
194  } else if("p3".equals(p)) {
195  priority = IssuePriority.PRIORITY_HAS_WORKAROUND;
196  } else if("p4".equals(p)) {
197  priority = IssuePriority.PRIORITY_WRONG_BEHAVIOR;
198  } else if("p5".equals(p)) {
199  priority = IssuePriority.PRIORITY_CAUSE_UNEASE;
200  }
201  if(priority != null) {
202  changes.addChange(new EnumChange(issueCat, I_.get("Priority"),
203  IssuePriority.PRIORITY_HAS_WORKAROUND, priority));
204  issue.setPriority(priority);
205  }
206  break;
207  case "type":
208  String t = Streams.asString(stream, ElephantContext.getEncoding());
209  if("task".equals(t)) {
210  type = IssueType.TYPE_TASK;
211  } else if("defect".equals(t)) {
212  type = IssueType.TYPE_DEFECT;
213  } else if("enhancement".equals(t)) {
214  type = IssueType.TYPE_ENHANCEMENT;
215  } else if("prevention".equals(t)) {
216  type = IssueType.TYPE_PREVENTION;
217  } else if("feature".equals(t)) {
218  type = IssueType.TYPE_FEATURE;
219  } else if("document".equals(t)) {
220  type = IssueType.TYPE_DOCUMENT;
221  } else if("patch".equals(t)) {
222  type = IssueType.TYPE_PATCH;
223  } else if("question".equals(t)) {
224  type = IssueType.TYPE_QUESTION;
225  } else if("nonconformity".equals(t)) {
226  type = IssueType.TYPE_NONCONFORMITY;
227  } else if("bestpractice".equals(t)) {
228  type = IssueType.TYPE_BESTPRACTICE;
229  } else if("process".equals(t)) {
230  type = IssueType.TYPE_PROCESS;
231  } else if("proposition".equals(t)) {
232  type = IssueType.TYPE_PROPOSITION;
233  }
234  if(type != null) {
235  changes.addChange(new EnumChange(issueCat, I_.get("Type"),
236  IssueType.TYPE_TASK, type));
237  issue.setType(type);
238  }
239  break;
240  case "grouping":
241  grouping = Streams.asString(stream, ElephantContext.getEncoding());
242  if(!Strings.isBlank(grouping)) {
243  changes.addChange(new StringChange(issueCat, I_.get("Grouping"),
244  "", grouping));
245  issue.setGrouping(grouping);
246  }
247  break;
248  case "expenses":
249  expenses = NumberUtils.toDouble(Streams.asString(stream), 0);
250  break;
251  case "hours":
252  hours = NumberUtils.toDouble(Streams.asString(stream), 0);
253  break;
254  case "price":
255  price = NumberUtils.toDouble(Streams.asString(stream), 0);
256  break;
257  case "webDefault":
258  webDefault = Streams.asString(stream, ElephantContext.getEncoding());
259  break;
260  case "cancelEmails":
261  cancelEmails = Boolean.parseBoolean(Streams.asString(stream, ElephantContext.getEncoding()));
262  break;
263  case "responsibleIsReporter":
264  responsibleIsReporter = Boolean.parseBoolean(Streams.asString(stream, ElephantContext.getEncoding()));
265  break;
266  }
267  } else if(issue != null && !Strings.isBlank(issue.getDescription())) {
268  issue.setExpenses(expenses);
269  issue.setHours(hours);
270  issue.setPrice(price);
271  issue = checkSave(constructor, dao, changes, issue, issueCat, responsibleIsReporter);
272  Attachment attachment = new Attachment();
273  attachment.setModification(issue.getModification());
274  attachment.setPath("/issue/" + issue.getId());
275  attachment.setOwner(contact.getId());
276  attachment.setOnlyOwner(false);
277  attachment.setComment("");
278  attachment.setShowKey(null);
279  attachment.setPublishable(true);
280  AttachContent ac = new AttachContent();
281  ByteArrayOutputStream baos = new ByteArrayOutputStream();
282  Streams.copy(item.openStream(), baos, true);
283  ac.setFileContent(baos.toByteArray());
284  attachment.setAttachContent(ac);
285  attachment.setFileName(convertToFileName(item.getName()));
286  attachment.setFileContentType(item.getContentType());
287  attachment.setFileSize(ac.getFileContent().length);
288  attachment.setValidated(Application.getApplication().isInRole("attach:self-validate"));
289  if(attachment.getFileSize() > 0) {
290  attachment = new AttachPU().saveObject(attachment);
291  SystemLogger.getInstance().doLog(SystemLogType.LOG_INFO, attachment, "uploaded", null);
292  changes.addChange(new StringChange(attachCat, I_.get("Upload"), attachment.getFileName(), null, true));
293  }
294  }
295  }
296  changes.clearEquals();
297  if(changes.stringSize() > 0) {
298  if(issue != null && !Strings.isBlank(issue.getDescription())) {
299  IssueComment ic = new IssueComment();
300  ic.setIssue(issue);
301  ic.setModification(issue.getModification());
302  ic.setIContact(Authentication.getIContact());
303  ic.setComment(changes.getChangesString());
304  issue.getComments().add(ic);
305  issue = checkSave(constructor, dao, changes, issue, issueCat, responsibleIsReporter);
306  SystemLogger.getInstance().doLog(SystemLogType.LOG_INFO, issue, "saved",
307  issue.getId() + " - " + issue.getDescription());
308  if(!cancelEmails) {
309  AbstractDossierNotification notif = AbstractDossierNotification.getByGrouping(issue);
310  if(notif == null) {
311  new IssueMail(changes, issue, 0, 0, 0).sendMail();
312  } else {
313  notif.sendNotification();
314  }
315  }
316  if(!Strings.isBlank(webDefault)) {
317  DescribeItUtil.addDescription(issue, DescribeItUtil.DEFAULT_ID, webDefault, (Contact) contact.getContact(), null);
318  }
319  }
320  }
321  if(!Strings.isBlank(redirect)) {
322  constructor.redirect(redirect.replaceAll("\\#ID", issue.getId() + ""));
323  }
324  }
325 
326  private String convertToFileName(String fileName) {
327  if(fileName.contains("/")) {
328  fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
329  }
330  return fileName;
331  }
332 
333  private Issue checkSave(IConstructor constructor, Dao dao, Changes changes, Issue issue, ChangeCategory issueCat,
334  Boolean responsibleIsReporter) {
335  if(issue.getId() == null) {
336  changes.addChange(new StringChange(issueCat, I_.get("Dossier"),
337  "", issue.getDossier() != null ? issue.getDossier().getDescription() : ""));
338  ChangeCategory cc = new ChangeCategory(4, I_.get("Participants"));
339  IContact responsible = issue.getDossier().getDefaultResponsible();
340  IContact reporter = Authentication.getIContact();
341  if(responsible == null || !responsible.isWebUser()) {
342  responsible = reporter;
343  }
344  IssueParticipant ip = issue.addReporter(responsibleIsReporter ? responsible : reporter);
345  changes.addChange(new UniqueString(cc, I_.byKey(ip.getRole().toString()), ip.getName(), true));
346  ip = issue.addResponsible(responsible);
347  changes.addChange(new UniqueString(cc, I_.byKey(ip.getRole().toString()), ip.getName(), true));
348  issue.setResolution(IssueResolution.RESOLUTION_NONE);
349  if(Strings.isBlank(issue.getDescription())) {
350  issue.setDescription("********");
351  }
352  }
353  IssueWrapper iw = new IssueWrapper(issue);
354  iw.clearEmpties();
355  issue = dao.saveObject(issue);
356  return issue;
357  }
358 
359 }
void setType(IssueType type)
Definition: Issue.java:295
void setDescription(String description)
Definition: Issue.java:154
static Issue getDefaultIssue()
Definition: Issue.java:503
void setModification(Date modification)
Definition: Issue.java:202
void setDossier(Dossier dossier)
Definition: Issue.java:162
void setPriority(IssuePriority priority)
Definition: Issue.java:210
Set< IssueComment > getComments()
Definition: Issue.java:122
void setHours(double hours)
Definition: Issue.java:311
void setGrouping(String grouping)
Definition: Issue.java:263
void setPrice(double price)
Definition: Issue.java:319
void setExpenses(double expenses)
Definition: Issue.java:303
boolean myTurn(HttpServletRequest request)
static String createIssue(String link, String dossierId, String template)
void execute(ServletContext context, HttpServletRequest request, HttpServletResponse response)
static String linkToCreateIssue(String link, String dossierId, String template)
static boolean isYourTurn(HttpServletRequest request, String path)
static String createRelativeURL(String id)
String parse(String rootTmpl, String tmpl)
Object put(Object key, Object value)