001: package org.tigris.scarab.actions;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2003 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by CollabNet <http://www.collab.net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of CollabNet.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of CollabNet.
047: */
048:
049: import java.util.ArrayList;
050: import java.util.HashMap;
051: import java.util.HashSet;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.Map;
055: import java.util.Set;
056: import java.util.StringTokenizer;
057:
058: import org.apache.commons.collections.MapIterator;
059: import org.apache.commons.collections.map.LinkedMap;
060: import org.apache.fulcrum.intake.model.Field;
061: import org.apache.fulcrum.intake.model.Group;
062: import org.apache.fulcrum.parser.ParameterParser;
063: import org.apache.turbine.RunData;
064: import org.apache.turbine.TemplateContext;
065: import org.apache.turbine.tool.IntakeTool;
066: import org.tigris.scarab.actions.base.RequireLoginFirstAction;
067: import org.tigris.scarab.attribute.DateAttribute;
068: import org.tigris.scarab.attribute.OptionAttribute;
069: import org.tigris.scarab.attribute.UserAttribute;
070: import org.tigris.scarab.notification.NotificationManager;
071: import org.tigris.scarab.notification.NotificationManagerFactory;
072: import org.tigris.scarab.om.ActivitySet;
073: import org.tigris.scarab.notification.ActivityType;
074: import org.tigris.scarab.om.Attachment;
075: import org.tigris.scarab.om.AttachmentManager;
076: import org.tigris.scarab.om.Attribute;
077: import org.tigris.scarab.om.AttributeValue;
078: import org.tigris.scarab.om.Condition;
079: import org.tigris.scarab.om.Issue;
080: import org.tigris.scarab.om.IssueType;
081: import org.tigris.scarab.om.Module;
082: import org.tigris.scarab.om.RModuleAttribute;
083: import org.tigris.scarab.om.RModuleIssueType;
084: import org.tigris.scarab.om.ScarabUser;
085: import org.tigris.scarab.services.security.ScarabSecurity;
086: import org.tigris.scarab.tools.ScarabLocalizationTool;
087: import org.tigris.scarab.tools.ScarabRequestTool;
088: import org.tigris.scarab.tools.localization.L10NKeySet;
089: import org.tigris.scarab.tools.localization.L10NMessage;
090: import org.tigris.scarab.util.IteratorWithSize;
091: import org.tigris.scarab.util.Log;
092: import org.tigris.scarab.util.ScarabConstants;
093: import org.tigris.scarab.util.word.ComplexQueryException;
094: import org.tigris.scarab.util.word.IssueSearch;
095: import org.tigris.scarab.util.word.IssueSearchFactory;
096: import org.tigris.scarab.util.word.MaxConcurrentSearchException;
097: import org.tigris.scarab.util.word.QueryResult;
098:
099: /**
100: * This class is responsible for report issue forms.
101: *
102: * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
103: * @version $Id: ReportIssue.java 10378 2006-12-10 23:34:12Z dabbous $
104: */
105: public class ReportIssue extends RequireLoginFirstAction {
106: private static final int MAX_RESULTS = 25;
107:
108: /**
109: * Calls do check for duplicates by default.
110: */
111: public void doPerform(RunData data, TemplateContext context)
112: throws Exception {
113: doCheckforduplicates(data, context);
114: }
115:
116: private boolean checkIssueTypeStatus(RunData data,
117: TemplateContext context) throws Exception {
118: ScarabRequestTool scarabR = getScarabRequestTool(context);
119: Issue issue = scarabR.getReportingIssue();
120: Module module = issue.getModule();
121: IssueType issueType = issue.getIssueType();
122: boolean isValid = module != null && !module.getDeleted()
123: && issueType != null;
124: if (isValid) {
125: RModuleIssueType rmit = module
126: .getRModuleIssueType(issueType);
127: isValid = rmit != null && rmit.getActive();
128: }
129:
130: if (!isValid) {
131: scarabR.setAlertMessage(L10NKeySet.IssueTypeUnavailable);
132: data.setTarget(((ScarabUser) data.getUser()).getHomePage());
133: cleanup(data, context);
134: }
135: return isValid;
136: }
137:
138: public void doCheckforduplicates(RunData data,
139: TemplateContext context) throws Exception {
140: if (checkIssueTypeStatus(data, context)) {
141: checkForDuplicates(data, context);
142: }
143: }
144:
145: public void checkForDuplicates(RunData data, TemplateContext context)
146: throws Exception {
147: ScarabLocalizationTool l10n = getLocalizationTool(context);
148: IntakeTool intake = getIntakeTool(context);
149: ScarabRequestTool scarabR = getScarabRequestTool(context);
150: try {
151: Issue issue = scarabR.getReportingIssue();
152: LinkedMap avMap = issue.getModuleAttributeValuesMap();
153:
154: // set the values entered so far and if that is successful look
155: // for duplicates
156: if (setAttributeValues(issue, intake, context, avMap)) {
157: // check for duplicates, if there are none skip the dedupe page
158: searchAndSetTemplate(data, context, 0, MAX_RESULTS,
159: issue, "entry,Wizard3.vm");
160: }
161: } catch (Exception e) {
162: L10NMessage l10nMessage = new L10NMessage(
163: L10NKeySet.ErrorExceptionMessage, e);
164: scarabR.setAlertMessage(l10nMessage);
165: Log.get().error("Error while checking for duplicates", e);
166: setTarget(data, "entry,Wizard1.vm");
167: return;
168: }
169:
170: // we know we started at Wizard1 if we are here, Wizard3 needs
171: // to know where the issue entry process starts because it may
172: // branch back
173: data.getParameters().add(ScarabConstants.HISTORY_SCREEN,
174: "entry,Wizard1.vm");
175: }
176:
177: /**
178: * Common code related to deduping. A search for duplicate issues is
179: * performed and if the number of possible duplicates is greater than
180: * the threshold, the results are placed in the ScarabRequestTool and
181: * the screen is set to entry,Wizard2.vm so that they can be viewed.
182: *
183: * @param data a <code>RunData</code> value
184: * @param context a <code>TemplateContext</code> value
185: * @param threshold an <code>int</code> number of issues that determines
186: * whether "entry,Wizard2.vm" screen or the screen given by
187: * nextTemplate is shown
188: * @param maxResults a <code>int</code> number of issues that are returned
189: * as potential duplicates
190: * @param nextTemplate a <code>String</code> screen name to branch to
191: * if the number of duplicate issues is less than or equal to the threshold
192: * @return true if the number of possible duplicates is greater than the
193: * threshold
194: * @exception Exception if an error occurs
195: */
196: private boolean searchAndSetTemplate(RunData data,
197: TemplateContext context, int threshold, int maxResults,
198: Issue issue, String nextTemplate) throws Exception {
199: // if all of the attributes are unset, then we don't need to run
200: // this query...just break out of it early...
201: List attributeValues = issue.getAttributeValues();
202: boolean hasSetValues = false;
203: for (Iterator itr = attributeValues.iterator(); itr.hasNext()
204: && !hasSetValues;) {
205: AttributeValue attVal = (AttributeValue) itr.next();
206: hasSetValues = attVal.isSet();
207: }
208: if (!hasSetValues) {
209: setTarget(data, nextTemplate);
210: return true;
211: }
212:
213: // search on the option attributes and keywords
214: IssueSearch search = null;
215: String template = null;
216: boolean dupThresholdExceeded = false;
217: try {
218: search = IssueSearchFactory.INSTANCE.getInstance(issue,
219: (ScarabUser) data.getUser());
220: // remove special characters from the text attributes
221: for (Iterator textAVs = search.getTextAttributeValues()
222: .iterator(); textAVs.hasNext();) {
223: AttributeValue av = (AttributeValue) textAVs.next();
224: if (av.getAttribute().getAttributeType().getName()
225: .equals("date"))
226: av.setValue(DateAttribute.internalDateFormat(av
227: .getValue(), getLocalizationTool(context)
228: .get(L10NKeySet.ShortDatePattern)));
229: String s = av.getValue();
230: if (s != null && s.length() > 0) {
231: StringTokenizer tokens = new StringTokenizer(s,
232: ScarabConstants.INVALID_SEARCH_CHARACTERS);
233: StringBuffer query = new StringBuffer(
234: s.length() + 10);
235: while (tokens.hasMoreTokens()) {
236: query.append(' ');
237: query.append(tokens.nextToken());
238: }
239: av.setValue(query.toString().toLowerCase());
240: }
241: }
242:
243: // set the template to dedupe unless none exist, then skip
244: // to final entry screen
245: IteratorWithSize queryResults = search.getQueryResults();
246: dupThresholdExceeded = (queryResults.size() > threshold);
247: if (dupThresholdExceeded) {
248: List matchingIssueIds = new ArrayList(maxResults);
249: // limit the number of matching issues to maxResults
250: for (int i = 0; queryResults.hasNext()
251: && i <= maxResults; i++) {
252: matchingIssueIds.add(((QueryResult) queryResults
253: .next()).getUniqueId());
254: }
255: context.put("issueList", matchingIssueIds);
256: template = "entry,Wizard2.vm";
257: } else {
258: template = nextTemplate;
259: }
260: } catch (MaxConcurrentSearchException e) {
261: getScarabRequestTool(context).setInfoMessage(
262: L10NKeySet.DupeCheckSkippedForLackOfResources);
263: } catch (ComplexQueryException e) {
264: getScarabRequestTool(context).setInfoMessage(
265: L10NKeySet.DupeCheckSkippedBecauseComplexity);
266: } finally {
267: if (search != null) {
268: search.close();
269: IssueSearchFactory.INSTANCE.notifyDone();
270: }
271: }
272:
273: setTarget(data, template);
274: return dupThresholdExceeded;
275: }
276:
277: /**
278: * Checks the Module the issue is being entered into to see what
279: * attributes are required to have values. If a required field was present
280: * and the user did not enter anything, intake is notified that the
281: * field was required.
282: *
283: * @param issue an <code>Issue</code> value
284: * @param intake an <code>IntakeTool</code> value
285: * @exception Exception if an error occurs
286: */
287: private void setRequiredFlags(Issue issue, IntakeTool intake,
288: LinkedMap avMap, TemplateContext context) throws Exception {
289: if (issue == null) {
290: ScarabLocalizationTool l10n = getLocalizationTool(context);
291: throw new Exception(l10n.get("IssueNoLongerValid")); //EXCEPTION
292: }
293: Set selectedOptions = new HashSet();
294: Map conditionallyRequiredFields = new HashMap();
295: IssueType issueType = issue.getIssueType();
296: List requiredAttributes = issueType.getRequiredAttributes(issue
297: .getModule());
298: for (MapIterator iter = avMap.mapIterator(); iter.hasNext();) {
299: AttributeValue aval = (AttributeValue) avMap.get(iter
300: .next());
301:
302: Group group = intake.get("AttributeValue", aval
303: .getQueryKey(), false);
304: if (group != null) {
305: Field field = null;
306: if (aval instanceof OptionAttribute) {
307: field = group.get("OptionId");
308: // Will store the selected optionId, for later query.
309: Object fieldValue = field.getValue();
310: if (null != fieldValue) {
311: selectedOptions.add(fieldValue);
312: }
313: } else if (aval instanceof UserAttribute) {
314: field = group.get("UserId");
315: } else {
316: field = group.get("Value");
317: }
318:
319: /**
320: * If the field has any conditional constraint, will be added to the collection
321: * in the hash.
322: */
323: List conditions = aval.getRModuleAttribute()
324: .getConditions();
325: if (conditions.size() > 0) {
326: for (Iterator it = conditions.iterator(); it
327: .hasNext();) {
328: Condition cond = (Condition) it.next();
329: Integer id = cond.getOptionId();
330: List fields = (List) conditionallyRequiredFields
331: .get(id);
332: if (fields == null) {
333: fields = new ArrayList();
334: }
335: fields.add(field);
336: conditionallyRequiredFields.put(id, fields);
337: }
338: }
339:
340: for (int j = requiredAttributes.size() - 1; j >= 0; j--) {
341: if (aval.getAttribute().getPrimaryKey().equals(
342: ((Attribute) requiredAttributes.get(j))
343: .getPrimaryKey())
344: && !aval.isSet()) {
345: field.setRequired(true);
346: break;
347: }
348: }
349: }
350: }
351: /**
352: * Now that we have all the info, we will force the 'required' status of any field
353: * whose requiredOptionId has been set in the issue.
354: */
355: for (Iterator requiredIds = conditionallyRequiredFields
356: .keySet().iterator(); requiredIds.hasNext();) {
357: Integer attributeId = (Integer) requiredIds.next();
358: if (selectedOptions.contains(attributeId)) {
359: List fields = (List) conditionallyRequiredFields
360: .get(attributeId);
361: for (Iterator iter = fields.iterator(); iter.hasNext();) {
362: Field field = (Field) iter.next();
363: if (field.getValue().toString().length() == 0) {
364: field.setRequired(true);
365: field
366: .setMessage("ConditionallyRequiredAttribute");
367: }
368: }
369: }
370: }
371: }
372:
373: /**
374: * Add/Modify any attribute values that were just entered into intake.
375: *
376: * @param issue the <code>Issue</code> currently being editted
377: * @param intake an <code>IntakeTool</code> containing the fields for the
378: * issue's attribute values.
379: * @exception Exception pass thru
380: */
381: private boolean setAttributeValues(Issue issue, IntakeTool intake,
382: TemplateContext context, LinkedMap avMap) throws Exception {
383: boolean success = false;
384: // set any required flags on attribute values
385: setRequiredFlags(issue, intake, avMap, context);
386: if (intake.isAllValid()) {
387: for (MapIterator i = avMap.mapIterator(); i.hasNext();) {
388: AttributeValue aval = (AttributeValue) avMap.get(i
389: .next());
390: Group group = intake.get("AttributeValue", aval
391: .getQueryKey(), false);
392: if (group != null) {
393: Field field = group
394: .get(aval instanceof OptionAttribute ? "OptionId"
395: : "Value");
396: String value = field.toString();
397:
398: if (value != null && value.length() > 0) {
399: group.setProperties(aval);
400: }
401: }
402: }
403: success = true;
404: } else {
405: getScarabRequestTool(context)
406: .setAlertMessage(ERROR_MESSAGE);
407: }
408: return success;
409: }
410:
411: /**
412: * handles entering an issue
413: */
414: public void doEnterissue(RunData data, TemplateContext context)
415: throws Exception {
416: if (checkIssueTypeStatus(data, context)) {
417: enterIssue(data, context);
418: }
419: }
420:
421: /**
422: * handles entering an issue
423: */
424: private void enterIssue(RunData data, TemplateContext context)
425: throws Exception {
426: IntakeTool intake = getIntakeTool(context);
427: ScarabRequestTool scarabR = getScarabRequestTool(context);
428: ScarabLocalizationTool l10n = getLocalizationTool(context);
429: Issue issue = scarabR.getReportingIssue();
430: ScarabUser user = (ScarabUser) data.getUser();
431: LinkedMap avMap = issue.getModuleAttributeValuesMap();
432:
433: // set the attribute values and if that was successful save the issue.
434: if (setAttributeValues(issue, intake, context, avMap)) {
435: DateAttribute.convertDateAttributes(issue
436: .getAttributeValues(), getLocalizationTool(context)
437: .get("ShortDatePattern"));
438: if (issue.containsMinimumAttributeValues()) {
439: // we need to see that the default text was filled out
440: // if necessary. We can
441: // only do this after setting the attributes above.
442: boolean saveIssue = true;
443: Group reasonGroup = intake.get("Attachment", "_1",
444: false);
445: Field reasonField = reasonGroup.get("Data");
446: if (issue.getDefaultTextAttributeValue() == null) {
447: reasonField.setRequired(true);
448: saveIssue = false;
449: }
450:
451: // if the reason field is to long, then show an error.
452: String reasonString = reasonField.toString();
453: if (reasonString != null && reasonString.length() > 254) {
454: reasonField
455: .setMessage("intake_ReasonMustBeLessThan256Characters");
456: saveIssue = false;
457: }
458: // If there is a default text attribute,or if a comment has
459: // Been provided, proceed.
460: if (reasonField.isValid() || saveIssue) {
461: HashMap newValues = new HashMap();
462: List modAttrs = issue.getModule()
463: .getRModuleAttributes(issue.getIssueType(),
464: true, "all");
465:
466: // this is used for the workflow stuff...FIXME: it should
467: // be refactored as soon as we possibly can. the reason is
468: // that all of this data can be retrieved by simply using
469: // issue.getModuleAttributeValuesMap() because the call
470: // to setAttributeValues() above already gets the group
471: // information into the module attribute values.
472: for (int i = 0; i < modAttrs.size(); i++) {
473: Attribute attr = ((RModuleAttribute) modAttrs
474: .get(i)).getAttribute();
475: String queryKey = "__"
476: + attr.getAttributeId().toString();
477: Group group = intake.get("AttributeValue",
478: queryKey, false);
479: String newValue = "";
480:
481: if (group != null) {
482: if (attr.isOptionAttribute()) {
483: newValue = group.get("OptionId")
484: .toString();
485: } else {
486: newValue = group.get("Value")
487: .toString();
488: }
489: if (newValue.length() != 0) {
490: newValues.put(attr.getAttributeId(),
491: newValue);
492: }
493: }
494: }
495:
496: // Save the Reason
497: ActivitySet activitySet = null;
498: Attachment reason = null;
499: try {
500: // grab the comment data
501: reason = new Attachment();
502: reasonField.setProperty(reason);
503: activitySet = issue.setInitialAttributeValues(
504: activitySet, reason, newValues, user);
505: } catch (Exception se) {
506: scarabR.setAlertMessage(l10n.getMessage(se));
507: return;
508: }
509:
510: // Save any unsaved attachments as part of this ActivitySet as well
511: activitySet = issue.doSaveFileAttachments(
512: activitySet, user);
513:
514: // set the template to the user selected value
515: int templateCode = data.getParameters().getInt(
516: "template_code", 2);
517:
518: // if user preference for next template is unset,
519: // set it.
520: int userPref = user.getEnterIssueRedirect();
521: if (userPref == 0 || userPref != templateCode) {
522: user.setEnterIssueRedirect(templateCode);
523: }
524: doRedirect(data, context, templateCode, issue);
525:
526: NotificationManagerFactory.getInstance()
527: .addActivityNotification(
528: ActivityType.ISSUE_CREATED,
529: activitySet, issue, user);
530:
531: cleanup(data, context);
532: data.getParameters().add("id",
533: issue.getUniqueId().toString());
534: L10NMessage l10nMessage = new L10NMessage(
535: L10NKeySet.IssueAddedToModule, issue
536: .getUniqueId(),
537: getScarabRequestTool(context)
538: .getCurrentModule().getRealName());
539: scarabR.setConfirmMessage(l10nMessage);
540: } else {
541: scarabR.setAlertMessage(ERROR_MESSAGE);
542: }
543: } else {
544: // this would be an application or hacking error
545: }
546: }
547: }
548:
549: /**
550: * Add attachment file
551: */
552: public void doAddfile(RunData data, TemplateContext context)
553: throws Exception {
554: IntakeTool intake = getIntakeTool(context);
555: ScarabRequestTool scarabR = getScarabRequestTool(context);
556: Issue issue = scarabR.getReportingIssue();
557: Attachment attachment = AttachmentManager.getInstance();
558: Group group = intake.get("Attachment",
559: attachment.getQueryKey(), false);
560:
561: ModifyIssue.addFileAttachment(issue, group, attachment,
562: scarabR, data, intake);
563: ScarabLocalizationTool l10n = getLocalizationTool(context);
564: if (scarabR.getAlertMessage() == null) {
565: scarabR.setConfirmMessage(L10NKeySet.FileAdded);
566: }
567:
568: LinkedMap avMap = issue.getModuleAttributeValuesMap();
569: // set any attribute values that were entered before adding the file.
570: setAttributeValues(issue, intake, context, avMap);
571: doGotowizard3(data, context);
572: }
573:
574: /**
575: * Remove an attachment file
576: */
577: public void doRemovefile(RunData data, TemplateContext context)
578: throws Exception {
579: ScarabRequestTool scarabR = getScarabRequestTool(context);
580: ScarabLocalizationTool l10n = getLocalizationTool(context);
581: Issue issue = scarabR.getReportingIssue();
582: ParameterParser params = data.getParameters();
583: Object[] keys = params.getKeys();
584: String key;
585: String attachmentIndex;
586: boolean fileDeleted = false;
587: for (int i = 0; i < keys.length; i++) {
588: key = keys[i].toString();
589: if (key.startsWith("file_delete_")) {
590: attachmentIndex = key.substring(12);
591: issue.removeFile(attachmentIndex);
592: fileDeleted = true;
593: }
594: }
595: if (fileDeleted) {
596: scarabR.setConfirmMessage(L10NKeySet.FileDeleted);
597: } else {
598: scarabR.setConfirmMessage(L10NKeySet.NoFilesChanged);
599: }
600: LinkedMap avMap = issue.getModuleAttributeValuesMap();
601: // set any attribute values that were entered before adding the file.
602: setAttributeValues(issue, getIntakeTool(context), context,
603: avMap);
604: doGotowizard3(data, context);
605: }
606:
607: /**
608: * Handles adding a comment to one or more issues. This is an option
609: * which is available on Wizard2 during the dedupe process.
610: */
611: public void doAddcomment(RunData data, TemplateContext context)
612: throws Exception {
613: ScarabLocalizationTool l10n = getLocalizationTool(context);
614: IntakeTool intake = getIntakeTool(context);
615: ScarabRequestTool scarabR = getScarabRequestTool(context);
616: Issue issue = scarabR.getReportingIssue();
617: if (intake.isAllValid()) {
618: Attachment attachment = new Attachment();
619: Group group = intake.get("Attachment", attachment
620: .getQueryKey(), false);
621: if (group != null) {
622: List issues = scarabR.getIssues();
623: if (issues == null || issues.size() == 0) {
624: scarabR
625: .setAlertMessage(L10NKeySet.NoIssuesSelectedToAddComment);
626: searchAndSetTemplate(data, context, 0, MAX_RESULTS,
627: issue, "entry,Wizard2.vm");
628: return;
629: }
630: ActivitySet activitySet = null;
631: for (Iterator itr = issues.iterator(); itr.hasNext();) {
632: Issue prevIssue = (Issue) itr.next();
633: // save the attachment
634: attachment = new Attachment();
635: group.setProperties(attachment);
636: if (attachment.getData() != null
637: && attachment.getData().trim().length() > 0) {
638: ScarabUser user = (ScarabUser) data.getUser();
639: activitySet = prevIssue.addComment(activitySet,
640: attachment, user);
641: NotificationManagerFactory.getInstance()
642: .addActivityNotification(
643: ActivityType.COMMENT_ADDED,
644: activitySet, issue, null, null,
645: user);
646: scarabR
647: .setConfirmMessage(L10NKeySet.CommentAdded);
648: } else {
649: scarabR
650: .setAlertMessage(L10NKeySet.NoTextInCommentTextArea);
651: searchAndSetTemplate(data, context, 0,
652: MAX_RESULTS, issue, "entry,Wizard2.vm");
653: return;
654: }
655: }
656: }
657:
658: // if there was only one duplicate issue and we just added
659: // a comment to it, assume user is done
660: String nextTemplate = ((ScarabUser) data.getUser())
661: .getHomePage();
662: if (!searchAndSetTemplate(data, context, 1, MAX_RESULTS,
663: issue, nextTemplate)) {
664: cleanup(data, context);
665: } else {
666: intake.remove(group);
667: }
668: return;
669: } else {
670: // Comment was probably too long. Repopulate the issue list, so
671: // the page can be shown again, and the user can fix the comment.
672: searchAndSetTemplate(data, context, 0, MAX_RESULTS, issue,
673: "entry,Wizard2.vm");
674: }
675: }
676:
677: /**
678: * The button for this action is commented out on Wizard2, so it
679: * will not be called
680: public void doAddvote(RunData data, TemplateContext context)
681: throws Exception
682: {
683: IntakeTool intake = getIntakeTool(context);
684: ScarabLocalizationTool l10n = getLocalizationTool(context);
685: if (intake.isAllValid())
686: {
687: ScarabRequestTool scarabR = getScarabRequestTool(context);
688: Issue issue = scarabR.getReportingIssue();
689:
690: try
691: {
692: issue.addVote((ScarabUser)data.getUser());
693: scarabR.setConfirmMessage(
694: l10n.format("VoteForIssueAccepted", issue.getUniqueId()));
695: // if there was only one duplicate issue and the user just
696: // voted for it, assume user is done
697: String nextTemplate =
698: ((ScarabUser)data.getUser()).getHomePage();
699: if (! searchAndSetTemplate(data, context, 1, nextTemplate))
700: {
701: cleanup(data, context);
702: }
703: }
704: catch (ScarabException e)
705: {
706: scarabR.setAlertMessage(
707: l10n.format("VoteFailedException", e.getMessage()));
708: // User attempted to vote when they were not allowed. This
709: // should probably not be allowed in the ui, but right now
710: // it is and we should protect against url hacking anyway.
711: // Repopulate the data so the dedupe page can be shown again.
712: searchAndSetTemplate(data, context, 0, "entry,Wizard2.vm");
713: }
714: }
715: else
716: {
717: // Not sure this case needs to be covered, but just to be safe
718: // repopulate the data so the dedupe page can be shown again.
719: searchAndSetTemplate(data, context, 0, "entry,Wizard2.vm");
720: }
721: }
722: */
723:
724: public void doGotowizard3(RunData data, TemplateContext context)
725: throws Exception {
726: setTarget(data, "entry,Wizard3.vm");
727: }
728:
729: public void doUsetemplates(RunData data, TemplateContext context)
730: throws Exception {
731: getIntakeTool(context).removeAll();
732: String templateId = data.getParameters().getString(
733: "select_template_id");
734: if (templateId != null && templateId.length() > 0) {
735: data.getParameters().add("templateId", templateId);
736: }
737: }
738:
739: private void cleanup(RunData data, TemplateContext context) {
740: data.getParameters().remove(ScarabConstants.HISTORY_SCREEN);
741: String issueKey = data.getParameters().getString(
742: ScarabConstants.REPORTING_ISSUE);
743: ((ScarabUser) data.getUser()).setReportingIssue(issueKey, null);
744: data.getParameters().remove(ScarabConstants.REPORTING_ISSUE);
745: getScarabRequestTool(context).setReportingIssue(null);
746: IntakeTool intake = getIntakeTool(context);
747: intake.removeAll();
748: }
749:
750: /**
751: * User selects page to redirect to after entering issue.
752: */
753: private void doRedirect(RunData data, TemplateContext context,
754: int templateCode, Issue issue) throws Exception {
755: ScarabUser user = (ScarabUser) data.getUser();
756: ScarabRequestTool scarabR = getScarabRequestTool(context);
757: ScarabLocalizationTool l10n = getLocalizationTool(context);
758: String template = null;
759: switch (templateCode) {
760: case 1:
761: if (user.hasPermission(ScarabSecurity.ISSUE__ENTER, user
762: .getCurrentModule())) {
763: IssueType issueType = issue.getIssueType();
764: template = scarabR.getNextEntryTemplate(issueType);
765: data.getParameters().setString(
766: ScarabConstants.CURRENT_ISSUE_TYPE,
767: issueType.getQueryKey());
768: } else {
769: template = user.getHomePage();
770: scarabR
771: .setAlertMessage(L10NKeySet.InsufficientPermissionsToEnterIssues);
772: }
773: break;
774: case 2:
775: if (user.hasPermission(ScarabSecurity.ISSUE__ASSIGN, user
776: .getCurrentModule())) {
777: template = "AssignIssue.vm";
778: data.getParameters()
779: .setString(ScarabConstants.CANCEL_TEMPLATE,
780: "ViewIssue.vm");
781: data.getParameters().add("issue_ids",
782: issue.getUniqueId());
783: // data.getParameters()
784: // .setString("id", issue.getUniqueId().toString());
785: getIntakeTool(context).removeAll();
786: scarabR.resetAssociatedUsers();
787: } else {
788: template = user.getHomePage();
789: scarabR
790: .setAlertMessage(L10NKeySet.InsufficientPermissionsToAssignIssues);
791: }
792: break;
793: case 3:
794: if (user.hasPermission(ScarabSecurity.ISSUE__VIEW, user
795: .getCurrentModule())) {
796: template = "ViewIssue.vm";
797: data.getParameters().setString("id",
798: issue.getUniqueId().toString());
799: } else {
800: template = user.getHomePage();
801: scarabR
802: .setAlertMessage(L10NKeySet.InsufficientPermissionsToViewIssues);
803: }
804: break;
805: case 4:
806: template = user.getHomePage();
807: break;
808: case 5:
809: if (user.hasPermission(ScarabSecurity.ISSUE__VIEW, user
810: .getCurrentModule())) {
811: template = "ViewIssue.vm";
812: data.getParameters().setString("id",
813: issue.getUniqueId().toString());
814: data.getParameters().setString("tab", "3"); // comment tab == 3
815: data.getUser().setTemp(ScarabConstants.TAB_KEY, "3");
816: } else {
817: template = user.getHomePage();
818: scarabR
819: .setAlertMessage(L10NKeySet.InsufficientPermissionsToViewIssues);
820: }
821: break;
822: }
823: setTarget(data, template);
824: }
825:
826: public void doStart(RunData data, TemplateContext context)
827: throws Exception {
828: cleanOutStaleIssue(data, context);
829: }
830:
831: /**
832: * for easy access by TemplateList action
833: */
834: static void cleanOutStaleIssue(RunData data, TemplateContext context)
835: throws Exception {
836: String key = data.getParameters().getString(
837: ScarabConstants.REPORTING_ISSUE);
838: ScarabUser user = (ScarabUser) data.getUser();
839: if (key != null) {
840: data.getParameters()
841: .remove(ScarabConstants.REPORTING_ISSUE);
842: user.setReportingIssue(key, null);
843: }
844: user.setHomePage("home,EnterNew.vm");
845: }
846: }
|