Skip to content

Commit 5dd0514

Browse files
committed
feat: Support for multivalued status as described in issue #315.
1 parent 027181e commit 5dd0514

6 files changed

Lines changed: 251 additions & 41 deletions

File tree

src/main/java/com/crowdin/client/tasks/TasksApi.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
import com.crowdin.client.core.model.ResponseObject;
1515
import com.crowdin.client.tasks.model.*;
1616

17+
import java.util.EnumSet;
1718
import java.util.List;
1819
import java.util.Map;
1920
import java.util.Optional;
21+
import java.util.stream.Collectors;
2022

2123
public class TasksApi extends CrowdinApi {
2224
public TasksApi(Credentials credentials) {
@@ -40,14 +42,30 @@ public TasksApi(Credentials credentials, ClientConfig clientConfig) {
4042
* </ul>
4143
*/
4244
public ResponseList<Task> listTasks(Long projectId, Integer limit, Integer offset, Status status, Integer assigneeId) throws HttpException, HttpBadRequestException {
43-
Map<String, Optional<Object>> queryParams = HttpRequestConfig.buildUrlParams(
44-
"status", Optional.ofNullable(status),
45-
"assigneeId", Optional.ofNullable(assigneeId),
46-
"limit", Optional.ofNullable(limit),
47-
"offset", Optional.ofNullable(offset)
48-
);
49-
TaskResponseList taskResponseList = this.httpClient.get(this.url + "/projects/" + projectId + "/tasks", new HttpRequestConfig(queryParams), TaskResponseList.class);
50-
return TaskResponseList.to(taskResponseList);
45+
EnumSet<Status> statuses = (status != null) ? EnumSet.of(status) : null;
46+
47+
ListTasksParams params = new ListTasksParams();
48+
params.setStatuses(statuses);
49+
params.setLimit(limit);
50+
params.setOffset(offset);
51+
params.setAssigneeId(assigneeId);
52+
53+
return listTasksInternal(projectId, params);
54+
}
55+
56+
/**
57+
* Lists tasks for a given project, filtered by multiple statuses.
58+
*
59+
* @param projectId ID of the project
60+
* @param params Query params
61+
* @return List of tasks
62+
* @see <ul>
63+
* <li><a href="https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.getMany" target="_blank"><b>API Documentation</b></a></li>
64+
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.tasks.getMany" target="_blank"><b>Enterprise API Documentation</b></a></li>
65+
* </ul>
66+
*/
67+
public ResponseList<Task> listTasks(Long projectId, ListTasksParams params) throws HttpException, HttpBadRequestException {
68+
return listTasksInternal(projectId, params);
5169
}
5270

5371
/**
@@ -159,6 +177,34 @@ public ResponseObject<Task> editTaskArchivedStatus(Long taskId, Long projectId,
159177
return ResponseObject.of(taskResponseObject.getData());
160178
}
161179

180+
//<editor-fold desc="List Tasks Common Method">
181+
private ResponseList<Task> listTasksInternal(Long projectId, ListTasksParams params) throws HttpException, HttpBadRequestException {
182+
ListTasksParams query = Optional.ofNullable(params).orElse(new ListTasksParams());
183+
184+
EnumSet<Status> statuses = query.getStatuses();
185+
186+
Map<String, Optional<Object>> queryParams = HttpRequestConfig.buildUrlParams(
187+
"status", Optional.ofNullable(
188+
statuses == null ? null : statuses.stream()
189+
.map(status -> status.to(status))
190+
.collect(Collectors.joining(","))
191+
),
192+
"assigneeId", Optional.ofNullable(query.getAssigneeId()),
193+
"limit", Optional.ofNullable(query.getLimit()),
194+
"offset", Optional.ofNullable(query.getOffset())
195+
);
196+
197+
TaskResponseList taskResponseList = this.httpClient.get(
198+
this.url + "/projects/" + projectId + "/tasks",
199+
new HttpRequestConfig(queryParams),
200+
TaskResponseList.class
201+
);
202+
203+
return TaskResponseList.to(taskResponseList);
204+
}
205+
206+
//</editor-fold>
207+
162208
//<editor-fold desc="Task Settings Templates">
163209

164210
/**
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.crowdin.client.tasks.model;
2+
3+
import com.crowdin.client.core.model.Pagination;
4+
import lombok.Data;
5+
import lombok.EqualsAndHashCode;
6+
7+
import java.util.EnumSet;
8+
9+
@EqualsAndHashCode(callSuper = true)
10+
@Data
11+
public class ListTasksParams extends Pagination {
12+
private EnumSet<Status> statuses;
13+
private Integer assigneeId;
14+
}

src/test/java/com/crowdin/client/tasks/TasksApiTest.java

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,28 @@
77
import com.crowdin.client.core.model.ResponseObject;
88
import com.crowdin.client.framework.RequestMock;
99
import com.crowdin.client.framework.TestClient;
10-
import com.crowdin.client.tasks.model.AssignedTeam;
11-
import com.crowdin.client.tasks.model.Assignee;
12-
import com.crowdin.client.tasks.model.AssigneeRequest;
13-
import com.crowdin.client.tasks.model.CreateTaskEnterpriseStringsBasedRequest;
14-
import com.crowdin.client.tasks.model.CreateTaskRequest;
15-
import com.crowdin.client.tasks.model.CreateTaskEnterpriseVendorRequest;
16-
import com.crowdin.client.tasks.model.CreateTaskStringsBasedRequest;
17-
import com.crowdin.client.tasks.model.Progress;
18-
import com.crowdin.client.tasks.model.Status;
19-
import com.crowdin.client.tasks.model.Task;
20-
import com.crowdin.client.tasks.model.Type;
10+
import com.crowdin.client.tasks.model.*;
2111
import com.crowdin.client.tasks.model.pending.CreateEnterprisePendingTaskRequest;
2212
import com.crowdin.client.tasks.model.pending.CreatePendingTaskRequest;
13+
import lombok.SneakyThrows;
2314
import org.apache.http.client.methods.HttpDelete;
2415
import org.apache.http.client.methods.HttpGet;
2516
import org.apache.http.client.methods.HttpPatch;
2617
import org.apache.http.client.methods.HttpPost;
2718
import org.junit.jupiter.api.Test;
2819

29-
import java.util.Arrays;
30-
import java.util.Calendar;
31-
import java.util.Date;
32-
import java.util.HashMap;
33-
import java.util.List;
34-
import java.util.Map;
35-
import java.util.TimeZone;
20+
import java.util.*;
3621

3722
import static java.util.Collections.singletonList;
38-
import static org.junit.jupiter.api.Assertions.assertEquals;
23+
import static org.junit.jupiter.api.Assertions.*;
24+
import static org.junit.jupiter.api.Assertions.assertNotNull;
3925

4026
public class TasksApiTest extends TestClient {
4127

4228
private final Long projectId = 12L;
4329
private final Long enterpriseProjectId = 13L;
30+
private final Long multiStatusProjectId = 14L;
31+
private final Long singleStatusProjectId = 15L;
4432
private final Long taskId = 2L;
4533
private final Long prevTaskId = 1L;
4634
private final Status status = Status.TODO;
@@ -61,26 +49,61 @@ public List<RequestMock> getMocks() {
6149
RequestMock.build(this.url + "/projects/" + projectId + "/tasks/" + taskId, HttpDelete.METHOD_NAME),
6250
RequestMock.build(this.url + "/projects/" + projectId + "/tasks/" + taskId, HttpPatch.METHOD_NAME, "api/tasks/editTask.json", "api/tasks/task.json"),
6351
RequestMock.build(this.url + "/user/tasks", HttpGet.METHOD_NAME, "api/tasks/listTasks.json"),
64-
RequestMock.build(this.url + "/user/tasks/" + taskId, HttpPatch.METHOD_NAME, "api/tasks/editTask.json", "api/tasks/task.json")
52+
RequestMock.build(this.url + "/user/tasks/" + taskId, HttpPatch.METHOD_NAME, "api/tasks/editTask.json", "api/tasks/task.json"),
53+
RequestMock.build(this.url + "/projects/" + multiStatusProjectId + "/tasks", HttpGet.METHOD_NAME, "api/tasks/multiStatusListTasks.json", new HashMap<String, String>() {{
54+
put("status", "todo,done");
55+
}}),
56+
RequestMock.build(this.url + "/projects/" + singleStatusProjectId + "/tasks", HttpGet.METHOD_NAME, "api/tasks/singleStatusListTasks.json", new HashMap<String, String>() {{
57+
put("status", "in_progress");
58+
}})
6559
);
6660
}
6761

6862
@Test
6963
public void listTasksTest() {
70-
Assignee assignee = new Assignee();
71-
assignee.setId(1L);
72-
assignee.setUsername("john_smith");
73-
assignee.setFullName("john_smith");
74-
assignee.setAvatarUrl("");
75-
assignee.setWordsCount(5);
76-
assignee.setWordsLeft(3);
7764
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
7865
ResponseList<Task> taskResponseList = this.getTasksApi().listTasks(projectId, null, null, null, null);
79-
assertEquals(taskResponseList.getData().size(), 1);
80-
assertEquals(taskResponseList.getData().get(0).getData().getId(), taskId);
81-
assertEquals(taskResponseList.getData().get(0).getData().getStatus(), status);
82-
assertEquals(new Date(119, Calendar.SEPTEMBER,27,7,0,14), taskResponseList.getData().get(0).getData().getDeadline());
83-
assertEquals(taskResponseList.getData().get(0).getData().getAssignees().get(0), assignee);
66+
67+
assertNotNull(taskResponseList.getData().get(0).getData());
68+
assertEquals(1, taskResponseList.getData().size());
69+
70+
assertEquals(projectId, taskResponseList.getData().get(0).getData().getProjectId());
71+
72+
assertListTasks(taskResponseList);
73+
}
74+
75+
@Test
76+
public void listTasksTest_testSingleStatus() {
77+
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
78+
ResponseList<Task> taskResponseList = this.getTasksApi().listTasks(singleStatusProjectId, null, null, Status.IN_PROGRESS, null);
79+
80+
assertNotNull(taskResponseList.getData().get(0).getData());
81+
assertEquals(1, taskResponseList.getData().size());
82+
assertEquals(singleStatusProjectId, taskResponseList.getData().get(0).getData().getProjectId());
83+
assertEquals(Status.IN_PROGRESS, taskResponseList.getData().get(0).getData().getStatus());
84+
85+
assertListTasks(taskResponseList);
86+
}
87+
88+
@Test
89+
public void listTasksTest_multipleStatuses() {
90+
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
91+
92+
EnumSet<Status> statuses = EnumSet.of(Status.TODO, Status.DONE);
93+
94+
ListTasksParams listTasksParams = new ListTasksParams();
95+
listTasksParams.setStatuses(statuses);
96+
97+
ResponseList<Task> taskResponseList = this.getTasksApi().listTasks(multiStatusProjectId, listTasksParams);
98+
99+
assertNotNull(taskResponseList.getData().get(0).getData());
100+
assertEquals(1, taskResponseList.getData().size());
101+
assertEquals(multiStatusProjectId, taskResponseList.getData().get(0).getData().getProjectId());
102+
103+
Status responseProjectStatus = taskResponseList.getData().get(0).getData().getStatus();
104+
assertTrue(statuses.contains(responseProjectStatus));
105+
106+
assertListTasks(taskResponseList);
84107
}
85108

86109
@Test
@@ -282,4 +305,21 @@ public void editUserTaskTest() {
282305
assertEquals(taskResponseObject.getData().getId(), taskId);
283306
assertEquals(taskResponseObject.getData().getStatus(), status);
284307
}
308+
309+
//<editor-fold desc="Common method for listTasks assertion">
310+
@SneakyThrows
311+
private void assertListTasks(ResponseList<Task> taskResponseList) {
312+
Assignee assignee = new Assignee();
313+
assignee.setId(1L);
314+
assignee.setUsername("john_smith");
315+
assignee.setFullName("john_smith");
316+
assignee.setAvatarUrl("");
317+
assignee.setWordsCount(5);
318+
assignee.setWordsLeft(3);
319+
320+
assertEquals(taskId, taskResponseList.getData().get(0).getData().getId());
321+
assertEquals(new Date(119, Calendar.SEPTEMBER,27,7,0,14), taskResponseList.getData().get(0).getData().getDeadline());
322+
assertEquals(assignee, taskResponseList.getData().get(0).getData().getAssignees().get(0));
323+
}
324+
//</editor-fold>
285325
}

src/test/resources/api/tasks/listTasks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{
44
"data": {
55
"id": 2,
6-
"projectId": 2,
6+
"projectId": 12,
77
"creatorId": 6,
88
"type": 1,
99
"status": "todo",
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"data": [
3+
{
4+
"data": {
5+
"id": 2,
6+
"projectId": 14,
7+
"creatorId": 6,
8+
"type": 1,
9+
"status": "todo",
10+
"title": "French",
11+
"assignees": [
12+
{
13+
"id": 1,
14+
"username": "john_smith",
15+
"fullName": "john_smith",
16+
"avatarUrl": "",
17+
"wordsCount": 5,
18+
"wordsLeft": 3
19+
}
20+
],
21+
"assignedTeams": [
22+
{
23+
"id": 1,
24+
"wordsCount": 5
25+
}
26+
],
27+
"fileIds": [
28+
1
29+
],
30+
"progress": {
31+
"total": 24,
32+
"done": 15,
33+
"percent": 62
34+
},
35+
"sourceLanguageId": "en",
36+
"targetLanguageId": "fr",
37+
"description": "Proofread all French strings",
38+
"hash": "dac37aff364d83899128e68afe0de4994",
39+
"translationUrl": "/proofread/9092638ac9f2a2d1b5571d08edc53763/all/en-fr/10?task=dac37aff364d83899128e68afe0de4994",
40+
"wordsCount": 24,
41+
"filesCount": 2,
42+
"commentsCount": 0,
43+
"deadline": "2019-09-27T07:00:14+00:00",
44+
"timeRange": "string",
45+
"workflowStepId": 10,
46+
"createdAt": "2019-09-23T09:04:29+00:00",
47+
"updatedAt": "2019-09-23T09:04:29+00:00"
48+
}
49+
}
50+
],
51+
"pagination": {
52+
"offset": 0,
53+
"limit": 25
54+
}
55+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"data": [
3+
{
4+
"data": {
5+
"id": 2,
6+
"projectId": 15,
7+
"creatorId": 6,
8+
"type": 1,
9+
"status": "in_progress",
10+
"title": "French",
11+
"assignees": [
12+
{
13+
"id": 1,
14+
"username": "john_smith",
15+
"fullName": "john_smith",
16+
"avatarUrl": "",
17+
"wordsCount": 5,
18+
"wordsLeft": 3
19+
}
20+
],
21+
"assignedTeams": [
22+
{
23+
"id": 1,
24+
"wordsCount": 5
25+
}
26+
],
27+
"fileIds": [
28+
1
29+
],
30+
"progress": {
31+
"total": 24,
32+
"done": 15,
33+
"percent": 62
34+
},
35+
"sourceLanguageId": "en",
36+
"targetLanguageId": "fr",
37+
"description": "Proofread all French strings",
38+
"hash": "dac37aff364d83899128e68afe0de4994",
39+
"translationUrl": "/proofread/9092638ac9f2a2d1b5571d08edc53763/all/en-fr/10?task=dac37aff364d83899128e68afe0de4994",
40+
"wordsCount": 24,
41+
"filesCount": 2,
42+
"commentsCount": 0,
43+
"deadline": "2019-09-27T07:00:14+00:00",
44+
"timeRange": "string",
45+
"workflowStepId": 10,
46+
"createdAt": "2019-09-23T09:04:29+00:00",
47+
"updatedAt": "2019-09-23T09:04:29+00:00"
48+
}
49+
}
50+
],
51+
"pagination": {
52+
"offset": 0,
53+
"limit": 25
54+
}
55+
}

0 commit comments

Comments
 (0)