├── .gitignore
├── .travis.yml
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── org
│ │ └── everit
│ │ └── jira
│ │ └── worklog
│ │ └── query
│ │ └── plugin
│ │ ├── DateTimeConverterUtil.java
│ │ ├── FindWorklogsByIssuesParam.java
│ │ ├── IssueBeanWithTimespent.java
│ │ ├── SearchResultsBeanWithTimespent.java
│ │ ├── WorklogQueryCore.java
│ │ ├── WorklogQueryCoreImpl.java
│ │ ├── WorklogQueryException.java
│ │ ├── WorklogQueryResource.java
│ │ └── query
│ │ ├── FindWorklogsByIssuesQuery.java
│ │ ├── FindWorklogsQuery.java
│ │ └── JsonWorklog.java
└── resources
│ ├── atlassian-plugin.xml
│ └── icons
│ ├── e_logo16.png
│ ├── e_logo72.png
│ ├── jwqp144.png
│ └── jwqp16.png
└── test
├── java
└── org
│ └── everit
│ └── jira
│ └── worklog
│ └── query
│ └── test
│ ├── DatabaseSupport.java
│ ├── MockTest.java
│ └── WorklogQueryTest.java
└── resources
└── expectedResults.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | # Eclipse and Maven Files #
2 | .classpath
3 | .settings
4 | .project
5 | .checkstyle
6 | target
7 | .fbExcludeFilterFile
8 | .pmd
9 | .pmdruleset.xml
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
4 | script: mvn verify
5 | install: true
6 | sudo: false
7 | cache:
8 | directories:
9 | - $HOME/.m2
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jira-worklog-query-plugin
2 | =========================
3 |
4 | Worklog Query Plugin is a JIRA plugin enabling its users to run worklog
5 | queries and apply parameters on these queries through RESTful services. The
6 | plugin handles queries according to user roles, therefore, these queries can
7 | only be run on worklogs the user has appropriate permissions to access.
8 | Various filtering parameters can also be set up to narrow down the search
9 | results to a certain interval of time, user, user group and/or project. The
10 | result of the worklog query is served in JSON format.
11 |
12 | The documentation of the plugin can be found [here][1].
13 |
14 | The version history can be found on the [Atlassian Marketplace][2].
15 |
16 | [](https://github.com/igrigorik/ga-beacon)
17 |
18 | [1]: http://www.everit.org/jira-worklog-query-plugin/
19 | [2]: https://marketplace.atlassian.com/plugins/org.everit.jira.worklog.query.plugin.core/versions
20 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
22 |
23 | 4.0.0
24 |
25 |
26 | org.everit.config
27 | org.everit.config.oss
28 | 7.1.0
29 |
30 |
31 | org.everit.jira
32 | org.everit.jira.worklog.query.plugin
33 | 3.0.2
34 |
35 | bundle
36 |
37 | 2013
38 |
39 |
40 | 8.0.0
41 | 1.8
42 | 1.8
43 | 6.2.4
44 |
45 |
46 |
47 | scm:git:git://github.com/everit-org/jira-worklog-query-plugin.git
48 | scm:git:https://github.com/everit-org/jira-worklog-query-plugin.git
49 | https://github.com/everit-org/jira-worklog-query-plugin
50 |
51 |
52 |
53 | Travis CI
54 | https://travis-ci.org/everit-org/jira-worklog-query-plugin
55 |
56 |
57 |
58 | GitHub
59 | https://github.com/everit-org/jira-worklog-query-plugin/issues
60 |
61 |
62 |
63 |
64 | atlassian-public
65 | https://maven.atlassian.com/repository/public
66 |
67 | true
68 | never
69 | warn
70 |
71 |
72 | true
73 | warn
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | org.apache.felix
82 | maven-bundle-plugin
83 | true
84 |
85 |
86 | ${project.artifactId}
87 |
88 | com.atlassian.jira.rest.v2.*;version="${jira.version}",
89 | com.atlassian.jira.rest.api.*;version="${jira.version}",
90 | *
91 |
92 |
93 |
94 |
95 |
96 |
97 | org.apache.maven.plugins
98 | maven-checkstyle-plugin
99 |
100 | org/everit/jira/worklog/query/plugin/WorklogQueryResource*
101 |
102 |
103 |
104 | com.atlassian.maven.plugins
105 | maven-jira-plugin
106 | ${maven.jira.plugin.version}
107 | false
108 |
109 |
110 | generate-obr-artifact
111 | package
112 |
113 | generate-obr-artifact
114 |
115 |
116 |
117 |
118 |
119 |
120 | org.everit.jira
121 | jira-querydsl-support
122 |
123 |
124 |
125 | <_manifest>${project.build.outputdirectory}/META-INF/MANIFEST.MF
126 |
127 |
128 |
129 |
130 | org.apache.maven.plugins
131 | maven-surefire-plugin
132 |
133 |
134 | UTC
135 |
136 |
137 |
138 |
139 |
140 |
141 | src/main/resources
142 | true
143 |
144 |
145 |
146 |
147 |
148 |
149 | com.atlassian.jira
150 | jira-rest-plugin
151 | ${jira.version}
152 | provided
153 |
154 |
155 | com.atlassian.jira
156 | jira-core
157 | ${jira.version}
158 | provided
159 |
160 |
161 | jndi
162 | jndi
163 |
164 |
165 | jta
166 | jta
167 |
168 |
169 |
170 |
171 | com.atlassian.jira
172 | jira-rest-api
173 | ${jira.version}
174 | provided
175 |
176 |
177 |
178 | org.everit.jira
179 | jira-querydsl-support
180 | 2.0.0
181 | provided
182 |
183 |
184 |
185 | com.sun.jersey
186 | jersey-client
187 | 1.12
188 |
189 |
190 |
191 | junit
192 | junit
193 | 4.12
194 | test
195 |
196 |
197 | com.atlassian.jira
198 | jira-tests
199 | ${jira.version}
200 | test
201 |
202 |
203 | org.powermock
204 | powermock-module-junit4
205 | 2.0.0
206 | test
207 |
208 |
209 | org.powermock
210 | powermock-api-mockito2
211 | 2.0.0
212 | test
213 |
214 |
215 | org.apache.geronimo.components
216 | geronimo-transaction
217 | 3.1.3
218 | test
219 |
220 |
221 | org.apache.commons
222 | commons-dbcp2
223 | 2.1
224 | test
225 |
226 |
227 | com.atlassian.plugins.rest
228 | atlassian-rest-module
229 | 6.0.0
230 | test
231 |
232 |
233 |
234 |
235 |
236 |
237 | com.google.guava
238 | guava
239 | 29.0-jre
240 |
241 |
242 |
243 |
244 |
245 |
246 | 3dparty
247 | https://maven.atlassian.com/3rdparty
248 |
249 | true
250 |
251 |
252 | false
253 |
254 |
255 |
256 | atlassian-public
257 | https://maven.atlassian.com/repository/public
258 |
259 | true
260 | never
261 | warn
262 |
263 |
264 | true
265 | warn
266 |
267 |
268 |
269 | everit.release
270 | everit-releases
271 | https://repo.everit.biz/artifactory/public-release/
272 |
273 |
274 |
275 |
276 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/DateTimeConverterUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin;
17 |
18 | import java.sql.Timestamp;
19 | import java.text.DateFormat;
20 | import java.text.ParseException;
21 | import java.text.SimpleDateFormat;
22 | import java.util.Calendar;
23 | import java.util.Date;
24 |
25 | /**
26 | * The utility class of date and time conversions.
27 | */
28 | public final class DateTimeConverterUtil {
29 |
30 | /**
31 | * The date format of the input parameters.
32 | */
33 | private static final String INPUT_DATE_FORMAT = "yyyy-MM-dd";
34 |
35 | /**
36 | * The date format of JIRA.
37 | */
38 | private static final String JIRA_OUTPUT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.s";
39 |
40 | /**
41 | * The date format of the output.
42 | */
43 | private static final String OUTPUT_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
44 |
45 | /**
46 | * Convert the date to String ({@value #OUTPUT_DATE_TIME_FORMAT}).
47 | *
48 | * @param date
49 | * The Date to convert.
50 | * @return The result time.
51 | */
52 | private static String dateToString(final Date date) {
53 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(OUTPUT_DATE_TIME_FORMAT);
54 | String dateString = simpleDateFormat.format(date);
55 | return dateString;
56 | }
57 |
58 | /**
59 | * Convert String ({@value #INPUT_DATE_FORMAT}) to Calendar.
60 | *
61 | * @param dateString
62 | * The String date to convert.
63 | * @return The result Date.
64 | * @throws ParseException
65 | * If can't parse the date.
66 | */
67 | public static Calendar inputStringToCalendar(final String dateString) throws ParseException {
68 | DateFormat dateFormat = new SimpleDateFormat(INPUT_DATE_FORMAT);
69 | Calendar calendar = Calendar.getInstance();
70 | calendar.setTime(dateFormat.parse(dateString));
71 | return calendar;
72 | }
73 |
74 | /**
75 | * Set the calendar hour, minute and second value.
76 | *
77 | * @param originalCalendar
78 | * The original calendar.
79 | * @param hourOfDay
80 | * The hour of the day to set.
81 | * @param minute
82 | * The minute to set.
83 | * @param second
84 | * The second to set.
85 | * @return The new calendar object.
86 | */
87 | public static Calendar setCalendarHourMinSec(final Calendar originalCalendar,
88 | final int hourOfDay,
89 | final int minute, final int second) {
90 | Calendar calendar = Calendar.getInstance();
91 | calendar.set(Calendar.MILLISECOND, 0);
92 | calendar.set(
93 | originalCalendar.get(Calendar.YEAR),
94 | originalCalendar.get(Calendar.MONTH),
95 | originalCalendar.get(Calendar.DAY_OF_MONTH),
96 | hourOfDay,
97 | minute,
98 | second);
99 | return calendar;
100 | }
101 |
102 | /**
103 | * Format a String date to valid ISO-8601 format String date.
104 | *
105 | * @param dateString
106 | * The date.
107 | * @return The formated String date.
108 | * @throws ParseException
109 | * If cannot parse the String to Date.
110 | */
111 | public static String stringDateToISO8601FormatString(final String dateString)
112 | throws ParseException {
113 | DateFormat dateFormat = new SimpleDateFormat(JIRA_OUTPUT_DATE_TIME_FORMAT);
114 | Date date = dateFormat.parse(dateString);
115 | return DateTimeConverterUtil.dateToString(date);
116 | }
117 |
118 | /**
119 | * Format a timestamp to valid ISO-8601 format String date.
120 | *
121 | * @param timestamp
122 | * The timestamp.
123 | * @return The formated String date.
124 | * @throws ParseException
125 | * If cannot parse the String to Date.
126 | */
127 | public static String stringDateToISO8601FormatString(final Timestamp timestamp) {
128 | Date date = new Date(timestamp.getTime());
129 | return DateTimeConverterUtil.dateToString(date);
130 | }
131 |
132 | /**
133 | * Private constructor.
134 | */
135 | private DateTimeConverterUtil() {
136 | }
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/FindWorklogsByIssuesParam.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin;
17 |
18 | import java.io.Serializable;
19 | import java.util.List;
20 |
21 | import com.atlassian.jira.rest.api.util.StringList;
22 |
23 | /**
24 | * FindWorklogsByIssues method parameter container class.
25 | */
26 | public class FindWorklogsByIssuesParam implements Serializable {
27 |
28 | /**
29 | * Serial Version UID.
30 | */
31 | private static final long serialVersionUID = -4947183929460600358L;
32 | /**
33 | * The query start date parameter.
34 | */
35 | public String startDate;
36 | /**
37 | * The query end date parameter.
38 | */
39 | public String endDate;
40 | /**
41 | * The query user parameter.
42 | */
43 | public String user;
44 | /**
45 | * The query group parameter.
46 | */
47 | public String group;
48 | /**
49 | * The query jql parameter.
50 | */
51 | public String jql;
52 | /**
53 | * The query start At parameter.
54 | */
55 | public int startAt;
56 | /**
57 | * The query max Result parameter.
58 | */
59 | public int maxResults;
60 | /**
61 | * The query fields parameter.
62 | */
63 | public List fields;
64 |
65 | public FindWorklogsByIssuesParam endDate(final String endDate) {
66 | this.endDate = endDate;
67 | return this;
68 | }
69 |
70 | public FindWorklogsByIssuesParam fields(final List fields) {
71 | this.fields = fields;
72 | return this;
73 | }
74 |
75 | public FindWorklogsByIssuesParam group(final String group) {
76 | this.group = group;
77 | return this;
78 | }
79 |
80 | public FindWorklogsByIssuesParam jql(final String jql) {
81 | this.jql = jql;
82 | return this;
83 | }
84 |
85 | public FindWorklogsByIssuesParam maxResults(final int maxResults) {
86 | this.maxResults = maxResults;
87 | return this;
88 | }
89 |
90 | private void readObject(final java.io.ObjectInputStream stream) throws java.io.IOException,
91 | ClassNotFoundException {
92 | stream.close();
93 | throw new java.io.NotSerializableException(getClass().getName());
94 | }
95 |
96 | public FindWorklogsByIssuesParam startAt(final int startAt) {
97 | this.startAt = startAt;
98 | return this;
99 | }
100 |
101 | public FindWorklogsByIssuesParam startDate(final String startDate) {
102 | this.startDate = startDate;
103 | return this;
104 | }
105 |
106 | public FindWorklogsByIssuesParam user(final String user) {
107 | this.user = user;
108 | return this;
109 | }
110 |
111 | private void writeObject(final java.io.ObjectOutputStream stream) throws java.io.IOException {
112 | stream.close();
113 | throw new java.io.NotSerializableException(getClass().getName());
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/IssueBeanWithTimespent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin;
17 |
18 | import java.net.URI;
19 | import java.net.URISyntaxException;
20 |
21 | import javax.xml.bind.annotation.XmlElement;
22 |
23 | import com.atlassian.jira.rest.v2.issue.IssueBean;
24 |
25 | /**
26 | * IssueBeanWithTimespent extends the original IssueBean class with spent time value.
27 | */
28 | public class IssueBeanWithTimespent extends IssueBean {
29 | @XmlElement
30 | private Long timespent = 0L;
31 |
32 | public IssueBeanWithTimespent(final Long id, final String key, final String selfUri,
33 | final Long timespent) throws URISyntaxException {
34 | super(id, key, new URI(selfUri));
35 | this.timespent = timespent;
36 | }
37 |
38 | public Long getTimeSpent() {
39 | return timespent;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/SearchResultsBeanWithTimespent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin;
17 |
18 | import java.util.List;
19 |
20 | import javax.xml.bind.annotation.XmlElement;
21 | import javax.xml.bind.annotation.XmlRootElement;
22 |
23 | import org.codehaus.jackson.map.annotate.JsonSerialize;
24 |
25 | import com.atlassian.jira.rest.v2.search.SearchResultsBean;
26 |
27 | /**
28 | * SearchResultsBeanWithTimespent extends the original SearchResultsBean class with issues
29 | * timespent.
30 | */
31 | @XmlRootElement
32 | @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
33 | public class SearchResultsBeanWithTimespent extends SearchResultsBean {
34 |
35 | @XmlElement
36 | private List issues;
37 |
38 | /**
39 | * SearchResultsBeanWithTimespent constructor with fields.
40 | *
41 | * @param startAt
42 | * Start the result list from.
43 | * @param maxResults
44 | * Max number of results.
45 | * @param total
46 | * Total number of found result.
47 | * @param issues
48 | * List of the found issues.
49 | */
50 | public SearchResultsBeanWithTimespent(final Integer startAt, final Integer maxResults,
51 | final Integer total, final List issues) {
52 | this.startAt = startAt;
53 | this.maxResults = maxResults;
54 | this.total = total;
55 | setIssues(issues);
56 | }
57 |
58 | @SuppressWarnings("unused")
59 | public List getIssues() {
60 | return issues;
61 | }
62 |
63 | public void setIssues(final List issues) {
64 | this.issues = issues;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/WorklogQueryCore.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin;
17 |
18 | import java.util.List;
19 |
20 | import javax.ws.rs.core.Response;
21 |
22 | import com.atlassian.jira.rest.api.util.StringList;
23 |
24 | /**
25 | * The interface of the core part of the WorklogQueryResource class.
26 | */
27 | public interface WorklogQueryCore {
28 |
29 | Response findUpdatedWorklogs(String startDate, String endDate, String user, String group,
30 | String project, List fields) throws WorklogQueryException;
31 |
32 | Response findWorklogs(String startDate, String endDate, String user, String group,
33 | String project, List fields) throws WorklogQueryException;
34 |
35 | SearchResultsBeanWithTimespent findWorklogsByIssues(
36 | FindWorklogsByIssuesParam findWorklogsByIssuesParam)
37 | throws WorklogQueryException;
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/WorklogQueryCoreImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin;
17 |
18 | import java.text.ParseException;
19 | import java.util.ArrayList;
20 | import java.util.Arrays;
21 | import java.util.Calendar;
22 | import java.util.Collection;
23 | import java.util.HashMap;
24 | import java.util.List;
25 | import java.util.Map;
26 | import java.util.Set;
27 |
28 | import javax.ws.rs.core.Response;
29 |
30 | import org.everit.jira.querydsl.support.QuerydslSupport;
31 | import org.everit.jira.querydsl.support.ri.QuerydslSupportImpl;
32 | import org.everit.jira.worklog.query.plugin.query.FindWorklogsByIssuesQuery;
33 | import org.everit.jira.worklog.query.plugin.query.FindWorklogsQuery;
34 | import org.everit.jira.worklog.query.plugin.query.JsonWorklog;
35 | import org.slf4j.Logger;
36 | import org.slf4j.LoggerFactory;
37 |
38 | import com.atlassian.jira.bc.issue.search.SearchService;
39 | import com.atlassian.jira.bc.issue.search.SearchService.ParseResult;
40 | import com.atlassian.jira.component.ComponentAccessor;
41 | import com.atlassian.jira.config.properties.APKeys;
42 | import com.atlassian.jira.issue.Issue;
43 | import com.atlassian.jira.issue.fields.Field;
44 | import com.atlassian.jira.issue.fields.FieldException;
45 | import com.atlassian.jira.issue.fields.NavigableField;
46 | import com.atlassian.jira.issue.fields.OrderableField;
47 | import com.atlassian.jira.issue.fields.ProjectSystemField;
48 | import com.atlassian.jira.issue.fields.layout.field.FieldLayout;
49 | import com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem;
50 | import com.atlassian.jira.issue.fields.rest.FieldJsonRepresentation;
51 | import com.atlassian.jira.issue.fields.rest.RestAwareField;
52 | import com.atlassian.jira.issue.search.SearchException;
53 | import com.atlassian.jira.issue.search.SearchResults;
54 | import com.atlassian.jira.jql.parser.JqlParseException;
55 | import com.atlassian.jira.permission.ProjectPermissions;
56 | import com.atlassian.jira.project.Project;
57 | import com.atlassian.jira.rest.api.util.StringList;
58 | import com.atlassian.jira.rest.v2.issue.IncludedFields;
59 | import com.atlassian.jira.rest.v2.issue.IssueBean;
60 | import com.atlassian.jira.rest.v2.issue.RESTException;
61 | import com.atlassian.jira.security.JiraAuthenticationContext;
62 | import com.atlassian.jira.user.ApplicationUser;
63 | import com.atlassian.jira.util.collect.CollectionBuilder;
64 | import com.atlassian.jira.util.json.JSONArray;
65 | import com.atlassian.jira.web.bean.PagerFilter;
66 |
67 | /**
68 | * The implementations of the WorklogQueryCore.
69 | */
70 | public class WorklogQueryCoreImpl implements WorklogQueryCore {
71 |
72 | private static final int DEFAULT_MAXRESULT_PARAM = 25;
73 |
74 | private static final int DEFAULT_STARTAT_PARAM = 0;
75 |
76 | /**
77 | * The last hour of a day.
78 | */
79 | private static final int LAST_HOUR_OF_DAY = 23;
80 |
81 | /**
82 | * The last minute of an hour.
83 | */
84 | private static final int LAST_MINUTE_OF_HOUR = 59;
85 |
86 | /**
87 | * The last second of a minute.
88 | */
89 | private static final int LAST_SECOND_OF_MINUTE = 59;
90 |
91 | /**
92 | * The logger used to log.
93 | */
94 | private static final Logger LOGGER = LoggerFactory.getLogger(WorklogQueryCoreImpl.class);
95 |
96 | private QuerydslSupport querydslSupport;
97 |
98 | /**
99 | * Simple constructor. Create {@link QuerydslSupport} instance.
100 | */
101 | public WorklogQueryCoreImpl() {
102 | try {
103 | querydslSupport = new QuerydslSupportImpl();
104 | } catch (Exception e) {
105 | throw new RuntimeException("Cannot create Worklog Query instance.", e);
106 | }
107 | }
108 |
109 | private void addFields(final Issue issue, final IssueBean bean) {
110 | // iterate over all the visible layout items from the field layout for this issue and attempt to
111 | // add them
112 | // to the result
113 | ApplicationUser loggedInUser =
114 | ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
115 | FieldLayout layout = ComponentAccessor.getFieldLayoutManager().getFieldLayout(issue);
116 | List fieldLayoutItems =
117 | layout.getVisibleLayoutItems(issue.getProjectObject(),
118 | CollectionBuilder.list(issue.getIssueType().getId()));
119 | for (FieldLayoutItem fieldLayoutItem : fieldLayoutItems) {
120 | OrderableField> field = fieldLayoutItem.getOrderableField();
121 | FieldJsonRepresentation fieldValue = getFieldValue(fieldLayoutItem, issue);
122 | if ((fieldValue != null) && (fieldValue.getStandardData() != null)) {
123 | bean.addField(field, fieldValue, false);
124 | }
125 | }
126 | // Then we try to add "NavigableFields" which aren't "OrderableFields" unless they ae special
127 | // ones.
128 | // These aren't included in the Field Layout.
129 | // This is a bit crap because "getAvailableNavigableFields" doesn't take the issue into account.
130 | // All it means is the field is not hidden in at least one project the user has BROWSE
131 | // permission on.
132 | try {
133 | Set fields = ComponentAccessor.getFieldManager()
134 | .getAvailableNavigableFields(loggedInUser);
135 | for (NavigableField field : fields) {
136 | if (!bean.hasField(field.getId())
137 | && (!(field instanceof OrderableField) || (field instanceof ProjectSystemField))
138 | && (field instanceof RestAwareField)) {
139 | addRestAwareField(issue, bean, field, (RestAwareField) field);
140 | }
141 | }
142 | } catch (FieldException e) {
143 | // ignored...display as much as we can.
144 | }
145 |
146 | }
147 |
148 | private void addFieldsToIssueBeans(final List fields,
149 | final Map issueIdIssue, final List issueBeans) {
150 | IncludedFields includedFields = IncludedFields.includeNavigableByDefault(fields);
151 | boolean isEmptyField = StringList.joinLists(fields)
152 | .asList().contains("emptyFieldValue");
153 | for (IssueBeanWithTimespent issueBean : issueBeans) {
154 | issueBean.fieldsToInclude(includedFields);
155 | if (!isEmptyField) {
156 | addFields(issueIdIssue.get(Long.valueOf(issueBean.getId())), issueBean);
157 | }
158 | }
159 | }
160 |
161 | private void addRestAwareField(final Issue issue, final IssueBean bean, final Field field,
162 | final RestAwareField restAware) {
163 | FieldJsonRepresentation fieldJsonFromIssue = restAware.getJsonFromIssue(issue, false, null);
164 | if ((fieldJsonFromIssue != null) && (fieldJsonFromIssue.getStandardData() != null)) {
165 | bean.addField(field, fieldJsonFromIssue, false);
166 | }
167 | }
168 |
169 | /**
170 | * Check the required (or optional) parameters. If any parameter missing or conflict return with
171 | * the right Response what describes the problem. If everything is right then return with null.
172 | *
173 | * @param startDate
174 | * The startDate parameter.
175 | * @param endDate
176 | * The endDate parameter.
177 | * @param user
178 | * The user parameter.
179 | * @param group
180 | * The group parameter.
181 | *
182 | * @return If a bad parameter was found then return with Response else null.
183 | */
184 | private void checkRequiredFindWorklogsByIssuesParameter(final String startDate,
185 | final String endDate,
186 | final String user, final String group) {
187 | if (isStringEmpty(startDate)) {
188 | throw new RESTException(Response.Status.BAD_REQUEST, "The 'startDate' parameter is missing!");
189 | }
190 | if (isStringEmpty(endDate)) {
191 | throw new RESTException(Response.Status.BAD_REQUEST, "The 'endDate' parameter is missing!");
192 | }
193 | if ((isStringEmpty(user)) && (isStringEmpty(group))) {
194 | throw new RESTException(Response.Status.BAD_REQUEST,
195 | "The 'user' or the 'group' parameter is missing!");
196 | }
197 | if ((!isStringEmpty(user)) && (!isStringEmpty(group))) {
198 | throw new RESTException(Response.Status.BAD_REQUEST,
199 | "The 'user' and the 'group' parameters cannot be present at the same time.");
200 | }
201 | }
202 |
203 | /**
204 | * Check the required (or optional) parameters. If any parameter missing or conflict return with
205 | * the right Response what describes the problem. If everything is right then return with null.
206 | *
207 | * @param startDate
208 | * The findWorklogs startDate parameter.
209 | * @param user
210 | * The findWorklogs user parameter.
211 | * @param group
212 | * The findWorklogs group parameter.
213 | * @return If find bad parameter then return with Response else null.
214 | */
215 | private Response checkRequiredFindWorklogsParameter(final String startDate, final String user,
216 | final String group) {
217 | if (isStringEmpty(startDate)) {
218 | return Response.status(Response.Status.BAD_REQUEST)
219 | .entity("The 'startDate' parameter is missing!").build();
220 | }
221 | if ((isStringEmpty(user)) && (isStringEmpty(group))) {
222 | return Response.status(Response.Status.BAD_REQUEST)
223 | .entity("The 'user' or the 'group' parameter is missing!").build();
224 | }
225 | if ((!isStringEmpty(user)) && (!isStringEmpty(group))) {
226 | return Response.status(Response.Status.BAD_REQUEST)
227 | .entity("The 'user' and the 'group' parameters cannot be present at the same time.")
228 | .build();
229 | }
230 | return null;
231 | }
232 |
233 | private Map collectIssueIds(final List issues) {
234 | Map result = new HashMap<>();
235 | for (Issue issue : issues) {
236 | result.put(issue.getId(), issue);
237 | }
238 | return result;
239 | }
240 |
241 | /**
242 | * Convert the endDate String to Calendar.
243 | *
244 | * @param endDateString
245 | * The endDate parameter.
246 | * @return The formated, valid calendar.
247 | * @throws ParseException
248 | * If cannot parse the String to Calendar.
249 | */
250 | private Calendar convertEndDate(final String endDateString) throws WorklogQueryException {
251 | Calendar endDate;
252 | if ((endDateString == null) || (endDateString.length() == 0)) {
253 | endDate = Calendar.getInstance();
254 | } else {
255 | try {
256 | endDate = DateTimeConverterUtil.inputStringToCalendar(endDateString);
257 | } catch (ParseException e) {
258 | LOGGER.error("Failed to convert end date", e);
259 | throw new WorklogQueryException("Cannot parse the 'endDate' parameter: " + endDateString,
260 | e);
261 | }
262 | }
263 | endDate = DateTimeConverterUtil.setCalendarHourMinSec(endDate,
264 | LAST_HOUR_OF_DAY, LAST_MINUTE_OF_HOUR, LAST_SECOND_OF_MINUTE);
265 | return endDate;
266 | }
267 |
268 | /**
269 | * Convert the startDate String to Calendar.
270 | *
271 | * @param startDateString
272 | * The startDate parameter.
273 | * @return The formated, valid calendar.
274 | * @throws ParseException
275 | * Id cannot parse the String to Calendar.
276 | */
277 | private Calendar convertStartDate(final String startDateString) throws WorklogQueryException {
278 | Calendar startDate;
279 | try {
280 | startDate = DateTimeConverterUtil.inputStringToCalendar(startDateString);
281 | } catch (ParseException e) {
282 | LOGGER.error("Failed to convert start date", e);
283 | throw new WorklogQueryException("Cannot parse the 'startDate' parameter: " + startDateString,
284 | e);
285 | }
286 | startDate = DateTimeConverterUtil.setCalendarHourMinSec(startDate, 0, 0, 0);
287 | return startDate;
288 | }
289 |
290 | /**
291 | * Creates a list of project Id's. Filtering based on project permission and the query
292 | * projectString parameter.
293 | *
294 | * @param projectString
295 | * The query projectString parameter.
296 | * @param user
297 | * The logged user.
298 | *
299 | * @return The list of the issues conditions.
300 | */
301 | private List createProjects(final String projectString, final ApplicationUser user) {
302 |
303 | Collection projects = ComponentAccessor.getPermissionManager()
304 | .getProjects(ProjectPermissions.BROWSE_PROJECTS, user);
305 |
306 | List projectList = new ArrayList<>();
307 | for (Project project : projects) {
308 | if ((projectString != null) && (projectString.length() != 0)) {
309 | if (projectString.equals(project.getKey())) {
310 | projectList.add(project.getId());
311 | }
312 | } else {
313 | projectList.add(project.getId());
314 | }
315 | }
316 | return projectList;
317 | }
318 |
319 | private List createUsers(final String userName, final String group) {
320 | List users = new ArrayList<>();
321 | if ((group != null) && (group.length() != 0)) {
322 | Set groupUsers = ComponentAccessor.getUserUtil()
323 | .getAllUsersInGroupNames(
324 | Arrays.asList(new String[] { group }));
325 | for (ApplicationUser groupUser : groupUsers) {
326 | users.add(groupUser.getKey());
327 | }
328 | } else if ((userName != null) && (userName.length() != 0)) {
329 | ApplicationUser user = ComponentAccessor.getUserManager().getUserByName(userName);
330 | if (user != null) {
331 | users.add(user.getKey());
332 | }
333 | }
334 | return users;
335 | }
336 |
337 | /**
338 | * The findUpdatedWorklogs REST method core implementation.
339 | *
340 | * @param startDate
341 | * The start Date parameter of the REST.
342 | * @param endDate
343 | * The end Date parameter of the REST.
344 | * @param user
345 | * The user parameter of the REST.
346 | * @param group
347 | * The group parameter of the REST.
348 | * @param project
349 | * The project parameter of the REST.
350 | * @param fields
351 | * The fields parameter of the REST.
352 | * @return The founded worklogs.
353 | *
354 | */
355 | @Override
356 | public Response findUpdatedWorklogs(final String startDate, final String endDate,
357 | final String user, final String group,
358 | final String project, final List fields) throws WorklogQueryException {
359 | Response checkRequiredFindWorklogsParamResponse = checkRequiredFindWorklogsParameter(startDate,
360 | user, group);
361 | if (checkRequiredFindWorklogsParamResponse != null) {
362 | return checkRequiredFindWorklogsParamResponse;
363 | }
364 | Calendar startDateCalendar = convertStartDate(startDate);
365 | Calendar endDateCalendar = convertEndDate(endDate);
366 | try {
367 | return worklogQuery(startDateCalendar, endDateCalendar, user, group, project, fields, true);
368 | } catch (Exception e) {
369 | LOGGER.error("Failed to query the worklogs", e);
370 | return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
371 | .entity(e.getMessage()).build();
372 | }
373 | }
374 |
375 | /**
376 | * The findWorklogs REST method core implementation.
377 | *
378 | * @param startDate
379 | * The start Date parameter of the REST.
380 | * @param endDate
381 | * The end Date parameter of the REST.
382 | * @param user
383 | * The user parameter of the REST.
384 | * @param group
385 | * The group parameter of the REST.
386 | * @param project
387 | * The project parameter of the REST.
388 | * @param fields
389 | * The fields parameter of the REST.
390 | * @return The founded worklogs.
391 | */
392 | @Override
393 | public Response findWorklogs(final String startDate, final String endDate, final String user,
394 | final String group, final String project, final List fields)
395 | throws WorklogQueryException {
396 | Response checkRequiredFindWorklogsParamResponse = checkRequiredFindWorklogsParameter(startDate,
397 | user, group);
398 | if (checkRequiredFindWorklogsParamResponse != null) {
399 | return checkRequiredFindWorklogsParamResponse;
400 | }
401 | Calendar startDateCalendar = convertStartDate(startDate);
402 | Calendar endDateCalendar = convertEndDate(endDate);
403 | try {
404 | return worklogQuery(startDateCalendar, endDateCalendar, user, group, project, fields, false);
405 | } catch (Exception e) {
406 | LOGGER.error("Failed to query the worklogs", e);
407 | return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
408 | .entity(e.getMessage()).build();
409 | }
410 | }
411 |
412 | /**
413 | *
414 | * The findWorklogsByIssues REST method core implementation.
415 | *
416 | * @param findWorklogsByIssuesParam
417 | * The parameters object of the findWorklogsByIssues method parameters.
418 | * @return The search result.
419 | */
420 | @Override
421 | public SearchResultsBeanWithTimespent findWorklogsByIssues(
422 | final FindWorklogsByIssuesParam findWorklogsByIssuesParam)
423 | throws WorklogQueryException {
424 | int tmpStartAt = findWorklogsByIssuesParam.startAt;
425 | int tmpMaxResults = findWorklogsByIssuesParam.maxResults;
426 | checkRequiredFindWorklogsByIssuesParameter(findWorklogsByIssuesParam.startDate,
427 | findWorklogsByIssuesParam.endDate, findWorklogsByIssuesParam.user,
428 | findWorklogsByIssuesParam.group);
429 |
430 | Calendar startDateCalendar = convertStartDate(findWorklogsByIssuesParam.startDate);
431 | Calendar endDateCalendar = convertEndDate(findWorklogsByIssuesParam.endDate);
432 | if (tmpStartAt < 0) {
433 | tmpStartAt = DEFAULT_STARTAT_PARAM;
434 | }
435 | if (tmpMaxResults < 0) {
436 | tmpMaxResults = DEFAULT_MAXRESULT_PARAM;
437 | }
438 | List users =
439 | createUsers(findWorklogsByIssuesParam.user, findWorklogsByIssuesParam.group);
440 | if (users.isEmpty()) {
441 | throw new WorklogQueryException(
442 | "Error running search: There is no group or user matching the given parameters.");
443 | }
444 | List issues = null;
445 | try {
446 | issues = getIssuesByJQL(findWorklogsByIssuesParam.jql);
447 | } catch (SearchException e) {
448 | LOGGER.error("Failed to query the worklogs", e);
449 | throw new WorklogQueryException("Error running search: ", e);
450 | } catch (JqlParseException e) {
451 | LOGGER.error("Failed to parse the JQL", e);
452 | throw new WorklogQueryException(e.getMessage(), e);
453 | }
454 |
455 | Map issueIdIssue = collectIssueIds(issues);
456 |
457 | List issueBeans = null;
458 | try {
459 | String jiraBaseUrl = ComponentAccessor.getApplicationProperties()
460 | .getString(APKeys.JIRA_BASEURL) + "/rest/api/2/issue/";
461 | issueBeans = querydslSupport.execute(new FindWorklogsByIssuesQuery(startDateCalendar,
462 | endDateCalendar, users, issueIdIssue.keySet(), tmpStartAt, tmpMaxResults, jiraBaseUrl));
463 |
464 | addFieldsToIssueBeans(findWorklogsByIssuesParam.fields, issueIdIssue, issueBeans);
465 | } catch (Exception e) {
466 | LOGGER.error("Error when try collectig issue beans.", e);
467 | throw new WorklogQueryException("Error when try collectig issue beans.", e);
468 | }
469 | SearchResultsBeanWithTimespent searchResultsBean =
470 | new SearchResultsBeanWithTimespent(tmpStartAt, tmpMaxResults, issueBeans.size(),
471 | issueBeans);
472 |
473 | return searchResultsBean;
474 | }
475 |
476 | private FieldJsonRepresentation getFieldValue(final FieldLayoutItem fieldLayoutItem,
477 | final Issue issue) {
478 | OrderableField> field = fieldLayoutItem.getOrderableField();
479 |
480 | if (field instanceof RestAwareField) {
481 | RestAwareField restAware = (RestAwareField) field;
482 | return restAware.getJsonFromIssue(issue, false, fieldLayoutItem);
483 | } else {
484 | return null;
485 | }
486 | }
487 |
488 | /**
489 | * Returns the selected issues based on the given JQL filter.
490 | *
491 | * @param jql
492 | * JQL filter the search is based on.
493 | * @return List of the matching JIRA Issues.
494 | * @throws SearchException
495 | * Atlassian Search Service excaption.
496 | * @throws JqlParseException
497 | * Thrown when the given JQL is not valid.
498 | */
499 | private List getIssuesByJQL(final String jql)
500 | throws SearchException,
501 | JqlParseException {
502 | JiraAuthenticationContext authenticationContext = ComponentAccessor
503 | .getJiraAuthenticationContext();
504 | ApplicationUser loggedInUser = authenticationContext.getLoggedInUser();
505 | List issues = null;
506 | SearchService searchService = ComponentAccessor.getComponentOfType(SearchService.class);
507 | ParseResult parseResult = searchService.parseQuery(loggedInUser, jql);
508 | if (parseResult.isValid()) {
509 | SearchResults results = searchService.search(loggedInUser,
510 | parseResult.getQuery(), PagerFilter.getUnlimitedFilter());
511 | issues = results.getResults();
512 | } else {
513 | throw new JqlParseException(null, parseResult.getErrors().toString());
514 | }
515 | return issues;
516 | }
517 |
518 | /**
519 | * Check the given String is empty.
520 | *
521 | * @param theString
522 | * The String variable.
523 | * @return If the String is null or the String length equals whit 0 then true, else false.
524 | */
525 | private boolean isStringEmpty(final String theString) {
526 | if ((theString == null) || (theString.length() == 0)) {
527 | return true;
528 | }
529 | return false;
530 | }
531 |
532 | /**
533 | * The method to query worklogs.
534 | *
535 | * @param startDate
536 | * The startDate calendar parameter.
537 | * @param endDate
538 | * The endDate calendar parameter.
539 | * @param userString
540 | * The user String parameter.
541 | * @param groupString
542 | * The group String parameter.
543 | * @param projectString
544 | * The project String parameter.
545 | * @param updated
546 | * True if the method give back the worklogs which were created or updated in the given
547 | * period, else false. The false give back the worklogs of the period.
548 | * @return JSONString what contains a list of queried worklogs.
549 | */
550 | private Response worklogQuery(final Calendar startDate, final Calendar endDate,
551 | final String userString, final String groupString, final String projectString,
552 | final List fields, final boolean updated) {
553 |
554 | JiraAuthenticationContext authenticationContext = ComponentAccessor
555 | .getJiraAuthenticationContext();
556 | ApplicationUser loggedInUser = authenticationContext.getLoggedInUser();
557 |
558 | List projects = createProjects(projectString, loggedInUser);
559 | if ((projectString != null) && projects.isEmpty()) {
560 | return Response
561 | .status(Response.Status.BAD_REQUEST)
562 | .entity(
563 | "Error running search: There is no project matching the given 'project' parameter: "
564 | + projectString)
565 | .build();
566 | }
567 |
568 | List users = createUsers(userString, groupString);
569 | if (users.isEmpty()) {
570 | return Response.status(Response.Status.BAD_REQUEST)
571 | .entity("Error running search: There is no group or user matching the given parameters.")
572 | .build();
573 | }
574 |
575 | List jsonWorklogs =
576 | querydslSupport.execute(new FindWorklogsQuery(startDate, endDate, fields,
577 | users, projects, updated));
578 | JSONArray jsonArrayResult = new JSONArray();
579 | jsonArrayResult.put(jsonWorklogs);
580 |
581 | return Response.ok(jsonArrayResult.toString()).build();
582 | }
583 |
584 | }
585 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/WorklogQueryException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin;
17 |
18 | /**
19 | * The exception to handle Worklog Query Plugin exceptions.
20 | */
21 | public class WorklogQueryException extends RuntimeException {
22 |
23 | /**
24 | * The generated serial version UID.
25 | */
26 | private static final long serialVersionUID = -3704417971282723535L;
27 |
28 | /**
29 | * The simple constructor.
30 | *
31 | * @param msg
32 | * the detail message.
33 | */
34 | protected WorklogQueryException(final String msg) {
35 | super(msg);
36 | }
37 |
38 | /**
39 | * The simple constructor.
40 | *
41 | * @param msg
42 | * the detail message.
43 | * @param cause
44 | * the cause.
45 | */
46 | protected WorklogQueryException(final String msg, final Throwable cause) {
47 | super(msg, cause);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/WorklogQueryResource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin;
17 |
18 | import java.util.List;
19 |
20 | import javax.ws.rs.DefaultValue;
21 | import javax.ws.rs.GET;
22 | import javax.ws.rs.Path;
23 | import javax.ws.rs.Produces;
24 | import javax.ws.rs.QueryParam;
25 | import javax.ws.rs.core.MediaType;
26 | import javax.ws.rs.core.Response;
27 |
28 | import com.atlassian.jira.rest.api.util.StringList;
29 |
30 | /**
31 | * The WorklogQueryResource class. The class contains the findWorklogs method. The class grant the
32 | * JIRA worklog query.
33 | *
34 | */
35 | @Path("/find")
36 | public class WorklogQueryResource {
37 |
38 | private final WorklogQueryCore worklogQueryResource = new WorklogQueryCoreImpl();
39 |
40 | /**
41 | * The updatedWorklogs restful api method.
42 | *
43 | * @param startDate
44 | * The query startDate parameter.
45 | * @param endDate
46 | * The query endDate parameter, optional. Default value is the current time.
47 | * @param user
48 | * The query user parameter, optional. This or the group parameter is required.
49 | * @param group
50 | * The query group parameter, optional. This or the user parameter is required.
51 | * @param project
52 | * The query project parameter, optional. Default is all project.
53 | * @return {@link Response} what contains the result of the query. If the method parameters was
54 | * wrong then a message what contains the description of the bad request. In case of any
55 | * exception return {@link Response} with INTERNAL_SERVER_ERROR status what contains the
56 | * original exception message.
57 | */
58 | @GET
59 | @Produces("*/*")
60 | @Path("/updatedWorklogs")
61 | public Response findUpdatedWorklogs(
62 | @QueryParam("startDate") final String startDate,
63 | @QueryParam("endDate") final String endDate,
64 | @QueryParam("user") final String user,
65 | @QueryParam("group") final String group,
66 | @QueryParam("project") final String project,
67 | @QueryParam("fields") final List fields) {
68 | try {
69 | return worklogQueryResource.findUpdatedWorklogs(startDate, endDate, user, group, project,
70 | fields);
71 | } catch (WorklogQueryException e) {
72 | return Response.status(Response.Status.BAD_REQUEST)
73 | .entity(e.getMessage()).build();
74 | }
75 | }
76 |
77 | /**
78 | * The worklogs restful api method.
79 | *
80 | * @param startDate
81 | * The query startDate parameter.
82 | * @param endDate
83 | * The query endDate parameter, optional. Default value is the current time.
84 | * @param user
85 | * The query user parameter, optional. This or the group parameter is required.
86 | * @param group
87 | * The query group parameter, optional. This or the user parameter is required.
88 | * @param project
89 | * The query project parameter, optional. Default is all project.
90 | * @return {@link Response} what contains the result of the query. If the method parameters was
91 | * wrong then a message what contains the description of the bad request. In case of any
92 | * exception return {@link Response} with INTERNAL_SERVER_ERROR status what contains the
93 | * original exception message.
94 | */
95 | @GET
96 | @Produces({ MediaType.APPLICATION_JSON })
97 | @Path("/worklogs")
98 | public Response findWorklogs(
99 | @QueryParam("startDate") final String startDate,
100 | @QueryParam("endDate") final String endDate,
101 | @QueryParam("user") final String user,
102 | @QueryParam("group") final String group,
103 | @QueryParam("project") final String project,
104 | @QueryParam("fields") final List fields) {
105 | try {
106 | return worklogQueryResource.findWorklogs(startDate, endDate, user, group, project, fields);
107 | } catch (WorklogQueryException e) {
108 | return Response.status(Response.Status.BAD_REQUEST)
109 | .entity(e.getMessage()).build();
110 | }
111 | }
112 |
113 | /**
114 | * FindWorklogsByIssues REST method.
115 | *
116 | * @param startDate
117 | * The query start date.
118 | * @param endDate
119 | * The query end date.
120 | * @param user
121 | * The searched user. Optional.
122 | * @param group
123 | * The searched group. Optional.
124 | * @param jql
125 | * Plus jql. Default empty String.
126 | * @param startAt
127 | * Start the query result list from this element. Default 0.
128 | * @param maxResults
129 | * Max number of results. Default 25.
130 | * @param fields
131 | * List of the queried fields.
132 | * @return The found worklogs.
133 | */
134 | @GET
135 | @Path("/worklogsByIssues")
136 | @Produces({ MediaType.APPLICATION_JSON })
137 | public Response findWorklogsByIssues(
138 | @QueryParam("startDate") final String startDate,
139 | @QueryParam("endDate") final String endDate,
140 | @QueryParam("user") final String user,
141 | @QueryParam("group") final String group,
142 | @DefaultValue("") @QueryParam("jql") final String jql,
143 | @DefaultValue("0") @QueryParam("startAt") final int startAt,
144 | @DefaultValue("25") @QueryParam("maxResults") final int maxResults,
145 | @DefaultValue("emptyFieldValue") @QueryParam("fields") final List fields) {
146 | FindWorklogsByIssuesParam findWorklogsByIssuesParam =
147 | new FindWorklogsByIssuesParam()
148 | .startDate(startDate)
149 | .endDate(endDate)
150 | .user(user)
151 | .group(group)
152 | .jql(jql)
153 | .startAt(startAt)
154 | .maxResults(maxResults)
155 | .fields(fields);
156 | try {
157 | return Response.ok(worklogQueryResource.findWorklogsByIssues(findWorklogsByIssuesParam))
158 | .build();
159 | } catch (WorklogQueryException e) {
160 | return Response.status(Response.Status.BAD_REQUEST)
161 | .entity(e.getMessage()).build();
162 | }
163 | }
164 |
165 | }
166 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/query/FindWorklogsByIssuesQuery.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin.query;
17 |
18 | import java.sql.Connection;
19 | import java.sql.SQLException;
20 | import java.sql.Timestamp;
21 | import java.util.Calendar;
22 | import java.util.List;
23 | import java.util.Set;
24 |
25 | import org.everit.jira.querydsl.schema.QJiraissue;
26 | import org.everit.jira.querydsl.schema.QProject;
27 | import org.everit.jira.querydsl.schema.QWorklog;
28 | import org.everit.jira.querydsl.support.QuerydslCallable;
29 | import org.everit.jira.worklog.query.plugin.IssueBeanWithTimespent;
30 |
31 | import com.querydsl.core.types.Expression;
32 | import com.querydsl.core.types.Projections;
33 | import com.querydsl.core.types.dsl.Expressions;
34 | import com.querydsl.core.types.dsl.SimpleExpression;
35 | import com.querydsl.core.types.dsl.StringExpression;
36 | import com.querydsl.core.types.dsl.StringExpressions;
37 | import com.querydsl.sql.Configuration;
38 | import com.querydsl.sql.SQLExpressions;
39 | import com.querydsl.sql.SQLQuery;
40 |
41 | /**
42 | * Query to find worklogs by issues.
43 | */
44 | public class FindWorklogsByIssuesQuery implements QuerydslCallable> {
45 |
46 | private final Calendar endDate;
47 |
48 | private final Set issueIds;
49 |
50 | private final String jiraBaseUrl;
51 |
52 | private final long limit;
53 |
54 | private final long offset;
55 |
56 | private final Calendar startDate;
57 |
58 | private final List userKeys;
59 |
60 | /**
61 | * Simple constructor.
62 | *
63 | * @param startDate
64 | * the start date of worklogs.
65 | * @param endDate
66 | * the end date of worklogs
67 | * @param userKeys
68 | * a list of user keys.
69 | * @param issueIds
70 | * a collection of user ids.
71 | * @param offset
72 | * the offset for the query results.
73 | * @param limit
74 | * the limit / max results for the query results.
75 | * @param jiraBaseUrl
76 | * the JIRA base url.
77 | */
78 | public FindWorklogsByIssuesQuery(final Calendar startDate, final Calendar endDate,
79 | final List userKeys, final Set issueIds, final long offset, final long limit,
80 | final String jiraBaseUrl) {
81 | this.endDate = endDate;
82 | this.startDate = startDate;
83 | this.userKeys = userKeys;
84 | this.issueIds = issueIds;
85 | this.offset = offset;
86 | this.limit = limit;
87 | this.jiraBaseUrl = jiraBaseUrl;
88 | }
89 |
90 | @Override
91 | public List call(final Connection connection,
92 | final Configuration configuration)
93 | throws SQLException {
94 | QWorklog worklog = new QWorklog("worklog");
95 | QJiraissue issue = new QJiraissue("issue");
96 | QProject project = new QProject("project");
97 |
98 | Timestamp startTimestamp = new Timestamp(startDate.getTimeInMillis());
99 | Timestamp endTimestamp = new Timestamp(endDate.getTimeInMillis());
100 |
101 | StringExpression issueKey = project.pkey.concat("-").concat(issue.issuenum.stringValue());
102 | SimpleExpression timeworked = SQLExpressions.sum(worklog.timeworked).as("timeworked");
103 | Expression jiraBaseUrlExpression = Expressions.constant(jiraBaseUrl);
104 | StringExpression jiraBaseUrlStringExpression = StringExpressions.ltrim(jiraBaseUrlExpression);
105 |
106 | StringExpression concat = jiraBaseUrlStringExpression.concat(issue.id.stringValue());
107 | return new SQLQuery>(connection, configuration)
108 | .select(Projections.constructor(IssueBeanWithTimespent.class,
109 | issue.id,
110 | issueKey,
111 | concat,
112 | timeworked))
113 | .from(worklog)
114 | .join(issue).on(issue.id.eq(worklog.issueid))
115 | .join(project).on(project.id.eq(issue.project))
116 | .where(worklog.startdate.goe(startTimestamp)
117 | .and(worklog.startdate.lt(endTimestamp))
118 | .and(worklog.author.in(userKeys))
119 | .and(worklog.issueid.in(issueIds)))
120 | .groupBy(issue.id, project.pkey, issue.issuenum)
121 | .offset(offset)
122 | .limit(limit)
123 | .orderBy(issue.id.asc())
124 | .fetch();
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/query/FindWorklogsQuery.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin.query;
17 |
18 | import java.sql.Connection;
19 | import java.sql.SQLException;
20 | import java.sql.Timestamp;
21 | import java.util.Arrays;
22 | import java.util.Calendar;
23 | import java.util.List;
24 |
25 | import org.everit.jira.querydsl.schema.QAppUser;
26 | import org.everit.jira.querydsl.schema.QCwdUser;
27 | import org.everit.jira.querydsl.schema.QJiraissue;
28 | import org.everit.jira.querydsl.schema.QProject;
29 | import org.everit.jira.querydsl.schema.QWorklog;
30 | import org.everit.jira.querydsl.support.QuerydslCallable;
31 |
32 | import com.atlassian.jira.rest.api.util.StringList;
33 | import com.querydsl.core.types.dsl.BooleanExpression;
34 | import com.querydsl.core.types.dsl.StringExpression;
35 | import com.querydsl.sql.Configuration;
36 | import com.querydsl.sql.SQLExpressions;
37 | import com.querydsl.sql.SQLQuery;
38 |
39 | /**
40 | * Query to find worklogs.
41 | */
42 | public class FindWorklogsQuery implements QuerydslCallable> {
43 |
44 | private final Calendar endDate;
45 |
46 | private final List fields;
47 |
48 | private List projectIds;
49 |
50 | private final Calendar startDate;
51 |
52 | private final boolean updated;
53 |
54 | private final List userKeys;
55 |
56 | /**
57 | * Simple constructor.
58 | *
59 | * @param startDate
60 | * the start date of worklogs.
61 | * @param endDate
62 | * the end date of worklogs
63 | * @param fields
64 | * a list of additional fields.
65 | * @param userKeys
66 | * a list of user keys.
67 | * @param projectIds
68 | * a list of project ids.
69 | * @param updated
70 | * True if the method give back the worklogs which were created or updated in the given
71 | * period, else false. The false give back the worklogs of the period.
72 | */
73 | public FindWorklogsQuery(final Calendar startDate, final Calendar endDate,
74 | final List fields, final List userKeys, final List projectIds,
75 | final boolean updated) {
76 | this.startDate = startDate;
77 | this.endDate = endDate;
78 | this.fields = fields;
79 | this.userKeys = userKeys;
80 | this.projectIds = projectIds;
81 | this.updated = updated;
82 | }
83 |
84 | @Override
85 | public List call(final Connection connection, final Configuration configuration)
86 | throws SQLException {
87 | QWorklog worklog = new QWorklog("worklog");
88 | QJiraissue issue = new QJiraissue("issue");
89 | QProject project = new QProject("project");
90 | QCwdUser cwduser = new QCwdUser("cwd_user");
91 | QAppUser appuser = new QAppUser("app_user");
92 |
93 | StringExpression issueKey = project.pkey.concat("-").concat(issue.issuenum.stringValue());
94 |
95 | Timestamp startTimestamp = new Timestamp(startDate.getTimeInMillis());
96 | Timestamp endTimestamp = new Timestamp(endDate.getTimeInMillis());
97 |
98 | List fieldsAsList =
99 | Arrays.asList(StringList.joinLists(fields).toQueryParam().split(","));
100 | final boolean useComment = fieldsAsList.contains("comment");
101 | final boolean useUpdated = fieldsAsList.contains("updated");
102 |
103 | BooleanExpression intervalPredicate = null;
104 | if (updated) {
105 | intervalPredicate = worklog.updated.goe(startTimestamp)
106 | .and(worklog.updated.lt(endTimestamp));
107 | } else {
108 | intervalPredicate = worklog.startdate.goe(startTimestamp)
109 | .and(worklog.startdate.lt(endTimestamp));
110 | }
111 |
112 | return new SQLQuery(connection, configuration)
113 | .select(JsonWorklog.createProjection(worklog.id,
114 | worklog.startdate,
115 | issueKey,
116 | SQLExpressions.select(cwduser.userName)
117 | .from(cwduser)
118 | .join(appuser).on(cwduser.lowerUserName.eq(appuser.lowerUserName))
119 | .where(appuser.userKey.eq(worklog.author))
120 | .distinct(),
121 | worklog.timeworked,
122 | useComment ? worklog.worklogbody : null,
123 | useUpdated ? worklog.updated : null))
124 | .from(worklog)
125 | .join(issue).on(issue.id.eq(worklog.issueid))
126 | .join(project).on(project.id.eq(issue.project))
127 | .where(intervalPredicate
128 | .and(worklog.author.in(userKeys))
129 | .and(issue.project.in(projectIds)))
130 | .orderBy(worklog.id.asc())
131 | .fetch();
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/org/everit/jira/worklog/query/plugin/query/JsonWorklog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.plugin.query;
17 |
18 | import java.sql.Timestamp;
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | import org.everit.jira.worklog.query.plugin.DateTimeConverterUtil;
23 |
24 | import com.atlassian.jira.util.json.JSONException;
25 | import com.atlassian.jira.util.json.JSONObject;
26 | import com.querydsl.core.types.Projections;
27 | import com.querydsl.core.types.QBean;
28 | import com.querydsl.core.types.dsl.DateTimeExpression;
29 | import com.querydsl.core.types.dsl.NumberExpression;
30 | import com.querydsl.core.types.dsl.SimpleExpression;
31 | import com.querydsl.core.types.dsl.StringExpression;
32 | import com.querydsl.sql.SQLQuery;
33 |
34 | /**
35 | * JsonWorklog is an unordered collection of name/value pairs. Contains information of worklog.
36 | */
37 | public class JsonWorklog extends JSONObject {
38 |
39 | private static final String COMMENT = "commentBody";
40 |
41 | private static final String DURATION = "duration";
42 |
43 | private static final String ID = "id";
44 |
45 | private static final String ISSUE_KEY = "issueKey";
46 |
47 | private static final String START_DATE = "startDate";
48 |
49 | private static final String UPDATED = "updated";
50 |
51 | private static final String USER_ID = "userId";
52 |
53 | /**
54 | * Create a JsonWorklog Bean populating projection for the given type and expressions.
55 | *
56 | * @param worklogId
57 | * the id of the worklog expression.
58 | * @param startDate
59 | * the worklog startdate expression.
60 | * @param issueKey
61 | * the issue key expression.
62 | * @param userId
63 | * the user id SQL subquery.
64 | * @param duration
65 | * the worklog duration expression.
66 | * @param comment
67 | * the worklog comment expression.
68 | * @param updated
69 | * the worklog updated date expression.
70 | * @return the JsonWorklog Bean population projection.
71 | */
72 | public static QBean createProjection(final NumberExpression worklogId,
73 | final DateTimeExpression startDate, final StringExpression issueKey,
74 | final SQLQuery userId, final NumberExpression duration,
75 | final StringExpression comment, final DateTimeExpression updated) {
76 |
77 | List> expressionList = new ArrayList>();
78 | expressionList.add(worklogId.as(ID));
79 | expressionList.add(startDate.as(START_DATE));
80 | expressionList.add(issueKey.as(ISSUE_KEY));
81 | expressionList.add(userId.as(USER_ID));
82 | expressionList.add(duration.as(DURATION));
83 | if (comment != null) {
84 | expressionList.add(comment.as(COMMENT));
85 | }
86 | if (updated != null) {
87 | expressionList.add(updated.as(UPDATED));
88 | }
89 |
90 | SimpleExpression>[] expressions = new SimpleExpression>[expressionList.size()];
91 |
92 | return Projections.bean(JsonWorklog.class, expressionList.toArray(expressions));
93 | }
94 |
95 | /**
96 | * Create a JsonWorklog Bean populating projection for the given type and expressions.
97 | *
98 | * @param worklogId
99 | * the id of the worklog expression.
100 | * @param startDate
101 | * the worklog startdate expression.
102 | * @param issueKey
103 | * the issue key expression.
104 | * @param userId
105 | * the user id expression.
106 | * @param duration
107 | * the worklog duration expression.
108 | * @param comment
109 | * the worklog comment expression.
110 | * @param updated
111 | * the worklog updated date expression.
112 | * @return the JsonWorklog Bean population projection.
113 | */
114 | public static QBean createProjection(final NumberExpression worklogId,
115 | final DateTimeExpression startDate, final StringExpression issueKey,
116 | final StringExpression userId, final NumberExpression duration,
117 | final StringExpression comment, final DateTimeExpression updated) {
118 |
119 | List> expressionList = new ArrayList>();
120 | expressionList.add(worklogId.as(ID));
121 | expressionList.add(startDate.as(START_DATE));
122 | expressionList.add(issueKey.as(ISSUE_KEY));
123 | expressionList.add(userId.as(USER_ID));
124 | expressionList.add(duration.as(DURATION));
125 | if (comment != null) {
126 | expressionList.add(comment.as(COMMENT));
127 | }
128 | if (updated != null) {
129 | expressionList.add(updated.as(UPDATED));
130 | }
131 |
132 | SimpleExpression>[] expressions = new SimpleExpression>[expressionList.size()];
133 |
134 | return Projections.bean(JsonWorklog.class, expressionList.toArray(expressions));
135 | }
136 |
137 | public void setCommentBody(final String comment) throws JSONException {
138 | put("comment", comment);
139 | }
140 |
141 | public void setDuration(final long duration) throws JSONException {
142 | put(DURATION, duration);
143 | }
144 |
145 | public void setId(final long id) throws JSONException {
146 | put(ID, Long.valueOf(id));
147 | }
148 |
149 | public void setIssueKey(final String issueKey) throws JSONException {
150 | put(ISSUE_KEY, issueKey);
151 | }
152 |
153 | public void setStartDate(final Timestamp startDate) throws JSONException {
154 | put(START_DATE, DateTimeConverterUtil.stringDateToISO8601FormatString(startDate));
155 | }
156 |
157 | public void setUpdated(final Timestamp updated) throws JSONException {
158 | put(UPDATED, DateTimeConverterUtil.stringDateToISO8601FormatString(updated));
159 | }
160 |
161 | public void setUserId(final String userId) throws JSONException {
162 | put(USER_ID, userId);
163 | }
164 |
165 | }
166 |
--------------------------------------------------------------------------------
/src/main/resources/atlassian-plugin.xml:
--------------------------------------------------------------------------------
1 |
23 |
25 |
26 |
27 | ${project.version}
28 | Query worklogs in JSON format via an authenticated RESTful service. Using the
29 | Worklog Query Plugin is easy to retrieve time tracking data from any application.
30 |
31 |
32 |
33 | true
34 | icons/jwqp16.png
35 | icons/jwqp144.png
36 | icons/e_logo16.png
37 | icons/e_logo72.png
38 |
39 |
40 |
41 | Provides the REST resource for the Worklog Query plugin.
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/main/resources/icons/e_logo16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/everit-org/jira-worklog-query-plugin/d4f167eb6ff4e76a040d98b45d99bcc720cd85f4/src/main/resources/icons/e_logo16.png
--------------------------------------------------------------------------------
/src/main/resources/icons/e_logo72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/everit-org/jira-worklog-query-plugin/d4f167eb6ff4e76a040d98b45d99bcc720cd85f4/src/main/resources/icons/e_logo72.png
--------------------------------------------------------------------------------
/src/main/resources/icons/jwqp144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/everit-org/jira-worklog-query-plugin/d4f167eb6ff4e76a040d98b45d99bcc720cd85f4/src/main/resources/icons/jwqp144.png
--------------------------------------------------------------------------------
/src/main/resources/icons/jwqp16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/everit-org/jira-worklog-query-plugin/d4f167eb6ff4e76a040d98b45d99bcc720cd85f4/src/main/resources/icons/jwqp16.png
--------------------------------------------------------------------------------
/src/test/java/org/everit/jira/worklog/query/test/DatabaseSupport.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.test;
17 |
18 | import java.sql.Connection;
19 | import java.sql.SQLException;
20 | import java.sql.Statement;
21 |
22 | import javax.sql.DataSource;
23 |
24 | public final class DatabaseSupport {
25 |
26 | private static void createAppUserTable(final Statement createStatement) throws SQLException {
27 | createStatement.execute("CREATE TABLE \"PUBLIC\".APP_USER ("
28 | + " ID BIGINT NOT NULL,"
29 | + " USER_KEY VARCHAR(2147483647),"
30 | + " LOWER_USER_NAME VARCHAR(2147483647),"
31 | + " CONSTRAINT PK_APP_USER PRIMARY KEY (ID)"
32 | + " );");
33 | }
34 |
35 | private static void createCwdUserTable(final Statement createStatement) throws SQLException {
36 | createStatement.execute("CREATE TABLE \"PUBLIC\".CWD_USER ("
37 | + " ID BIGINT NOT NULL,"
38 | + " DIRECTORY_ID BIGINT,"
39 | + " USER_NAME VARCHAR(2147483647),"
40 | + " LOWER_USER_NAME VARCHAR(2147483647),"
41 | + " ACTIVE INTEGER,"
42 | + " CREATED_DATE TIMESTAMP,"
43 | + " UPDATED_DATE TIMESTAMP,"
44 | + " FIRST_NAME VARCHAR(2147483647),"
45 | + " LOWER_FIRST_NAME VARCHAR(2147483647),"
46 | + " LAST_NAME VARCHAR(2147483647),"
47 | + " LOWER_LAST_NAME VARCHAR(2147483647),"
48 | + " DISPLAY_NAME VARCHAR(2147483647),"
49 | + " LOWER_DISPLAY_NAME VARCHAR(2147483647),"
50 | + " EMAIL_ADDRESS VARCHAR(2147483647),"
51 | + " LOWER_EMAIL_ADDRESS VARCHAR(2147483647),"
52 | + " CREDENTIAL VARCHAR(2147483647),"
53 | + " DELETED_EXTERNALLY INTEGER,"
54 | + " EXTERNAL_ID VARCHAR(2147483647),"
55 | + " CONSTRAINT PK_CWD_USER PRIMARY KEY (ID)"
56 | + " );");
57 | }
58 |
59 | private static void createJiraIssueTable(final Statement createStatement) throws SQLException {
60 | createStatement.execute("CREATE TABLE \"PUBLIC\".JIRAISSUE ("
61 | + " ID BIGINT NOT NULL,"
62 | + " PKEY VARCHAR(2147483647),"
63 | + " ISSUENUM BIGINT,"
64 | + " PROJECT BIGINT,"
65 | + " REPORTER VARCHAR(2147483647),"
66 | + " ASSIGNEE VARCHAR(2147483647),"
67 | + " CREATOR VARCHAR(2147483647),"
68 | + " ISSUETYPE VARCHAR(2147483647),"
69 | + " SUMMARY VARCHAR(2147483647),"
70 | + " DESCRIPTION VARCHAR(2147483647),"
71 | + " ENVIRONMENT VARCHAR(2147483647),"
72 | + " PRIORITY VARCHAR(2147483647),"
73 | + " RESOLUTION VARCHAR(2147483647),"
74 | + " ISSUESTATUS VARCHAR(2147483647),"
75 | + " CREATED TIMESTAMP,"
76 | + " UPDATED TIMESTAMP,"
77 | + " DUEDATE TIMESTAMP,"
78 | + " RESOLUTIONDATE TIMESTAMP,"
79 | + " VOTES BIGINT,"
80 | + " WATCHES BIGINT,"
81 | + " TIMEORIGINALESTIMATE BIGINT,"
82 | + " TIMEESTIMATE BIGINT,"
83 | + " TIMESPENT BIGINT,"
84 | + " WORKFLOW_ID BIGINT,"
85 | + " \"SECURITY\" BIGINT,"
86 | + " FIXFOR BIGINT,"
87 | + " COMPONENT BIGINT,"
88 | + " CONSTRAINT PK_JIRAISSUE PRIMARY KEY (ID)"
89 | + " );");
90 | }
91 |
92 | private static void createProjectTable(final Statement createStatement) throws SQLException {
93 | createStatement.execute("CREATE TABLE \"PUBLIC\".PROJECT ("
94 | + " ID BIGINT NOT NULL,"
95 | + " PNAME VARCHAR(2147483647),"
96 | + " URL VARCHAR(2147483647),"
97 | + " LEAD VARCHAR(2147483647),"
98 | + " DESCRIPTION VARCHAR(2147483647),"
99 | + " PKEY VARCHAR(2147483647),"
100 | + " PCOUNTER BIGINT,"
101 | + " ASSIGNEETYPE BIGINT,"
102 | + " AVATAR BIGINT,"
103 | + " ORIGINALKEY VARCHAR(2147483647),"
104 | + " PROJECTTYPE VARCHAR(2147483647),"
105 | + " CONSTRAINT PK_PROJECT PRIMARY KEY (ID)"
106 | + " );");
107 | }
108 |
109 | private static void createWorklogTable(final Statement createStatement) throws SQLException {
110 | createStatement.execute("CREATE TABLE \"PUBLIC\".WORKLOG ("
111 | + " ID BIGINT NOT NULL,"
112 | + " ISSUEID BIGINT,"
113 | + " AUTHOR VARCHAR(2147483647),"
114 | + " GROUPLEVEL VARCHAR(2147483647),"
115 | + " ROLELEVEL BIGINT,"
116 | + " WORKLOGBODY VARCHAR(2147483647),"
117 | + " CREATED TIMESTAMP,"
118 | + " UPDATEAUTHOR VARCHAR(2147483647),"
119 | + " UPDATED TIMESTAMP,"
120 | + " STARTDATE TIMESTAMP,"
121 | + " TIMEWORKED BIGINT,"
122 | + " CONSTRAINT PK_WORKLOG PRIMARY KEY (ID)"
123 | + " );");
124 | }
125 |
126 | public static void dropTables(final DataSource datasource) throws SQLException {
127 | try (Connection connection = datasource.getConnection();
128 | Statement createStatement = connection.createStatement();) {
129 | createStatement.execute("DROP TABLE \"PUBLIC\".WORKLOG");
130 | createStatement.execute("DROP TABLE \"PUBLIC\".PROJECT");
131 | createStatement.execute("DROP TABLE \"PUBLIC\".JIRAISSUE");
132 | createStatement.execute("DROP TABLE \"PUBLIC\".CWD_USER");
133 | createStatement.execute("DROP TABLE \"PUBLIC\".APP_USER");
134 | }
135 | }
136 |
137 | public static void initializeDatabase(final DataSource datasource) throws SQLException {
138 | try (Connection connection = datasource.getConnection();
139 | Statement createStatement = connection.createStatement();) {
140 | DatabaseSupport.createWorklogTable(createStatement);
141 |
142 | DatabaseSupport.createJiraIssueTable(createStatement);
143 |
144 | DatabaseSupport.createProjectTable(createStatement);
145 |
146 | DatabaseSupport.createCwdUserTable(createStatement);
147 |
148 | DatabaseSupport.createAppUserTable(createStatement);
149 |
150 | DatabaseSupport.insertJiraIssueRows(createStatement);
151 |
152 | DatabaseSupport.insertWorklogRows(createStatement);
153 |
154 | DatabaseSupport.insertProjectRows(createStatement);
155 |
156 | DatabaseSupport.insertCwdUserRows(createStatement);
157 |
158 | DatabaseSupport.insertAppUserRows(createStatement);
159 | }
160 | }
161 |
162 | private static void insertAppUserRows(final Statement createStatement) throws SQLException {
163 | createStatement.execute("INSERT INTO app_user VALUES (10000, "
164 | + "'test-user@everit.biz', 'test-user@everit.biz');");
165 | }
166 |
167 | private static void insertCwdUserRows(final Statement createStatement) throws SQLException {
168 | createStatement.execute(
169 | "INSERT INTO cwd_user VALUES (10000, 1, 'test-user@everit.biz', "
170 | + "'test-user@everit.biz', 1, '2016-03-07 14:06:16.89', "
171 | + "'2016-03-07 14:06:16.89', 'Zsigmond', 'zsigmond', 'Czine', 'czine', "
172 | + "'Zsigmond Czine', 'zsigmond czine', 'test-user@everit.biz', "
173 | + "'test-user@everit.biz', "
174 | + "'asdf', NULL, "
175 | + "'7c717a76-20bc-4d80-9087-a073e057cf78');");
176 | }
177 |
178 | private static void insertJiraIssueRows(final Statement createStatement) throws SQLException {
179 | createStatement.execute(
180 | "INSERT INTO jiraissue VALUES (10002, NULL, 3, 10000, 'test-user@everit.biz', NULL, "
181 | + "'test-user@everit.biz', '10001', 'harom', NULL, NULL, '3', NULL, '10000', "
182 | + "'2016-03-07 14:07:41.156', '2016-03-07 14:07:41.156', NULL, NULL, 0, 1,"
183 | + " NULL, NULL, NULL, 10002, NULL, NULL, NULL);");
184 | createStatement.execute(
185 | "INSERT INTO jiraissue VALUES (10001, NULL, 2, 10000, 'test-user@everit.biz', NULL, "
186 | + "'test-user@everit.biz', '10001', 'ketto', NULL, NULL, '3', NULL, '10000', "
187 | + "'2016-03-07 14:07:38.683', '2016-03-07 14:08:09.022', NULL, NULL, 0, 1, "
188 | + "NULL, 0, 22020, 10001, NULL, NULL, NULL);");
189 | createStatement.execute(
190 | "INSERT INTO jiraissue VALUES (10003, NULL, 4, 10000, 'test-user@everit.biz', NULL, "
191 | + "'test-user@everit.biz', '10001', 'negy', NULL, NULL, '3', NULL, '10000', "
192 | + "'2016-03-07 14:07:43.854', '2016-03-07 14:08:24.627', NULL, NULL, 0, 1, "
193 | + "NULL, 0, 22080, 10003, NULL, NULL, NULL);");
194 | createStatement.execute(
195 | "INSERT INTO jiraissue VALUES (10004, NULL, 5, 10000, 'test-user@everit.biz', NULL, "
196 | + "'test-user@everit.biz', '10001', 'ot', NULL, NULL, '3', NULL, '10000', "
197 | + "'2016-03-07 14:07:45.756', '2016-03-07 14:08:33.903', NULL, NULL, 0, 1, "
198 | + "NULL, 0, 22080, 10004, NULL, NULL, NULL);");
199 | createStatement.execute(
200 | "INSERT INTO jiraissue VALUES (10000, NULL, 1, 10000, 'test-user@everit.biz', NULL, "
201 | + "'test-user@everit.biz', '10001', 'egy', NULL, NULL, '3', NULL, '10000', "
202 | + "'2016-03-07 14:07:33.368', '2016-03-11 10:46:46.357', NULL, NULL, 0, 1, "
203 | + "NULL, 0, 22020, 10000, NULL, NULL, NULL);");
204 | }
205 |
206 | private static void insertProjectRows(final Statement createStatement) throws SQLException {
207 | createStatement.execute("INSERT INTO project VALUES (10000, 'SAMPLE', '', "
208 | + "'test-user@everit.biz', '', 'SAM', 5, 3, 10324, 'SAM', 'software');");
209 | }
210 |
211 | private static void insertWorklogRows(final Statement createStatement) throws SQLException {
212 | createStatement.execute(
213 | "INSERT INTO worklog VALUES (10001, 10001, 'test-user@everit.biz', NULL, NULL, '', "
214 | + "'2016-03-07 14:08:08.967', 'test-user@everit.biz', '2016-03-07 14:08:08.967', "
215 | + "'2016-03-01 08:00:00', 22020);");
216 | createStatement.execute(
217 | "INSERT INTO worklog VALUES (10002, 10003, 'test-user@everit.biz', NULL, NULL, '', "
218 | + "'2016-03-07 14:08:24.536', 'test-user@everit.biz', '2016-03-07 14:08:24.536', "
219 | + "'2016-02-24 08:00:00', 22080);");
220 | createStatement.execute(
221 | "INSERT INTO worklog VALUES (10003, 10004, 'test-user@everit.biz', NULL, NULL, '', "
222 | + "'2016-03-07 14:08:33.899', 'test-user@everit.biz', '2016-03-07 14:08:33.899', "
223 | + "'2016-02-23 08:00:00', 22080);");
224 | createStatement.execute(
225 | "INSERT INTO worklog VALUES (10000, 10000, 'test-user@everit.biz', NULL, NULL, 'asdfasf', "
226 | + "'2016-03-07 14:07:55.675', 'test-user@everit.biz', '2016-03-11 10:46:46.277', "
227 | + "'2016-03-07 08:00:00', 22020);");
228 | }
229 |
230 | private DatabaseSupport() {
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/src/test/java/org/everit/jira/worklog/query/test/MockTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.test;
17 |
18 | import java.io.IOException;
19 | import java.sql.Array;
20 | import java.sql.Blob;
21 | import java.sql.CallableStatement;
22 | import java.sql.Clob;
23 | import java.sql.Connection;
24 | import java.sql.DatabaseMetaData;
25 | import java.sql.NClob;
26 | import java.sql.PreparedStatement;
27 | import java.sql.SQLClientInfoException;
28 | import java.sql.SQLException;
29 | import java.sql.SQLWarning;
30 | import java.sql.SQLXML;
31 | import java.sql.Savepoint;
32 | import java.sql.Statement;
33 | import java.sql.Struct;
34 | import java.util.ArrayList;
35 | import java.util.List;
36 | import java.util.Map;
37 | import java.util.Properties;
38 | import java.util.TimeZone;
39 | import java.util.concurrent.Executor;
40 |
41 | import javax.sql.XADataSource;
42 | import javax.transaction.xa.XAException;
43 | import javax.ws.rs.core.Response;
44 |
45 | import org.apache.commons.dbcp2.managed.BasicManagedDataSource;
46 | import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
47 | import org.everit.jira.worklog.query.plugin.FindWorklogsByIssuesParam;
48 | import org.everit.jira.worklog.query.plugin.IssueBeanWithTimespent;
49 | import org.everit.jira.worklog.query.plugin.SearchResultsBeanWithTimespent;
50 | import org.everit.jira.worklog.query.plugin.WorklogQueryCoreImpl;
51 | import org.h2.jdbcx.JdbcDataSource;
52 | import org.junit.After;
53 | import org.junit.Assert;
54 | import org.junit.Before;
55 | import org.junit.Test;
56 | import org.junit.runner.RunWith;
57 | import org.mockito.ArgumentMatchers;
58 | import org.mockito.Mockito;
59 | import org.ofbiz.core.entity.config.DatasourceInfo;
60 | import org.powermock.api.mockito.PowerMockito;
61 | import org.powermock.core.classloader.annotations.PowerMockIgnore;
62 | import org.powermock.core.classloader.annotations.PrepareForTest;
63 | import org.powermock.modules.junit4.PowerMockRunner;
64 |
65 | import com.atlassian.jira.bc.issue.search.SearchService;
66 | import com.atlassian.jira.bc.issue.search.SearchService.ParseResult;
67 | import com.atlassian.jira.exception.DataAccessException;
68 | import com.atlassian.jira.issue.Issue;
69 | import com.atlassian.jira.issue.search.SearchException;
70 | import com.atlassian.jira.issue.search.SearchResults;
71 | import com.atlassian.jira.mock.component.MockComponentWorker;
72 | import com.atlassian.jira.mock.issue.MockIssue;
73 | import com.atlassian.jira.ofbiz.DefaultOfBizConnectionFactory;
74 | import com.atlassian.jira.permission.ProjectPermissions;
75 | import com.atlassian.jira.project.Project;
76 | import com.atlassian.jira.rest.api.util.StringList;
77 | import com.atlassian.jira.security.JiraAuthenticationContext;
78 | import com.atlassian.jira.security.PermissionManager;
79 | import com.atlassian.jira.user.ApplicationUser;
80 | import com.atlassian.jira.user.util.UserManager;
81 |
82 | @RunWith(PowerMockRunner.class)
83 | @PowerMockIgnore("javax.security.*")
84 | @PrepareForTest({ DefaultOfBizConnectionFactory.class, DatasourceInfo.class, ParseResult.class })
85 | public class MockTest {
86 |
87 | public class SinkConnection implements Connection {
88 |
89 | private Connection conn;
90 |
91 | @Override
92 | public void abort(final Executor executor) throws SQLException {
93 | getConnection().abort(executor);
94 | }
95 |
96 | @Override
97 | public void clearWarnings() throws SQLException {
98 | getConnection().clearWarnings();
99 | }
100 |
101 | @Override
102 | public void close() throws SQLException {
103 | getConnection().close();
104 | }
105 |
106 | @Override
107 | public void commit() throws SQLException {
108 | getConnection().commit();
109 | }
110 |
111 | @Override
112 | public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException {
113 | return getConnection().createArrayOf(typeName, elements);
114 | }
115 |
116 | @Override
117 | public Blob createBlob() throws SQLException {
118 | return getConnection().createBlob();
119 | }
120 |
121 | @Override
122 | public Clob createClob() throws SQLException {
123 | return getConnection().createClob();
124 | }
125 |
126 | @Override
127 | public NClob createNClob() throws SQLException {
128 | return getConnection().createNClob();
129 | }
130 |
131 | @Override
132 | public SQLXML createSQLXML() throws SQLException {
133 | return getConnection().createSQLXML();
134 | }
135 |
136 | @Override
137 | public Statement createStatement() throws SQLException {
138 | return getConnection().createStatement();
139 | }
140 |
141 | @Override
142 | public Statement createStatement(final int resultSetType, final int resultSetConcurrency)
143 | throws SQLException {
144 | return getConnection().createStatement(resultSetType, resultSetConcurrency);
145 | }
146 |
147 | @Override
148 | public Statement createStatement(final int resultSetType, final int resultSetConcurrency,
149 | final int resultSetHoldability) throws SQLException {
150 | return getConnection().createStatement(resultSetType, resultSetConcurrency,
151 | resultSetHoldability);
152 | }
153 |
154 | @Override
155 | public Struct createStruct(final String typeName, final Object[] attributes)
156 | throws SQLException {
157 | return getConnection().createStruct(typeName, attributes);
158 | }
159 |
160 | @Override
161 | public boolean getAutoCommit() throws SQLException {
162 | return getConnection().getAutoCommit();
163 | }
164 |
165 | @Override
166 | public String getCatalog() throws SQLException {
167 | return getConnection().getCatalog();
168 | }
169 |
170 | @Override
171 | public Properties getClientInfo() throws SQLException {
172 | return getConnection().getClientInfo();
173 | }
174 |
175 | @Override
176 | public String getClientInfo(final String name) throws SQLException {
177 | return getConnection().getClientInfo(name);
178 | }
179 |
180 | private Connection getConnection() {
181 | try {
182 | if ((conn == null) || conn.isClosed()) {
183 | conn = createXADatasource().getConnection();
184 | }
185 | } catch (SQLException e) {
186 | }
187 | return conn;
188 | }
189 |
190 | @Override
191 | public int getHoldability() throws SQLException {
192 | return getConnection().getHoldability();
193 | }
194 |
195 | @Override
196 | public DatabaseMetaData getMetaData() throws SQLException {
197 | return getConnection().getMetaData();
198 | }
199 |
200 | @Override
201 | public int getNetworkTimeout() throws SQLException {
202 | return getConnection().getNetworkTimeout();
203 | }
204 |
205 | @Override
206 | public String getSchema() throws SQLException {
207 | return getConnection().getSchema();
208 | }
209 |
210 | @Override
211 | public int getTransactionIsolation() throws SQLException {
212 | return getConnection().getTransactionIsolation();
213 | }
214 |
215 | @Override
216 | public Map> getTypeMap() throws SQLException {
217 | return getConnection().getTypeMap();
218 | }
219 |
220 | @Override
221 | public SQLWarning getWarnings() throws SQLException {
222 | return getConnection().getWarnings();
223 | }
224 |
225 | @Override
226 | public boolean isClosed() throws SQLException {
227 | return getConnection().isClosed();
228 | }
229 |
230 | @Override
231 | public boolean isReadOnly() throws SQLException {
232 | return getConnection().isReadOnly();
233 | }
234 |
235 | @Override
236 | public boolean isValid(final int timeout) throws SQLException {
237 | return getConnection().isValid(timeout);
238 | }
239 |
240 | @Override
241 | public boolean isWrapperFor(final Class> iface) throws SQLException {
242 | return getConnection().isWrapperFor(iface);
243 | }
244 |
245 | @Override
246 | public String nativeSQL(final String sql) throws SQLException {
247 | return getConnection().nativeSQL(sql);
248 | }
249 |
250 | @Override
251 | public CallableStatement prepareCall(final String sql) throws SQLException {
252 | return getConnection().prepareCall(sql);
253 | }
254 |
255 | @Override
256 | public CallableStatement prepareCall(final String sql, final int resultSetType,
257 | final int resultSetConcurrency)
258 | throws SQLException {
259 | return getConnection().prepareCall(sql, resultSetType, resultSetConcurrency);
260 | }
261 |
262 | @Override
263 | public CallableStatement prepareCall(final String sql, final int resultSetType,
264 | final int resultSetConcurrency,
265 | final int resultSetHoldability) throws SQLException {
266 | return getConnection().prepareCall(sql, resultSetType, resultSetConcurrency,
267 | resultSetHoldability);
268 | }
269 |
270 | @Override
271 | public PreparedStatement prepareStatement(final String sql) throws SQLException {
272 | return getConnection().prepareStatement(sql);
273 | }
274 |
275 | @Override
276 | public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys)
277 | throws SQLException {
278 | return getConnection().prepareStatement(sql, autoGeneratedKeys);
279 | }
280 |
281 | @Override
282 | public PreparedStatement prepareStatement(final String sql, final int resultSetType,
283 | final int resultSetConcurrency) throws SQLException {
284 | return getConnection().prepareStatement(sql, resultSetType, resultSetConcurrency);
285 | }
286 |
287 | @Override
288 | public PreparedStatement prepareStatement(final String sql, final int resultSetType,
289 | final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
290 | return getConnection().prepareCall(sql, resultSetType, resultSetConcurrency,
291 | resultSetHoldability);
292 | }
293 |
294 | @Override
295 | public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes)
296 | throws SQLException {
297 | return getConnection().prepareStatement(sql, columnIndexes);
298 | }
299 |
300 | @Override
301 | public PreparedStatement prepareStatement(final String sql, final String[] columnNames)
302 | throws SQLException {
303 | return getConnection().prepareStatement(sql, columnNames);
304 | }
305 |
306 | @Override
307 | public void releaseSavepoint(final Savepoint savepoint) throws SQLException {
308 | getConnection().releaseSavepoint(savepoint);
309 | }
310 |
311 | @Override
312 | public void rollback() throws SQLException {
313 | getConnection().rollback();
314 | }
315 |
316 | @Override
317 | public void rollback(final Savepoint savepoint) throws SQLException {
318 | getConnection().rollback(savepoint);
319 | }
320 |
321 | @Override
322 | public void setAutoCommit(final boolean autoCommit) throws SQLException {
323 | getConnection().setAutoCommit(autoCommit);
324 | }
325 |
326 | @Override
327 | public void setCatalog(final String catalog) throws SQLException {
328 | getConnection().setCatalog(catalog);
329 | }
330 |
331 | @Override
332 | public void setClientInfo(final Properties properties) throws SQLClientInfoException {
333 | getConnection().setClientInfo(properties);
334 | }
335 |
336 | @Override
337 | public void setClientInfo(final String name, final String value) throws SQLClientInfoException {
338 | getConnection().setClientInfo(name, value);
339 | }
340 |
341 | @Override
342 | public void setHoldability(final int holdability) throws SQLException {
343 | getConnection().setHoldability(holdability);
344 | }
345 |
346 | @Override
347 | public void setNetworkTimeout(final Executor executor, final int milliseconds)
348 | throws SQLException {
349 | getConnection().setNetworkTimeout(executor, milliseconds);
350 | }
351 |
352 | @Override
353 | public void setReadOnly(final boolean readOnly) throws SQLException {
354 | getConnection().setReadOnly(readOnly);
355 | }
356 |
357 | @Override
358 | public Savepoint setSavepoint() throws SQLException {
359 | return getConnection().setSavepoint();
360 | }
361 |
362 | @Override
363 | public Savepoint setSavepoint(final String name) throws SQLException {
364 | return getConnection().setSavepoint(name);
365 | }
366 |
367 | @Override
368 | public void setSchema(final String schema) throws SQLException {
369 | getConnection().setSchema(schema);
370 | }
371 |
372 | @Override
373 | public void setTransactionIsolation(final int level) throws SQLException {
374 | getConnection().setTransactionIsolation(level);
375 | }
376 |
377 | @Override
378 | public void setTypeMap(final Map> map) throws SQLException {
379 | getConnection().setTypeMap(map);
380 | }
381 |
382 | @Override
383 | public T unwrap(final Class iface) throws SQLException {
384 | return getConnection().unwrap(iface);
385 | }
386 |
387 | }
388 |
389 | private static final long N_10000 = 10000L;
390 |
391 | private BasicManagedDataSource managedDataSource = null;
392 |
393 | private String TEST_USER = "test-user@everit.biz";
394 |
395 | private WorklogQueryCoreImpl worklogQuery;
396 |
397 | @After
398 | public void after() throws SQLException {
399 | DatabaseSupport.dropTables(managedDataSource);
400 |
401 | if (managedDataSource != null) {
402 | try {
403 | managedDataSource.close();
404 | } catch (SQLException e) {
405 | throw new RuntimeException(e);
406 | }
407 | }
408 | }
409 |
410 | @Before
411 | public void before() throws DataAccessException, SQLException, SearchException {
412 | GeronimoTransactionManager transactionManager = null;
413 | try {
414 | transactionManager = new GeronimoTransactionManager(6000);
415 | } catch (XAException e) {
416 | throw new RuntimeException(e);
417 | }
418 |
419 | managedDataSource = createManagedDataSource(transactionManager, createXADatasource());
420 |
421 | ApplicationUser testUser = mockApplicationUser();
422 | Project project = mockProject();
423 |
424 | JiraAuthenticationContext jiraAuthenticationContext = mockJiraAuthenticationContext(testUser);
425 |
426 | PermissionManager permissionManager = mockPermissionManager(testUser, project);
427 |
428 | UserManager userManager = mockUserManager(testUser);
429 |
430 | SearchService searchService = Mockito.mock(SearchService.class);
431 | PowerMockito.mockStatic(ParseResult.class);
432 | ParseResult parseResult = Mockito.mock(ParseResult.class);
433 | Mockito.when(searchService.parseQuery(testUser, "")).thenReturn(parseResult);
434 | Mockito.when(parseResult.isValid()).thenReturn(Boolean.TRUE);
435 |
436 | SearchResults searchResults = Mockito.mock(SearchResults.class);
437 | List issues = new ArrayList<>();
438 | issues.add(new MockIssue(10000));
439 | issues.add(new MockIssue(10001));
440 | issues.add(new MockIssue(10002));
441 | issues.add(new MockIssue(10003));
442 | issues.add(new MockIssue(10004));
443 | Mockito.when(searchResults.getResults()).thenReturn(issues);
444 |
445 | // Mockito.when(
446 | // searchService.search(ArgumentMatchers.any(ApplicationUser.class),
447 | // ArgumentMatchers.any(Query.class),
448 | // ArgumentMatchers.any(PagerFilter.class)))
449 | Mockito.when(
450 | searchService.search(ArgumentMatchers.any(),
451 | ArgumentMatchers.any(),
452 | ArgumentMatchers.any()))
453 | .thenReturn(searchResults);
454 |
455 | mockDefaultOfBizConnectionFactory();
456 |
457 | new MockComponentWorker()
458 | .addMock(JiraAuthenticationContext.class, jiraAuthenticationContext)
459 | .addMock(PermissionManager.class, permissionManager)
460 | .addMock(UserManager.class, userManager)
461 | .addMock(SearchService.class, searchService)
462 | .init();
463 |
464 | worklogQuery = new WorklogQueryCoreImpl();
465 | DatabaseSupport.initializeDatabase(managedDataSource);
466 |
467 | System.setProperty("user.timezone", "UTC");
468 | TimeZone.setDefault(null);
469 | }
470 |
471 | private BasicManagedDataSource createManagedDataSource(
472 | final GeronimoTransactionManager transactionManager, final XADataSource xaDataSource) {
473 | BasicManagedDataSource lManagedDataSource = new BasicManagedDataSource();
474 | lManagedDataSource.setTransactionManager(transactionManager);
475 | lManagedDataSource.setXaDataSourceInstance(xaDataSource);
476 | return lManagedDataSource;
477 | }
478 |
479 | private JdbcDataSource createXADatasource() {
480 | JdbcDataSource xaDatasource = new JdbcDataSource();
481 | xaDatasource.setURL("jdbc:h2:mem:test");
482 | // xaDatasource.setURL("jdbc:h2:tcp://localhost:9092/~/test");
483 | xaDatasource.setUser("sa");
484 | xaDatasource.setPassword("");
485 | return xaDatasource;
486 | }
487 |
488 | private Properties loadExpectedResultProperties() throws IOException {
489 | Properties properties = new Properties();
490 | properties.load(this.getClass().getResourceAsStream("/expectedResults.properties"));
491 | return properties;
492 | }
493 |
494 | private ApplicationUser mockApplicationUser() {
495 | ApplicationUser testUser = Mockito.mock(ApplicationUser.class);
496 | Mockito.when(testUser.getKey()).thenReturn(TEST_USER);
497 | Mockito.when(testUser.getId()).thenReturn(N_10000);
498 | return testUser;
499 | }
500 |
501 | private void mockDefaultOfBizConnectionFactory() throws SQLException {
502 | PowerMockito.mockStatic(DefaultOfBizConnectionFactory.class);
503 | DefaultOfBizConnectionFactory defaultOfBizConnectionFactory =
504 | Mockito.mock(DefaultOfBizConnectionFactory.class);
505 | PowerMockito.when(DefaultOfBizConnectionFactory.getInstance())
506 | .thenReturn(defaultOfBizConnectionFactory);
507 |
508 | PowerMockito.mockStatic(DatasourceInfo.class);
509 | DatasourceInfo datasourceInfo = Mockito.mock(DatasourceInfo.class);
510 | PowerMockito.when(defaultOfBizConnectionFactory.getDatasourceInfo()).thenReturn(datasourceInfo);
511 | Mockito.when(datasourceInfo.getSchemaName()).thenReturn("PUBLIC");
512 | Mockito.when(defaultOfBizConnectionFactory.getConnection())
513 | .thenReturn(new SinkConnection());
514 | }
515 |
516 | private JiraAuthenticationContext mockJiraAuthenticationContext(final ApplicationUser testUser) {
517 | JiraAuthenticationContext jiraAuthenticationContext =
518 | Mockito.mock(JiraAuthenticationContext.class);
519 | Mockito.when(jiraAuthenticationContext.getLoggedInUser()).thenReturn(testUser);
520 | return jiraAuthenticationContext;
521 | }
522 |
523 | private PermissionManager mockPermissionManager(final ApplicationUser testUser,
524 | final Project project) {
525 | ArrayList projects = new ArrayList<>();
526 | projects.add(project);
527 | PermissionManager permissionManager = Mockito.mock(PermissionManager.class);
528 | Mockito.when(permissionManager.getProjects(ProjectPermissions.BROWSE_PROJECTS, testUser))
529 | .thenReturn(projects);
530 | return permissionManager;
531 | }
532 |
533 | private Project mockProject() {
534 | Project project = Mockito.mock(Project.class);
535 | Mockito.when(project.getId()).thenReturn(N_10000);
536 | Mockito.when(project.getKey()).thenReturn("SAM");
537 | return project;
538 | }
539 |
540 | private UserManager mockUserManager(final ApplicationUser testUser) {
541 | UserManager userManager = Mockito.mock(UserManager.class);
542 | Mockito.when(userManager.getUserByName(TEST_USER)).thenReturn(testUser);
543 | return userManager;
544 | }
545 |
546 | @Test
547 | public void testFindWorklogs() throws IOException {
548 | Response findWorklogs = worklogQuery.findWorklogs("2016-02-24", "2016-03-12", TEST_USER, "", "",
549 | new ArrayList());
550 | String json = findWorklogs.getEntity().toString();
551 | Properties properties = loadExpectedResultProperties();
552 | Assert.assertEquals(properties.get("findWorklogs"), json);
553 | }
554 |
555 | @Test
556 | public void testUpdateWorklogs() throws IOException {
557 | Response findUpdatedWorklogs =
558 | worklogQuery.findUpdatedWorklogs("2016-02-24", "2016-03-12", TEST_USER, "", "",
559 | new ArrayList());
560 | String json = findUpdatedWorklogs.getEntity().toString();
561 | Properties properties = loadExpectedResultProperties();
562 | Assert.assertEquals(properties.get("findUpdatedWorklogs"), json);
563 | }
564 |
565 | @Test
566 | public void testWorklogsByIssues() throws IOException {
567 | List fields = new ArrayList<>();
568 | fields.add(StringList.fromList("emptyFieldValue"));
569 | FindWorklogsByIssuesParam findWorklogsByIssuesParam = new FindWorklogsByIssuesParam()
570 | .startDate("2016-02-24")
571 | .endDate("2016-03-12")
572 | .user(TEST_USER)
573 | .jql("")
574 | .startAt(0)
575 | .maxResults(25)
576 | .fields(fields);
577 | SearchResultsBeanWithTimespent findWorklogsByIssues =
578 | worklogQuery.findWorklogsByIssues(findWorklogsByIssuesParam);
579 |
580 | Assert.assertEquals(3, findWorklogsByIssues.total.intValue());
581 | List issues = findWorklogsByIssues.getIssues();
582 | Assert.assertEquals("10000", issues.get(0).getId());
583 | Assert.assertEquals("SAM-1", issues.get(0).getKey());
584 | Assert.assertEquals("10001", issues.get(1).getId());
585 | Assert.assertEquals("SAM-2", issues.get(1).getKey());
586 | Assert.assertEquals("10003", issues.get(2).getId());
587 | Assert.assertEquals("SAM-4", issues.get(2).getKey());
588 | }
589 | }
590 |
--------------------------------------------------------------------------------
/src/test/java/org/everit/jira/worklog/query/test/WorklogQueryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.everit.jira.worklog.query.test;
17 |
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | import com.sun.jersey.api.client.Client;
22 | import com.sun.jersey.api.client.ClientResponse;
23 | import com.sun.jersey.api.client.WebResource;
24 | import com.sun.jersey.core.util.Base64;
25 |
26 | /**
27 | * The WorklogQueryTest class help test the plugin authorization and the plugin query.
28 | */
29 | public final class WorklogQueryTest {
30 | /**
31 | * The logger used to log.
32 | */
33 | private static final Logger LOGGER = LoggerFactory.getLogger(WorklogQueryTest.class);
34 |
35 | /**
36 | * The status code of the unsuccessful authorization.
37 | */
38 | public static final int INVALID_AUTHOR_STATUS = 401;
39 | /**
40 | * The user name for authentication.
41 | */
42 | public static final String USERNAME = "admin";
43 | /**
44 | * The password for authentication.
45 | */
46 | public static final String PASSWORD = "admin_ps";
47 |
48 | /**
49 | * The WorklogQueryTest class main method.
50 | *
51 | * @param args
52 | * The main args.
53 | */
54 | public static void main(final String[] args) {
55 | try {
56 | WorklogQueryTest.simpleClientTest();
57 | WorklogQueryTest.simpleClientUpdateTest();
58 | } catch (Exception e) {
59 | LOGGER.error("Fail to test jira-worklog-query", e);
60 | }
61 | }
62 |
63 | /**
64 | * The jira-worklog-query HTTP BASIC AUTHORIZATION test.
65 | *
66 | * @throws Exception
67 | * If any Exception happen.
68 | */
69 | public static void simpleClientTest() throws Exception {
70 | String url =
71 | "http://localhost:8080rest/jira-worklog-query/1.1.0/find/"
72 | + "worklogs?startDate=2012-12-12&user=admin";
73 | LOGGER.info("Start the simple test");
74 | byte[] authByteArray = Base64.encode(USERNAME + ":" + PASSWORD);
75 | String auth = new String(authByteArray, "UTF8");
76 | Client client = Client.create();
77 | WebResource webResource = client.resource(url);
78 | ClientResponse response =
79 | webResource.header("Authorization", "Basic " + auth).type("application/json")
80 | .accept("application/json").get(ClientResponse.class);
81 | int statusCode = response.getStatus();
82 |
83 | if (statusCode == INVALID_AUTHOR_STATUS) {
84 | throw new Exception("Invalid Username or Password");
85 | }
86 | final String stringResponse = response.getEntity(String.class);
87 | LOGGER.info("sr: " + stringResponse);
88 |
89 | }
90 |
91 | /**
92 | * The jira-worklog-query HTTP BASIC AUTHORIZATION test.
93 | *
94 | * @throws Exception
95 | * If any Exception happen.
96 | */
97 | public static void simpleClientUpdateTest() throws Exception {
98 | String url =
99 | "http://localhost:8080rest/jira-worklog-query/1.1.0/find/"
100 | + "updatedWorklogs?startDate=2013-04-15&user=admin";
101 | LOGGER.info("Start the simple test");
102 | byte[] authByteArray = Base64.encode(USERNAME + ":" + PASSWORD);
103 | String auth = new String(authByteArray, "UTF8");
104 | Client client = Client.create();
105 | WebResource webResource = client.resource(url);
106 | ClientResponse response =
107 | webResource.header("Authorization", "Basic " + auth).type("application/json")
108 | .accept("application/json").get(ClientResponse.class);
109 | int statusCode = response.getStatus();
110 |
111 | if (statusCode == INVALID_AUTHOR_STATUS) {
112 | throw new Exception("Invalid Username or Password");
113 | }
114 | final String stringResponse = response.getEntity(String.class);
115 | LOGGER.info("sr: " + stringResponse);
116 |
117 | }
118 |
119 | /**
120 | * Simple private constructor.
121 | */
122 | private WorklogQueryTest() {
123 |
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/src/test/resources/expectedResults.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2013 Everit Kft. (http://www.everit.org)
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | findWorklogs=[[{"id":10000,"startDate":"2016-03-07T08:00:00+0000","issueKey":"SAM-1","userId":"test-user@everit.biz","duration":22020},{"id":10001,"startDate":"2016-03-01T08:00:00+0000","issueKey":"SAM-2","userId":"test-user@everit.biz","duration":22020},{"id":10002,"startDate":"2016-02-24T08:00:00+0000","issueKey":"SAM-4","userId":"test-user@everit.biz","duration":22080}]]
18 | findUpdatedWorklogs=[[{"id":10000,"startDate":"2016-03-07T08:00:00+0000","issueKey":"SAM-1","userId":"test-user@everit.biz","duration":22020},{"id":10001,"startDate":"2016-03-01T08:00:00+0000","issueKey":"SAM-2","userId":"test-user@everit.biz","duration":22020},{"id":10002,"startDate":"2016-02-24T08:00:00+0000","issueKey":"SAM-4","userId":"test-user@everit.biz","duration":22080},{"id":10003,"startDate":"2016-02-23T08:00:00+0000","issueKey":"SAM-5","userId":"test-user@everit.biz","duration":22080}]]
19 |
--------------------------------------------------------------------------------