├── .gitignore
├── README.md
├── src
└── main
│ ├── resources
│ └── ru
│ │ └── mail
│ │ └── jira
│ │ └── plugins
│ │ └── commons
│ │ ├── email-text.vm
│ │ └── email-html.vm
│ └── java
│ └── ru
│ └── mail
│ └── jira
│ └── plugins
│ └── commons
│ ├── RestFieldException.java
│ ├── StreamRestResult.java
│ ├── HttpSenderException.java
│ ├── SentryClient.java
│ ├── ContractUtils.java
│ ├── RestExecutor.java
│ ├── HttpSender.java
│ ├── LocalUtils.java
│ └── CommonUtils.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .idea
3 | target
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | commons
2 | =======
3 |
4 | ru.mail.jira.plugins.commons
5 |
--------------------------------------------------------------------------------
/src/main/resources/ru/mail/jira/plugins/commons/email-text.vm:
--------------------------------------------------------------------------------
1 | #disable_html_escaping()
2 | $subject
3 | #dashes($subject)
4 |
5 |
6 | $message
7 | #parse("templates/email/text/includes/footer.vm")
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/RestFieldException.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 | public class RestFieldException extends IllegalArgumentException {
4 | private final String field;
5 |
6 | public RestFieldException(String message, String field) {
7 | super(message);
8 | this.field = field;
9 | }
10 |
11 | public String getField() {
12 | return field;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/resources/ru/mail/jira/plugins/commons/email-html.vm:
--------------------------------------------------------------------------------
1 | #disable_html_escaping()
2 | #parse( "templates/email/html/includes/emailconstants.vm" )
3 | #parse( "templates/email/html/includes/header.vm" )
4 |
5 | #set( $pageTitle = $subject )
6 | #rowWrapperNormal( "#parse( 'templates/email/html/includes/patterns/page-title.vm' )" )
7 |
8 | #rowWrapperNormalBegin( "", "wrapper-special-margin" )
9 | #set( $n = "
10 | " )
11 |
$message.replaceAll( "$n", "
" )
12 | #rowWrapperNormalEnd()
13 |
14 | #parse( "templates/email/html/includes/footer.vm" )
15 |
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/StreamRestResult.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 | import java.io.InputStream;
4 |
5 | public class StreamRestResult {
6 | private final InputStream inputStream;
7 | private final String contentType;
8 |
9 | public StreamRestResult(InputStream inputStream, String contentType) {
10 | this.inputStream = inputStream;
11 | this.contentType = contentType;
12 | }
13 |
14 | public InputStream getInputStream() {
15 | return inputStream;
16 | }
17 |
18 | public String getContentType() {
19 | return contentType;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/HttpSenderException.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 | import java.io.IOException;
4 |
5 | @SuppressWarnings("UnusedDeclaration")
6 | public class HttpSenderException extends IOException {
7 | private int responseCode;
8 | private String requestMessage;
9 | private String responseMessage;
10 |
11 | public HttpSenderException(int responseCode, String requestMessage, String responseMessage) {
12 | super(String.format("Invalid server response, code: %d, message: %s", responseCode, responseMessage));
13 | this.responseCode = responseCode;
14 | this.requestMessage = requestMessage;
15 | this.responseMessage = responseMessage;
16 | }
17 |
18 | public int getResponseCode() {
19 | return responseCode;
20 | }
21 |
22 | public String getRequestMessage() {
23 | return requestMessage;
24 | }
25 |
26 | public String getResponseMessage() {
27 | return responseMessage;
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return String.format("SenderException[responseCode=%d, requestMessage=%s, responseMessage=%s]", responseCode, requestMessage, responseMessage);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/SentryClient.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 |
4 | import com.atlassian.jira.component.ComponentAccessor;
5 | import com.atlassian.jira.security.JiraAuthenticationContext;
6 | import com.atlassian.jira.user.ApplicationUser;
7 | import io.sentry.Sentry;
8 | import io.sentry.event.UserBuilder;
9 |
10 | public class SentryClient {
11 | private static JiraAuthenticationContext jiraAuthenticationContext;
12 |
13 | public static void init(String dsn) {
14 | jiraAuthenticationContext = ComponentAccessor.getJiraAuthenticationContext();
15 | Sentry.init(dsn);
16 | }
17 |
18 | public static void capture(Throwable throwable) {
19 | try {
20 | setContextUser();
21 | Sentry.capture(throwable);
22 | } catch (Throwable e) {
23 | } finally {
24 | Sentry.clearContext();
25 | }
26 | }
27 |
28 | public static void capture(String message) {
29 | try {
30 | setContextUser();
31 | Sentry.capture(message);
32 | } catch (Throwable e) {
33 | } finally {
34 | Sentry.clearContext();
35 | }
36 | }
37 |
38 | public static void close() {
39 | Sentry.close();
40 | }
41 |
42 | private static void setContextUser() {
43 | if (jiraAuthenticationContext != null && jiraAuthenticationContext.isLoggedInUser()) {
44 | ApplicationUser user = jiraAuthenticationContext.getLoggedInUser();
45 | Sentry.setUser(new UserBuilder()
46 | .setId(user.getKey())
47 | .setEmail(user.getEmailAddress())
48 | .setUsername(user.getDisplayName())
49 | .build());
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | ru.mail.jira.plugins
8 | commons
9 | 1.0
10 |
11 |
12 |
13 | com.atlassian.jira
14 | jira-api
15 | ${jira.version}
16 | provided
17 |
18 |
19 | com.atlassian.jira
20 | jira-core
21 | ${jira.version}
22 | provided
23 |
24 |
25 | com.atlassian.plugins.rest
26 | atlassian-rest-common
27 | 1.0.2
28 | provided
29 |
30 |
31 |
32 | io.sentry
33 | sentry
34 | 1.1.0
35 |
36 |
37 | slf4j-api
38 | org.slf4j
39 |
40 |
41 |
42 |
43 |
44 |
45 | 7.3.3
46 |
47 |
48 |
49 |
50 | atlassian
51 | https://maven.atlassian.com/repository/public
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/ContractUtils.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | @SuppressWarnings("UnusedDeclaration")
7 | public class ContractUtils {
8 | private final static Pattern INN_PATTERN = Pattern.compile("\\d{10}|\\d{12}");
9 | private final static Pattern SNILS_WITH_CHECKSUM_PATTERN = Pattern.compile("(\\d{3}-\\d{3}-\\d{3}) (\\d{2})");
10 | private final static Pattern SNILS_WITHOUT_CHECKSUM_PATTERN = Pattern.compile("\\d{3}-\\d{3}-\\d{3}");
11 | private final static Pattern EXTRA_SNILS_VALIDATE_PATTERN = Pattern.compile("0{3}|1{3}|2{3}|3{3}|4{3}|5{3}|6{3}|7{3}|8{3}|9{3}");
12 |
13 | public static boolean isValidSnils(String snils) {
14 | Matcher snilsWithCsMatcher = SNILS_WITH_CHECKSUM_PATTERN.matcher(snils);
15 | if (snilsWithCsMatcher.matches()) {
16 | String joinedPartBeforeSpace = snilsWithCsMatcher.group(1).replaceAll("-", "");
17 | int checksum = Integer.valueOf(snilsWithCsMatcher.group(2));
18 |
19 | if (EXTRA_SNILS_VALIDATE_PATTERN.matcher(joinedPartBeforeSpace).find())
20 | return false;
21 |
22 | int sum = 0;
23 | for (int i = 0, j = 9; i < 9; i++, j--)
24 | sum += Character.getNumericValue(joinedPartBeforeSpace.charAt(i)) * j;
25 |
26 | if (sum < 100)
27 | return checksum == sum;
28 | else if (sum == 100 || sum == 101)
29 | return checksum == 0;
30 | else
31 | return (checksum == sum % 101) || (checksum == 0 && sum % 101 == 100);
32 | }
33 |
34 | if (SNILS_WITHOUT_CHECKSUM_PATTERN.matcher(snils).matches()) {
35 | String joinedPartBeforeSpace = snils.replaceAll("-", "");
36 | return !EXTRA_SNILS_VALIDATE_PATTERN.matcher(joinedPartBeforeSpace).find() && Integer.valueOf(joinedPartBeforeSpace) <= 1001998;
37 | }
38 |
39 | return false;
40 | }
41 |
42 | public static boolean isValidInn(String inn) {
43 | return INN_PATTERN.matcher(inn).matches();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/RestExecutor.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import javax.ws.rs.core.Response;
7 |
8 | @SuppressWarnings("UnusedDeclaration")
9 | public abstract class RestExecutor {
10 | private static final String FIELD_HEADER = "X-Atlassian-Rest-Exception-Field";
11 |
12 | private static final Logger log = LoggerFactory.getLogger(RestExecutor.class);
13 |
14 | protected abstract T doAction() throws Exception;
15 |
16 | public Response getResponse() {
17 | return getResponse(Response.Status.OK);
18 | }
19 |
20 | public Response getResponse(Response.Status successStatus) {
21 | try {
22 | T actionResult = doAction();
23 | Response.ResponseBuilder responseBuilder = Response.status(successStatus).entity(actionResult);
24 |
25 | if (actionResult instanceof byte[])
26 | responseBuilder = responseBuilder.type("application/force-download")
27 | .header("Content-Transfer-Encoding", "binary")
28 | .header("charset", "UTF-8");
29 | else if(actionResult instanceof StreamRestResult)
30 | responseBuilder = responseBuilder.entity(((StreamRestResult) actionResult).getInputStream())
31 | .type(((StreamRestResult) actionResult).getContentType());
32 | return responseBuilder.build();
33 | } catch (SecurityException e) {
34 | return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build();
35 | } catch (IllegalArgumentException e) {
36 | Response.ResponseBuilder responseBuilder = Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage());
37 | if (e instanceof RestFieldException)
38 | responseBuilder = responseBuilder.header(FIELD_HEADER, ((RestFieldException) e).getField());
39 | return responseBuilder.build();
40 | } catch (Exception e) {
41 | SentryClient.capture(e);
42 | log.error("REST Exception", e);
43 | return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/HttpSender.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 | import org.apache.commons.io.IOUtils;
4 | import org.apache.commons.lang3.StringUtils;
5 | import org.apache.log4j.Logger;
6 |
7 | import javax.xml.bind.DatatypeConverter;
8 | import java.io.IOException;
9 | import java.net.HttpURLConnection;
10 | import java.net.URL;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | @SuppressWarnings("UnusedDeclaration")
15 | public class HttpSender {
16 | private static final Logger log = Logger.getLogger(HttpSender.class);
17 |
18 | private final String url;
19 | private String user;
20 | private String password;
21 | private final Map headers = new HashMap();
22 |
23 | public HttpSender(String url, Object... params) {
24 | this.url = CommonUtils.formatUrl(url, params);
25 | }
26 |
27 | public HttpSender setAuthenticationInfo(String user, String password) {
28 | this.user = user;
29 | this.password = password;
30 | return this;
31 | }
32 |
33 | public HttpSender setHeader(String header, String value) {
34 | headers.put(header, value);
35 | return this;
36 | }
37 |
38 | public HttpSender setContentTypeJson() {
39 | setHeader("Content-Type", "application/json; charset=utf-8");
40 | return this;
41 | }
42 |
43 | private String getAuthRealm() {
44 | return DatatypeConverter.printBase64Binary(user.concat(":").concat(password).getBytes());
45 | }
46 |
47 | private String send(String method, String body) throws IOException {
48 | log.info(String.format("Sending HTTP request: %s", url));
49 |
50 | HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
51 | try {
52 | connection.setDoInput(true);
53 | connection.setDoOutput(StringUtils.isNotEmpty(body));
54 | connection.setAllowUserInteraction(true);
55 | connection.setRequestMethod(method);
56 | if (StringUtils.isNotEmpty(user) && StringUtils.isNotEmpty(password))
57 | connection.setRequestProperty("Authorization", "Basic " + getAuthRealm());
58 | for (Map.Entry entry : headers.entrySet())
59 | connection.setRequestProperty(entry.getKey(), entry.getValue());
60 | if (StringUtils.isNotEmpty(body))
61 | IOUtils.write(body, connection.getOutputStream());
62 |
63 | int rc = connection.getResponseCode();
64 | if (rc == HttpURLConnection.HTTP_OK) {
65 | String response = IOUtils.toString(connection.getInputStream(), "UTF-8");
66 | log.debug(String.format("HTTP response body:\n %s", response));
67 | return response;
68 | } else {
69 | String response = connection.getErrorStream() != null ? IOUtils.toString(connection.getErrorStream(), "UTF-8") : "";
70 | log.debug(String.format("HTTP error stream:\n %s", response));
71 | throw new HttpSenderException(rc, body, response);
72 | }
73 | } finally {
74 | connection.disconnect();
75 | }
76 | }
77 |
78 | public String sendGet() throws IOException {
79 | return send("GET", null);
80 | }
81 |
82 | public String sendGet(String body) throws IOException {
83 | return send("GET", body);
84 | }
85 |
86 | public String sendPost(String body) throws IOException {
87 | return send("POST", body);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/LocalUtils.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 |
5 | import java.text.DateFormatSymbols;
6 | import java.text.SimpleDateFormat;
7 | import java.util.ArrayList;
8 | import java.util.Calendar;
9 | import java.util.List;
10 |
11 | @SuppressWarnings("UnusedDeclaration")
12 | public class LocalUtils {
13 | private static final String ZERO_CAPTION = "ноль";
14 | private static final String MINUS_CAPTION = "минус";
15 |
16 | private static final String[][] MAGNITUDE_CAPTIONS = new String[][] {
17 | { null, null, null, null },
18 | { "FEMALE", "тысяча", "тысячи", "тысяч" },
19 | { null, "миллион", "миллиона", "миллионов" },
20 | { null, "миллиард", "миллиарда", "миллиардов" }
21 | };
22 | private static final int SEX_MAGNITUDE = 0;
23 | private static final int ONE_MAGNITUDE = 1;
24 | private static final int FOUR_MAGNITUDE = 2;
25 | private static final int MANY_MAGNITUDE = 3;
26 |
27 | private static final String[][] DIGIT_CAPTIONS = new String[][] {
28 | { null, null, "десять", null, null },
29 | { "один", "одна", "одиннадцать", "десять", "сто" },
30 | { "два", "две", "двенадцать", "двадцать", "двести" },
31 | { "три", "три", "тринадцать", "тридцать", "триста" },
32 | { "четыре", "четыре", "четырнадцать", "сорок", "четыреста" },
33 | { "пять", "пять", "пятнадцать", "пятьдесят", "пятьсот" },
34 | { "шесть", "шесть", "шестнадцать", "шестьдесят", "шестьсот" },
35 | { "семь", "семь", "семнадцать", "семьдесят", "семьсот" },
36 | { "восемь", "восемь", "восемнадцать", "восемьдесят", "восемьсот" },
37 | { "девять", "девять", "девятнадцать", "девяносто", "девятьсот" }
38 | };
39 | private static final int MALE_DIGIT = 0;
40 | private static final int FEMALE_DIGIT = 1;
41 | private static final int TEEN_DIGIT = 2;
42 | private static final int DECADE_DIGIT = 3;
43 | private static final int HUNDRED_DIGIT = 4;
44 |
45 | public static String numberToCaption(int number) {
46 | if (number == 0)
47 | return ZERO_CAPTION;
48 |
49 | List result = new ArrayList();
50 |
51 | if (number < 0) {
52 | result.add(MINUS_CAPTION);
53 | number = -number;
54 | }
55 |
56 | for (int magnitude = MAGNITUDE_CAPTIONS.length - 1; magnitude >= 0; magnitude--) {
57 | int magnitudeMultiplier = (int) Math.pow(1000, magnitude);
58 | int part = number / magnitudeMultiplier;
59 | number %= magnitudeMultiplier;
60 |
61 | if (part > 0) {
62 | if (part >= 100) {
63 | result.add(DIGIT_CAPTIONS[part / 100][HUNDRED_DIGIT]);
64 | part %= 100;
65 | }
66 | if (part >= 10 && part < 20) {
67 | result.add(DIGIT_CAPTIONS[part - 10][TEEN_DIGIT]);
68 | part = 0;
69 | }
70 | if (part >= 20) {
71 | result.add(DIGIT_CAPTIONS[part / 10][DECADE_DIGIT]);
72 | part %= 10;
73 | }
74 | if (part > 0) {
75 | boolean female = MAGNITUDE_CAPTIONS[magnitude][SEX_MAGNITUDE] != null;
76 | result.add(DIGIT_CAPTIONS[part][female ? FEMALE_DIGIT : MALE_DIGIT]);
77 | }
78 |
79 | if (magnitude > 0)
80 | switch (part) {
81 | case 1:
82 | result.add(MAGNITUDE_CAPTIONS[magnitude][ONE_MAGNITUDE]);
83 | break;
84 | case 2: case 3: case 4:
85 | result.add(MAGNITUDE_CAPTIONS[magnitude][FOUR_MAGNITUDE]);
86 | break;
87 | default:
88 | result.add(MAGNITUDE_CAPTIONS[magnitude][MANY_MAGNITUDE]);
89 | break;
90 | }
91 | }
92 | }
93 |
94 | return StringUtils.join(result, " ");
95 | }
96 |
97 | public static final String[] MONTH_NAMES_NOMINATIVE = new String[] { "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь" };
98 | public static final String[] MONTH_NAMES_GENITIVE = new String[] { "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря" };
99 |
100 | public static SimpleDateFormat updateMonthNames(SimpleDateFormat simpleDateFormat, String[] monthNames) {
101 | DateFormatSymbols dateFormatSymbols = simpleDateFormat.getDateFormatSymbols();
102 | dateFormatSymbols.setMonths(monthNames);
103 | simpleDateFormat.setDateFormatSymbols(dateFormatSymbols);
104 | return simpleDateFormat;
105 | }
106 |
107 | public static boolean isWeekend(Calendar calendar) {
108 | return calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY;
109 | }
110 |
111 | public static boolean isHoliday(Calendar calendar) {
112 | int month = calendar.get(Calendar.MONTH);
113 | int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
114 | if (month == Calendar.JANUARY && dayOfMonth < 9)
115 | return true;
116 | if (month == Calendar.FEBRUARY && dayOfMonth == 23)
117 | return true;
118 | if (month == Calendar.MARCH && dayOfMonth == 8)
119 | return true;
120 | if (month == Calendar.MAY && (dayOfMonth == 1 || dayOfMonth == 9))
121 | return true;
122 | if (month == Calendar.JUNE && dayOfMonth == 12)
123 | return true;
124 | if (month == Calendar.NOVEMBER && dayOfMonth == 4)
125 | return true;
126 | return false;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/ru/mail/jira/plugins/commons/CommonUtils.java:
--------------------------------------------------------------------------------
1 | package ru.mail.jira.plugins.commons;
2 |
3 | import com.atlassian.jira.component.ComponentAccessor;
4 | import com.atlassian.jira.issue.Issue;
5 | import com.atlassian.jira.issue.fields.CustomField;
6 | import com.atlassian.jira.mail.Email;
7 | import com.atlassian.jira.mail.builder.EmailBuilder;
8 | import com.atlassian.jira.notification.NotificationRecipient;
9 | import com.atlassian.jira.security.groups.GroupManager;
10 | import com.atlassian.jira.user.ApplicationUser;
11 | import com.atlassian.jira.user.util.UserManager;
12 | import com.atlassian.jira.util.ErrorCollection;
13 | import com.atlassian.mail.queue.MailQueueItem;
14 | import org.apache.commons.lang3.StringUtils;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 |
18 | import java.io.PrintWriter;
19 | import java.io.StringWriter;
20 | import java.io.UnsupportedEncodingException;
21 | import java.io.Writer;
22 | import java.net.URLEncoder;
23 | import java.util.*;
24 |
25 | @SuppressWarnings("UnusedDeclaration")
26 | public class CommonUtils {
27 | private final static Logger log = LoggerFactory.getLogger(CommonUtils.class);
28 |
29 | public static String getXmlTagContent(String xml, String tagName) {
30 | String startTag = String.format("<%s>", tagName);
31 | String endTag = String.format("%s>", tagName);
32 | int startPos = xml.indexOf(startTag);
33 | int endPos = xml.indexOf(endTag);
34 | return (startPos >= 0 && endPos >= 0) ? xml.substring(startPos + startTag.length(), endPos) : "";
35 | }
36 |
37 | public static String join(List stringList) {
38 | if (stringList == null)
39 | return "";
40 | return StringUtils.join(stringList, ", ");
41 | }
42 |
43 | public static List split(String joinedString) {
44 | List stringList = new LinkedList();
45 | if (StringUtils.isNotBlank(joinedString))
46 | for (String s : joinedString.trim().split("\\s*,\\s*"))
47 | if (StringUtils.isNotEmpty(s))
48 | stringList.add(s);
49 | return stringList;
50 | }
51 |
52 | public static String convertUserKeysToJoinedString(List userKeys) {
53 | List userNames = new LinkedList();
54 | if (userKeys != null)
55 | for (String userKey : userKeys) {
56 | ApplicationUser user = ComponentAccessor.getUserManager().getUserByKey(userKey);
57 | if (user != null)
58 | userNames.add(user.getName());
59 | }
60 | return join(userNames);
61 | }
62 |
63 | public static List convertJoinedStringToUserKeys(String joinedString) {
64 | List userKeys = new LinkedList();
65 | for (String userName : split(joinedString)) {
66 | ApplicationUser user = ComponentAccessor.getUserManager().getUserByName(userName);
67 | if (user == null)
68 | throw new IllegalArgumentException(ComponentAccessor.getJiraAuthenticationContext().getI18nHelper().getText("user.picker.errors.usernotfound", userName));
69 | userKeys.add(user.getKey());
70 | }
71 | return userKeys;
72 | }
73 |
74 | public static String formatErrorCollection(ErrorCollection errorCollection) {
75 | Collection lines = new ArrayList();
76 | if (errorCollection.getErrorMessages() != null)
77 | lines.addAll(errorCollection.getErrorMessages());
78 | if (errorCollection.getErrors() != null)
79 | for (Map.Entry e : errorCollection.getErrors().entrySet())
80 | lines.add(String.format("%s: %s", e.getKey(), e.getValue()));
81 | return StringUtils.join(lines, "\n");
82 | }
83 |
84 | public static CustomField getCustomField(Long id) {
85 | CustomField customField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(id);
86 | if (customField == null)
87 | throw new IllegalStateException(String.format("Custom field (%d) is not found.", id));
88 | return customField;
89 | }
90 |
91 | public static CustomField getCustomField(String id) {
92 | CustomField customField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(id);
93 | if (customField == null)
94 | throw new IllegalStateException(String.format("Custom field (%s) is not found.", id));
95 | return customField;
96 | }
97 |
98 | public static String getCustomFieldStringValue(Issue issue, long customFieldId) {
99 | CustomField customField = getCustomField(customFieldId);
100 | Object customFieldValue = issue.getCustomFieldValue(customField);
101 | if (customFieldValue != null)
102 | return customFieldValue.toString().trim();
103 | else
104 | return "";
105 | }
106 |
107 | public static boolean isUserInGroups(ApplicationUser user, Collection groupNames) {
108 | if (user == null)
109 | return false;
110 |
111 | GroupManager groupManager = ComponentAccessor.getGroupManager();
112 | for (String groupName : groupNames)
113 | if (groupManager.isUserInGroup(user.getName(), groupName))
114 | return true;
115 | return false;
116 | }
117 |
118 | public static void sendEmail(List recipientKeys, String subject, String message) {
119 | UserManager userManager = ComponentAccessor.getUserManager();
120 | for (String key : recipientKeys) {
121 | ApplicationUser user = userManager.getUserByKey(key);
122 | if (user != null)
123 | sendEmail(user, subject, message);
124 | else
125 | throw new IllegalArgumentException("Bad user key => " + key);
126 | }
127 | }
128 |
129 | public static void sendEmail(ApplicationUser recipient, String subject, String message) {
130 | Map params = new HashMap();
131 | params.put("subject", subject);
132 | params.put("message", message);
133 |
134 | Email email = new Email(recipient.getEmailAddress());
135 |
136 | NotificationRecipient notificationRecipient = new NotificationRecipient(recipient);
137 | boolean isHtmlFormat = !NotificationRecipient.MIMETYPE_TEXT.equals(notificationRecipient.getFormat());
138 |
139 | MailQueueItem item = new EmailBuilder(email, notificationRecipient)
140 | .withSubject(subject)
141 | .withBodyFromFile(isHtmlFormat ? "ru/mail/jira/plugins/commons/email-html.vm" : "ru/mail/jira/plugins/commons/email-text.vm")
142 | .addParameters(params)
143 | .renderLater();
144 | ComponentAccessor.getMailQueue().addItem(item);
145 | }
146 |
147 | public static String getStackTrace(Throwable e) {
148 | Writer stackTrace = new StringWriter();
149 | e.printStackTrace(new PrintWriter(stackTrace));
150 | return stackTrace.toString();
151 | }
152 |
153 | public static String formatUrl(String url, Object... params) {
154 | if (params == null || params.length == 0)
155 | return url;
156 |
157 | try {
158 | for (int i = 0; i < params.length; i++)
159 | params[i] = URLEncoder.encode(params[i].toString(), "UTF-8");
160 | } catch (UnsupportedEncodingException ignored) {
161 | }
162 | return String.format(url, params);
163 | }
164 | }
165 |
--------------------------------------------------------------------------------