1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.itracker.model.util;
20
21 import org.apache.commons.lang.StringUtils;
22 import org.apache.log4j.Logger;
23 import org.itracker.core.resources.ITrackerResources;
24 import org.itracker.model.*;
25
26 import java.net.MalformedURLException;
27 import java.net.URL;
28 import java.text.SimpleDateFormat;
29 import java.util.*;
30
31
32
33
34 public class IssueUtilities {
35
36 private static final Logger log = Logger.getLogger(IssueUtilities.class);
37 public static final int FIELD_TYPE_SINGLE = 1;
38 public static final int FIELD_TYPE_INDEXED = 2;
39 public static final int FIELD_TYPE_MAP = 3;
40
41 public static final int FIELD_ID = -1;
42 public static final int FIELD_DESCRIPTION = -2;
43 public static final int FIELD_STATUS = -3;
44 public static final int FIELD_RESOLUTION = -4;
45 public static final int FIELD_SEVERITY = -5;
46 public static final int FIELD_CREATOR = -6;
47 public static final int FIELD_CREATEDATE = -7;
48 public static final int FIELD_OWNER = -8;
49 public static final int FIELD_LASTMODIFIED = -9;
50 public static final int FIELD_PROJECT = -10;
51 public static final int FIELD_TARGET_VERSION = -11;
52 public static final int FIELD_COMPONENTS = -12;
53 public static final int FIELD_VERSIONS = -13;
54 public static final int FIELD_ATTACHMENTDESCRIPTION = -14;
55 public static final int FIELD_ATTACHMENTFILENAME = -15;
56 public static final int FIELD_HISTORY = -16;
57
58 protected static final int[] STANDARD_FIELDS = {FIELD_ID,
59 FIELD_DESCRIPTION, FIELD_STATUS, FIELD_RESOLUTION, FIELD_SEVERITY,
60 FIELD_CREATOR, FIELD_CREATEDATE, FIELD_OWNER, FIELD_LASTMODIFIED,
61 FIELD_PROJECT, FIELD_TARGET_VERSION, FIELD_COMPONENTS,
62 FIELD_VERSIONS, FIELD_ATTACHMENTDESCRIPTION,
63 FIELD_ATTACHMENTFILENAME, FIELD_HISTORY};
64
65 public static final int STATUS_NEW = 100;
66 public static final int STATUS_UNASSIGNED = 200;
67 public static final int STATUS_ASSIGNED = 300;
68 public static final int STATUS_RESOLVED = 400;
69 public static final int STATUS_CLOSED = 500;
70
71
72
73
74 public static final int STATUS_END = 600;
75
76 public static final int HISTORY_STATUS_REMOVED = -1;
77 public static final int HISTORY_STATUS_AVAILABLE = 1;
78
79
80
81
82 public static final int RELATION_TYPE_RELATED_P = 1;
83
84
85
86 public static final int RELATION_TYPE_RELATED_C = 2;
87
88
89
90 public static final int RELATION_TYPE_DUPLICATE_P = 3;
91
92
93
94 public static final int RELATION_TYPE_DUPLICATE_C = 4;
95
96
97
98 public static final int RELATION_TYPE_CLONED_P = 5;
99
100
101
102 public static final int RELATION_TYPE_CLONED_C = 6;
103
104
105
106 public static final int RELATION_TYPE_SPLIT_P = 7;
107
108
109
110 public static final int RELATION_TYPE_SPLIT_C = 8;
111
112
113
114 public static final int RELATION_TYPE_DEPENDENT_P = 9;
115
116
117
118 public static final int RELATION_TYPE_DEPENDENT_C = 10;
119
120 public static final int NUM_RELATION_TYPES = 10;
121
122 private static List<Configuration> resolutions = new ArrayList<Configuration>();
123 private static List<Configuration> severities = new ArrayList<Configuration>();
124 private static List<Configuration> statuses = new ArrayList<Configuration>();
125 private static List<CustomField> customFields = new ArrayList<CustomField>();
126 private static final Logger logger = Logger.getLogger(IssueUtilities.class);
127
128 public IssueUtilities() {
129 }
130
131 public static String getOwnerName(User owner, Locale locale) {
132 return (null != owner? owner.getFullName():
133 ITrackerResources.getString("itracker.web.generic.unassigned", locale));
134 }
135
136 public static int getFieldType(Integer fieldId) {
137 if (fieldId != null) {
138 if (fieldId > 0) {
139 return FIELD_TYPE_MAP;
140 }
141
142 }
143
144 return FIELD_TYPE_SINGLE;
145 }
146
147 public static String getFieldName(Integer fieldId) {
148 if (fieldId == null) {
149 return "";
150 }
151
152 if (fieldId > 0) {
153 return "customFields";
154 }
155
156 switch (fieldId) {
157 case FIELD_ID:
158 return "id";
159 case FIELD_DESCRIPTION:
160 return "description";
161 case FIELD_STATUS:
162 return "status";
163 case FIELD_RESOLUTION:
164 return "resolution";
165 case FIELD_SEVERITY:
166 return "severity";
167 case FIELD_CREATOR:
168 return "creatorId";
169 case FIELD_CREATEDATE:
170 return "createdate";
171 case FIELD_OWNER:
172 return "ownerId";
173 case FIELD_LASTMODIFIED:
174 return "lastmodified";
175 case FIELD_PROJECT:
176 return "projectId";
177 case FIELD_TARGET_VERSION:
178 return "targetVersion";
179 case FIELD_COMPONENTS:
180 return "components";
181 case FIELD_VERSIONS:
182 return "versions";
183 case FIELD_ATTACHMENTDESCRIPTION:
184 return "attachmentDescription";
185 case FIELD_ATTACHMENTFILENAME:
186 return "attachment";
187 case FIELD_HISTORY:
188 return "history";
189 default:
190 return "";
191 }
192 }
193
194 public static String getFieldName(Integer fieldId,
195 List<CustomField> customFields, Locale locale) {
196
197 if (fieldId < 0) {
198 return ITrackerResources.getString(getStandardFieldKey(fieldId), locale);
199 } else {
200 return CustomFieldUtilities.getCustomFieldName(fieldId,
201 locale);
202 }
203
204 }
205
206 public static String getStandardFieldKey(int fieldId) {
207 switch (fieldId) {
208 case FIELD_ID:
209 return "itracker.web.attr.id";
210 case FIELD_DESCRIPTION:
211 return "itracker.web.attr.description";
212 case FIELD_STATUS:
213 return "itracker.web.attr.status";
214 case FIELD_RESOLUTION:
215 return "itracker.web.attr.resolution";
216 case FIELD_SEVERITY:
217 return "itracker.web.attr.severity";
218 case FIELD_CREATOR:
219 return "itracker.web.attr.creator";
220 case FIELD_CREATEDATE:
221 return "itracker.web.attr.createdate";
222 case FIELD_OWNER:
223 return "itracker.web.attr.owner";
224 case FIELD_LASTMODIFIED:
225 return "itracker.web.attr.lastmodified";
226 case FIELD_PROJECT:
227 return "itracker.web.attr.project";
228 case FIELD_TARGET_VERSION:
229 return "itracker.web.attr.target";
230 case FIELD_COMPONENTS:
231 return "itracker.web.attr.components";
232 case FIELD_VERSIONS:
233 return "itracker.web.attr.versions";
234 case FIELD_ATTACHMENTDESCRIPTION:
235 return "itracker.web.attr.attachmentdescription";
236 case FIELD_ATTACHMENTFILENAME:
237 return "itracker.web.attr.attachmentfilename";
238 case FIELD_HISTORY:
239 return "itracker.web.attr.detaileddescription";
240 default:
241 return "itracker.web.generic.unknown";
242 }
243 }
244
245 public static NameValuePair[] getStandardFields(Locale locale) {
246 NameValuePaireValuePair">NameValuePair[] fieldNames = new NameValuePair[STANDARD_FIELDS.length];
247 for (int i = 0; i < STANDARD_FIELDS.length; i++) {
248 fieldNames[i] = new NameValuePair(ITrackerResources.getString(
249 getStandardFieldKey(STANDARD_FIELDS[i]), locale), Integer
250 .toString(STANDARD_FIELDS[i]));
251 }
252 return fieldNames;
253 }
254
255 public static String getRelationName(IssueRelation.Type value) {
256 return getRelationName(value, ITrackerResources.getLocale());
257 }
258
259
260 public static String getRelationName(IssueRelation.Type value, Locale locale) {
261 return StringUtils.defaultIfBlank(ITrackerResources.getString(
262 ITrackerResources.KEY_BASE_ISSUE_RELATION + value.getCode(), locale), value.name());
263 }
264
265 public static IssueRelation.Type getMatchingRelationType(IssueRelation.Type relationType) {
266 switch (relationType) {
267 case RELATED_P:
268 return IssueRelation.Type.RELATED_C;
269 case RELATED_C:
270 return IssueRelation.Type.RELATED_P;
271 case DUPLICATE_P:
272 return IssueRelation.Type.DUPLICATE_C;
273 case DUPLICATE_C:
274 return IssueRelation.Type.DUPLICATE_P;
275 case CLONED_P:
276 return IssueRelation.Type.CLONED_C;
277 case CLONED_C:
278 return IssueRelation.Type.CLONED_P;
279 case SPLIT_P:
280 return IssueRelation.Type.SPLIT_C;
281 case SPLIT_C:
282 return IssueRelation.Type.SPLIT_P;
283 case DEPENDENT_P:
284 return IssueRelation.Type.DEPENDENT_C;
285 case DEPENDENT_C:
286 default:
287 return IssueRelation.Type.DEPENDENT_P;
288 }
289 }
290
291 public static String componentsToString(Issue issue) {
292 StringBuilder value = new StringBuilder();
293 if (issue != null && issue.getComponents().size() > 0) {
294 for (int i = 0; i < issue.getComponents().size(); i++) {
295 value.append(i != 0 ? ", " : "").append(issue.getComponents().get(i).getName());
296 }
297 }
298 return value.toString();
299 }
300
301 public static String versionsToString(Issue issue) {
302 StringBuilder value = new StringBuilder();
303 if (issue != null && issue.getVersions().size() > 0) {
304 for (int i = 0; i < issue.getVersions().size(); i++) {
305 value.append(i != 0 ? ", " : "").append(issue.getVersions().get(i).getNumber());
306 }
307 }
308 return value.toString();
309 }
310
311 public static String historyToString(Issue issue, SimpleDateFormat sdf) {
312 StringBuilder value = new StringBuilder();
313 if (issue != null && issue.getHistory().size() > 0 && sdf != null) {
314 for (int i = 0; i < issue.getHistory().size(); i++) {
315 value.append(i != 0 ? "," : "").append(issue.getHistory().get(i).getDescription()).append(",").append(issue.getHistory().get(i).getUser().getFirstName());
316 value.append(" ").append(issue.getHistory().get(i).getUser().getLastName()).append(",").append(sdf.format(issue.getHistory().get(i)
317 .getLastModifiedDate()));
318 }
319 }
320 return value.toString();
321 }
322
323 public static String getStatusName(Integer value) {
324 return getStatusName(value, ITrackerResources.getLocale());
325 }
326
327 public static String getStatusName(Integer value, Locale locale) {
328 return getStatusName(Integer.toString(value), locale);
329 }
330
331 public static String getStatusName(String value, Locale locale) {
332 return StringUtils.defaultIfBlank(ITrackerResources.getString(ITrackerResources.KEY_BASE_STATUS
333 + value, locale), value);
334 }
335
336
337
338
339 public static List<Configuration> getStatuses() {
340 return statuses;
341 }
342
343 public static List<NameValuePair> getStatuses(Locale locale) {
344 List<NameValuePair> statusStrings = new ArrayList<>(statuses.size());
345 for (Configuration status : statuses) {
346 statusStrings.add(new NameValuePair(getStatusName(status.getValue(), locale), status.getValue()));
347 }
348 return statusStrings;
349 }
350
351 public static void setStatuses(List<Configuration> value) {
352 statuses = (value == null ? new ArrayList<Configuration>() : value);
353 }
354
355 public static int getNumberStatuses() {
356 return statuses.size();
357 }
358
359 public static String getSeverityName(Integer value) {
360 return StringUtils.defaultIfBlank(getSeverityName(value, ITrackerResources.getLocale()), String.valueOf(value));
361 }
362
363 public static String getSeverityName(Integer value, Locale locale) {
364 return StringUtils.defaultIfBlank(getSeverityName(Integer.toString(value), locale), String.valueOf(value));
365 }
366
367 public static String getSeverityName(String value, Locale locale) {
368 return StringUtils.defaultIfBlank(ITrackerResources.getString(ITrackerResources.KEY_BASE_SEVERITY
369 + value, locale), String.valueOf(value));
370 }
371
372
373
374
375
376
377
378
379
380 public static List<NameValuePair> getSeverities(Locale locale) {
381 List<NameValuePair> severityStrings = new ArrayList<>();
382
383 for (Configuration severity : severities) {
384 NameValuePair.html#NameValuePair">NameValuePair nvp = new NameValuePair(getSeverityName(severity.getValue(), locale),
385 severity.getValue());
386 severityStrings.add(nvp);
387 }
388 return severityStrings;
389 }
390
391 public static void setSeverities(List<Configuration> value) {
392 severities = (value == null ? new ArrayList<Configuration>() : value);
393 }
394
395 public static int getNumberSeverities() {
396 return severities.size();
397 }
398
399
400
401
402
403
404
405
406
407
408 public static int compareSeverity(Issuef="../../../../org/itracker/model/Issue.html#Issue">Issue issueA, Issue issueB) {
409 if (issueA == null && issueB == null) {
410 return 0;
411 } else if (issueA == null) {
412 return -1;
413 } else if (issueB == null) {
414 return 1;
415 } else {
416 int issueAIndex = Integer.MAX_VALUE;
417 int issueBIndex = Integer.MAX_VALUE;
418 for (int i = 0; i < severities.size(); i++) {
419 if (severities.get(i) != null) {
420 if (severities.get(i).getValue().equalsIgnoreCase(
421 Integer.toString(issueA.getSeverity()))) {
422 issueAIndex = i;
423 }
424 if (severities.get(i).getValue().equalsIgnoreCase(
425 Integer.toString(issueB.getSeverity()))) {
426 issueBIndex = i;
427 }
428 }
429 }
430 if (issueAIndex > issueBIndex) {
431 return -1;
432 } else if (issueAIndex < issueBIndex) {
433 return 1;
434 }
435 }
436
437 return 0;
438 }
439
440 public static String getResolutionName(int value) {
441 return getResolutionName(value, ITrackerResources.getLocale());
442 }
443
444 public static String getResolutionName(int value, Locale locale) {
445 return getResolutionName(Integer.toString(value), locale);
446 }
447
448 public static String getResolutionName(String value, Locale locale) {
449 return ITrackerResources.getString(
450 ITrackerResources.KEY_BASE_RESOLUTION + value, locale);
451 }
452
453 public static String checkResolutionName(String value, Locale locale)
454 throws MissingResourceException {
455 return ITrackerResources.getCheckForKey(
456 ITrackerResources.KEY_BASE_RESOLUTION + value, locale);
457 }
458
459
460
461
462
463
464
465
466
467 public static List<NameValuePair> getResolutions(Locale locale) {
468 final List<NameValuePair> resolutionStrings = new ArrayList<>(resolutions.size());
469 for (Configuration resolution : resolutions) {
470 resolutionStrings.add(new NameValuePair(
471 getResolutionName(resolution.getValue(), locale),
472 resolution.getValue()));
473 }
474 return resolutionStrings;
475 }
476
477
478
479
480 public static void setResolutions(List<Configuration> value) {
481 resolutions = (value == null ? new ArrayList<Configuration>() : value);
482 }
483
484 public static String getActivityName(IssueActivityType type) {
485 return getActivityName(type, ITrackerResources.getLocale());
486 }
487
488 public static String getActivityName(IssueActivityType type, Locale locale) {
489 return StringUtils.defaultIfBlank(ITrackerResources.getString("itracker.activity."
490 + String.valueOf(type.name()), locale), type.name());
491 }
492
493
494
495
496
497
498 public static List<CustomField> getCustomFields() {
499 return (customFields == null ? new ArrayList<CustomField>()
500 : customFields);
501 }
502
503
504
505
506
507 public static void setCustomFields(List<CustomField> value) {
508 customFields = (value == null ? new ArrayList<CustomField>() : value);
509 }
510
511
512
513
514
515
516
517
518 public static CustomField getCustomField(Integer id) {
519 return getCustomField(id, ITrackerResources.getLocale());
520 }
521
522
523
524
525
526
527
528
529
530 public static CustomField getCustomField(Integer id, Locale locale) {
531 CustomField retField = null;
532
533 try {
534 for (CustomField customField : customFields) {
535 if (customField != null
536 && customField.getId() != null
537 && customField.getId().equals(id)) {
538 retField = (CustomField) customField.clone();
539 break;
540 }
541 }
542 } catch (CloneNotSupportedException cnse) {
543 logger.error("Error cloning CustomField: " + cnse.getMessage());
544 }
545 if (retField == null) {
546 retField = new CustomField();
547 }
548
549 return retField;
550 }
551
552
553
554
555 public static int getNumberCustomFields() {
556 return customFields.size();
557 }
558
559
560
561
562
563
564
565
566 public static boolean canViewIssue(Issue issue, User user,
567 Map<Integer, Set<PermissionType>> permissions) {
568 if (user == null) {
569 if (log.isInfoEnabled()) {
570 log
571 .info("canViewIssue: missing argument. user is null returning false");
572 }
573 return false;
574 }
575 return canViewIssue(issue, user.getId(), permissions);
576 }
577
578
579
580
581
582
583
584
585
586 public static boolean canViewIssue(Issue issue, Integer userId,
587 Map<Integer, Set<PermissionType>> permissions) {
588
589 if (issue == null || userId == null || permissions == null) {
590 if (log.isInfoEnabled()) {
591 log.info("canViewIssue: missing argument. issue: " + issue
592 + ", userid: " + userId + ", permissions: "
593 + permissions);
594 }
595 return false;
596 }
597
598 if (UserUtilities.hasPermission(permissions,
599 issue.getProject().getId(), PermissionType.ISSUE_VIEW_ALL)) {
600 if (log.isDebugEnabled()) {
601 log.debug("canViewIssue: issue: " + issue + ", user: " + userId
602 + ", permission: " + PermissionType.ISSUE_VIEW_ALL);
603 }
604 return true;
605 }
606
607 boolean isUsersIssue = false;
608
609
610
611 if (issue.getCreator().getId().equals(userId)) {
612 if (log.isDebugEnabled()) {
613 log.debug("canViewIssue: issue: " + issue + ", user: " + userId
614 + ", permission: is creator");
615 }
616 isUsersIssue = true;
617 }
618
619 if (issue.getOwner() != null) {
620 if (issue.getOwner().getId().equals(userId)) {
621
622 if (log.isDebugEnabled()) {
623 log.debug("canViewIssue: issue: " + issue + ", user: "
624 + userId + ", permission: is owner");
625 }
626 isUsersIssue = true;
627 }
628 }
629
630
631
632
633 if (isUsersIssue) {
634 if (log.isDebugEnabled()) {
635 log.debug("canViewIssue: issue: " + issue + ", user: "
636 + userId + ", permission: isUsersIssue");
637 }
638 return true;
639 }
640
641
642 if (log.isDebugEnabled()) {
643 log.debug("canViewIssue: issue: " + issue + ", user: " + userId
644 + ", permission: none matched");
645 }
646 return false;
647 }
648
649
650
651
652
653
654
655
656 @Deprecated
657 public static boolean canEditIssue(Issue issue, Integer userId,
658 Map<Integer, Set<PermissionType>> permissions) {
659 if (issue == null || userId == null || permissions == null) {
660 if (log.isInfoEnabled()) {
661 log.info("canEditIssue: missing argument. issue: " + issue
662 + ", userid: " + userId + ", permissions: "
663 + permissions);
664 }
665 return false;
666 }
667
668
669 if (UserUtilities.hasPermission(permissions,
670 issue.getProject().getId(), PermissionType.ISSUE_EDIT_ALL)) {
671
672 if (log.isDebugEnabled()) {
673 log.debug("canEditIssue: user " + userId
674 + " has permission to edit issue " + issue.getId()
675 + ":" + PermissionType.ISSUE_EDIT_ALL);
676 }
677 return true;
678 }
679 if (!UserUtilities.hasPermission(permissions, issue.getProject()
680 .getId(), PermissionType.ISSUE_EDIT_USERS)) {
681 if (log.isDebugEnabled()) {
682 log.debug("canEditIssue: user " + userId
683 + " has not permission to edit issue " + issue.getId()
684 + ":" + PermissionType.ISSUE_EDIT_USERS);
685 }
686 return false;
687 }
688
689 if (issue.getCreator().getId().equals(userId)) {
690 if (log.isDebugEnabled()) {
691 log.debug("canEditIssue: user " + userId
692 + " is creator of issue " + issue.getId() + ":");
693 }
694 return true;
695 }
696 if (issue.getOwner() != null) {
697 if (issue.getOwner().getId().equals(userId)) {
698 if (log.isDebugEnabled()) {
699 log.debug("canEditIssue: user " + userId
700 + " is owner of issue " + issue.getId() + ":");
701 }
702 return true;
703 }
704 }
705
706 if (log.isDebugEnabled()) {
707 log.debug("canEditIssue: user " + userId
708 + " could not match permission, denied");
709 }
710 return false;
711 }
712
713
714
715
716
717
718
719
720 @Deprecated
721 public static boolean canBeAssignedIssue(Issue issue, Integer userId,
722 Map<Integer, Set<PermissionType>> permissions) {
723 if (issue == null || userId == null || permissions == null) {
724 return false;
725 }
726
727 if (UserUtilities.hasPermission(permissions,
728 issue.getProject().getId(), PermissionType.ISSUE_EDIT_ALL)) {
729 return true;
730 }
731 if (UserUtilities.hasPermission(permissions,
732 issue.getProject().getId(), PermissionType.ISSUE_EDIT_USERS)) {
733 if (issue.getCreator().getId().equals(userId)) {
734 return true;
735 } else if (UserUtilities.hasPermission(permissions, issue
736 .getProject().getId(), PermissionType.ISSUE_ASSIGNABLE)) {
737 return true;
738 } else if (issue.getOwner().getId() != null
739 && issue.getOwner().getId().equals(userId)) {
740 return true;
741 }
742 }
743
744 return false;
745 }
746
747
748
749
750
751
752
753
754 public static boolean canUnassignIssue(Issue issue, Integer userId,
755 Map<Integer, Set<PermissionType>> permissions) {
756 if (issue == null || userId == null || permissions == null) {
757 return false;
758 }
759
760 if (UserUtilities.hasPermission(permissions,
761 issue.getProject().getId(), PermissionType.ISSUE_ASSIGN_OTHERS)) {
762 return true;
763 }
764 return issue.getOwner() != null
765 && userId.equals(issue.getOwner().getId())
766 && UserUtilities.hasPermission(permissions, issue.getProject()
767 .getId(), PermissionType.ISSUE_UNASSIGN_SELF);
768
769 }
770
771 public static boolean hasIssueRelation(Issue issue, Integer relatedIssueId) {
772 if (issue != null) {
773 List<IssueRelation> relations = issue.getRelations();
774 for (IssueRelation relation : relations) {
775 if (relation.getRelatedIssue().getId().equals(
776 relatedIssueId)) {
777 return true;
778 }
779 }
780 }
781 return false;
782 }
783
784 public static boolean hasIssueNotification(Issue issue, Integer userId) {
785 return hasIssueNotification(issue, issue.getProject(), userId);
786 }
787
788 public static boolean hasHardNotification(Issue issue, Project project, Integer userId) {
789 if (issue == null || userId == null) {
790 return false;
791 }
792
793
794 if ((issue.getOwner() != null && issue.getOwner().getId().equals(userId))
795 || issue.getCreator().getId().equals(userId)) {
796 return true;
797 }
798
799 if (project != null && project.getOwners() != null) {
800 for (User user : project.getOwners()) {
801 if (user.getId().equals(userId)) {
802 return true;
803 }
804 }
805 }
806 Collection<Notification> notifications = issue.getNotifications();
807 if (notifications != null) {
808 for (Notification notification : notifications) {
809 if (notification.getUser().getId().equals(userId) && notification.getRole() != Notification.Role.IP) {
810 return true;
811 }
812 }
813 }
814 return false;
815 }
816
817
818
819
820
821 public static boolean hasIssueNotification(Issue issue, Project project,
822 Integer userId) {
823 if (issue == null || userId == null) {
824 return false;
825 }
826
827 if (hasHardNotification(issue, project, userId)) {
828 return true;
829 }
830
831 Collection<Notification> notifications = issue.getNotifications();
832 if (notifications != null) {
833 for (Notification notification : notifications) {
834 if (notification.getUser().getId().equals(userId)) {
835 return true;
836 }
837 }
838 }
839
840 return false;
841 }
842
843 public static URL getIssueURL(Issue issue, String baseURL) throws MalformedURLException {
844 return getIssueURL(issue, new URL(baseURL + (StringUtils.endsWith(baseURL, "/") ? "" : "/")
845 ));
846 }
847
848 public static URL getIssueURL(Issue issue, URL base) {
849 try {
850 if (null != base && null != issue)
851 return new URL(base, "module-projects/view_issue.do?id=" + issue.getId());
852 } catch (MalformedURLException e) {
853 log.error("could not create URL", e);
854 }
855 return null;
856 }
857 }
858
859