diff --git a/src/main/java/com/crowdin/client/tasks/TasksApi.java b/src/main/java/com/crowdin/client/tasks/TasksApi.java index 8fda1c912..65906802b 100644 --- a/src/main/java/com/crowdin/client/tasks/TasksApi.java +++ b/src/main/java/com/crowdin/client/tasks/TasksApi.java @@ -14,9 +14,11 @@ import com.crowdin.client.core.model.ResponseObject; import com.crowdin.client.tasks.model.*; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; public class TasksApi extends CrowdinApi { public TasksApi(Credentials credentials) { @@ -41,7 +43,7 @@ public TasksApi(Credentials credentials, ClientConfig clientConfig) { */ public ResponseList listTasks(Long projectId, Integer limit, Integer offset, Status status, Integer assigneeId) throws HttpException, HttpBadRequestException { Map> queryParams = HttpRequestConfig.buildUrlParams( - "status", Optional.ofNullable(status), + "status", Optional.ofNullable(status != null ? status.to(status) : null), "assigneeId", Optional.ofNullable(assigneeId), "limit", Optional.ofNullable(limit), "offset", Optional.ofNullable(offset) @@ -50,6 +52,42 @@ public ResponseList listTasks(Long projectId, Integer limit, Integer offse return TaskResponseList.to(taskResponseList); } + /** + * Lists tasks for a given project, filtered by multiple statuses. + * + * @param projectId project identifier + * @param params Query params + * @return List of tasks + * @see + */ + public ResponseList listTasks(Long projectId, ListTasksParams params) throws HttpException, HttpBadRequestException { + ListTasksParams query = Optional.ofNullable(params).orElse(new ListTasksParams()); + + EnumSet statuses = query.getStatuses(); + + Map> queryParams = HttpRequestConfig.buildUrlParams( + "status", Optional.ofNullable( + statuses == null ? null : statuses.stream() + .map(status -> status.to(status)) + .collect(Collectors.joining(",")) + ), + "assigneeId", Optional.ofNullable(query.getAssigneeId()), + "limit", Optional.ofNullable(query.getLimit()), + "offset", Optional.ofNullable(query.getOffset()) + ); + + TaskResponseList taskResponseList = this.httpClient.get( + this.url + "/projects/" + projectId + "/tasks", + new HttpRequestConfig(queryParams), + TaskResponseList.class + ); + + return TaskResponseList.to(taskResponseList); + } + /** * @param projectId project identifier * @param request request object diff --git a/src/main/java/com/crowdin/client/tasks/model/ListTasksParams.java b/src/main/java/com/crowdin/client/tasks/model/ListTasksParams.java new file mode 100644 index 000000000..695634193 --- /dev/null +++ b/src/main/java/com/crowdin/client/tasks/model/ListTasksParams.java @@ -0,0 +1,14 @@ +package com.crowdin.client.tasks.model; + +import com.crowdin.client.core.model.Pagination; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.EnumSet; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ListTasksParams extends Pagination { + private EnumSet statuses; + private Long assigneeId; +} diff --git a/src/test/java/com/crowdin/client/tasks/TasksApiTest.java b/src/test/java/com/crowdin/client/tasks/TasksApiTest.java index 1dc7f1f39..ff2a85124 100644 --- a/src/test/java/com/crowdin/client/tasks/TasksApiTest.java +++ b/src/test/java/com/crowdin/client/tasks/TasksApiTest.java @@ -7,40 +7,28 @@ import com.crowdin.client.core.model.ResponseObject; import com.crowdin.client.framework.RequestMock; import com.crowdin.client.framework.TestClient; -import com.crowdin.client.tasks.model.AssignedTeam; -import com.crowdin.client.tasks.model.Assignee; -import com.crowdin.client.tasks.model.AssigneeRequest; -import com.crowdin.client.tasks.model.CreateTaskEnterpriseStringsBasedRequest; -import com.crowdin.client.tasks.model.CreateTaskRequest; -import com.crowdin.client.tasks.model.CreateTaskEnterpriseVendorRequest; -import com.crowdin.client.tasks.model.CreateTaskStringsBasedRequest; -import com.crowdin.client.tasks.model.Progress; -import com.crowdin.client.tasks.model.Status; -import com.crowdin.client.tasks.model.Task; -import com.crowdin.client.tasks.model.Type; +import com.crowdin.client.tasks.model.*; import com.crowdin.client.tasks.model.pending.CreateEnterprisePendingTaskRequest; import com.crowdin.client.tasks.model.pending.CreatePendingTaskRequest; +import lombok.SneakyThrows; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPatch; import org.apache.http.client.methods.HttpPost; import org.junit.jupiter.api.Test; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; +import java.util.*; import static java.util.Collections.singletonList; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class TasksApiTest extends TestClient { private final Long projectId = 12L; private final Long enterpriseProjectId = 13L; + private final Long multiStatusProjectId = 14L; + private final Long singleStatusProjectId = 15L; private final Long taskId = 2L; private final Long prevTaskId = 1L; private final Status status = Status.TODO; @@ -61,26 +49,75 @@ public List getMocks() { RequestMock.build(this.url + "/projects/" + projectId + "/tasks/" + taskId, HttpDelete.METHOD_NAME), RequestMock.build(this.url + "/projects/" + projectId + "/tasks/" + taskId, HttpPatch.METHOD_NAME, "api/tasks/editTask.json", "api/tasks/task.json"), RequestMock.build(this.url + "/user/tasks", HttpGet.METHOD_NAME, "api/tasks/listTasks.json"), - RequestMock.build(this.url + "/user/tasks/" + taskId, HttpPatch.METHOD_NAME, "api/tasks/editTask.json", "api/tasks/task.json") + RequestMock.build(this.url + "/user/tasks/" + taskId, HttpPatch.METHOD_NAME, "api/tasks/editTask.json", "api/tasks/task.json"), + RequestMock.build(this.url + "/projects/" + multiStatusProjectId + "/tasks", HttpGet.METHOD_NAME, "api/tasks/multiStatusListTasks.json", new HashMap() {{ + put("status", "todo,done"); + }}), + RequestMock.build(this.url + "/projects/" + singleStatusProjectId + "/tasks", HttpGet.METHOD_NAME, "api/tasks/singleStatusListTasks.json", new HashMap() {{ + put("status", "in_progress"); + }}) ); } @Test public void listTasksTest() { - Assignee assignee = new Assignee(); - assignee.setId(1L); - assignee.setUsername("john_smith"); - assignee.setFullName("john_smith"); - assignee.setAvatarUrl(""); - assignee.setWordsCount(5); - assignee.setWordsLeft(3); TimeZone.setDefault(TimeZone.getTimeZone("GMT")); ResponseList taskResponseList = this.getTasksApi().listTasks(projectId, null, null, null, null); - assertEquals(taskResponseList.getData().size(), 1); - assertEquals(taskResponseList.getData().get(0).getData().getId(), taskId); - assertEquals(taskResponseList.getData().get(0).getData().getStatus(), status); - assertEquals(new Date(119, Calendar.SEPTEMBER,27,7,0,14), taskResponseList.getData().get(0).getData().getDeadline()); - assertEquals(taskResponseList.getData().get(0).getData().getAssignees().get(0), assignee); + + assertNotNull(taskResponseList.getData().get(0).getData()); + assertEquals(1, taskResponseList.getData().size()); + + assertEquals(projectId, taskResponseList.getData().get(0).getData().getProjectId()); + + assertListTasks(taskResponseList); + } + + @Test + public void listTasksTest_testSingleStatus() { + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + ResponseList taskResponseList = this.getTasksApi().listTasks(singleStatusProjectId, null, null, Status.IN_PROGRESS, null); + + assertNotNull(taskResponseList.getData().get(0).getData()); + assertEquals(1, taskResponseList.getData().size()); + assertEquals(singleStatusProjectId, taskResponseList.getData().get(0).getData().getProjectId()); + assertEquals(Status.IN_PROGRESS, taskResponseList.getData().get(0).getData().getStatus()); + + assertListTasks(taskResponseList); + } + + @Test + void listTasksTest_withNullStatuses() { + ListTasksParams listTasksParams = new ListTasksParams(); + listTasksParams.setStatuses(null); + + ResponseList taskResponseList = this.getTasksApi().listTasks(projectId, listTasksParams); + + assertNotNull(taskResponseList); + assertEquals(1, taskResponseList.getData().size()); + assertEquals(projectId, taskResponseList.getData().get(0).getData().getProjectId()); + + assertListTasks(taskResponseList); + } + + @Test + public void listTasksTest_multipleStatuses() { + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + + EnumSet statuses = EnumSet.of(Status.TODO, Status.DONE); + + ListTasksParams listTasksParams = new ListTasksParams(); + listTasksParams.setStatuses(statuses); + + ResponseList taskResponseList = this.getTasksApi().listTasks(multiStatusProjectId, listTasksParams); + + assertNotNull(taskResponseList.getData().get(0).getData()); + assertEquals(1, taskResponseList.getData().size()); + assertEquals(multiStatusProjectId, taskResponseList.getData().get(0).getData().getProjectId()); + + Status responseProjectStatus = taskResponseList.getData().get(0).getData().getStatus(); + assertTrue(statuses.contains(responseProjectStatus)); + + assertListTasks(taskResponseList); } @Test @@ -282,4 +319,21 @@ public void editUserTaskTest() { assertEquals(taskResponseObject.getData().getId(), taskId); assertEquals(taskResponseObject.getData().getStatus(), status); } + + // + @SneakyThrows + private void assertListTasks(ResponseList taskResponseList) { + Assignee assignee = new Assignee(); + assignee.setId(1L); + assignee.setUsername("john_smith"); + assignee.setFullName("john_smith"); + assignee.setAvatarUrl(""); + assignee.setWordsCount(5); + assignee.setWordsLeft(3); + + assertEquals(taskId, taskResponseList.getData().get(0).getData().getId()); + assertEquals(new Date(119, Calendar.SEPTEMBER,27,7,0,14), taskResponseList.getData().get(0).getData().getDeadline()); + assertEquals(assignee, taskResponseList.getData().get(0).getData().getAssignees().get(0)); + } + // } diff --git a/src/test/resources/api/tasks/listTasks.json b/src/test/resources/api/tasks/listTasks.json index f07d0e54c..a7a25bc23 100644 --- a/src/test/resources/api/tasks/listTasks.json +++ b/src/test/resources/api/tasks/listTasks.json @@ -3,7 +3,7 @@ { "data": { "id": 2, - "projectId": 2, + "projectId": 12, "creatorId": 6, "type": 1, "status": "todo", diff --git a/src/test/resources/api/tasks/multiStatusListTasks.json b/src/test/resources/api/tasks/multiStatusListTasks.json new file mode 100644 index 000000000..27c5186c9 --- /dev/null +++ b/src/test/resources/api/tasks/multiStatusListTasks.json @@ -0,0 +1,55 @@ +{ + "data": [ + { + "data": { + "id": 2, + "projectId": 14, + "creatorId": 6, + "type": 1, + "status": "todo", + "title": "French", + "assignees": [ + { + "id": 1, + "username": "john_smith", + "fullName": "john_smith", + "avatarUrl": "", + "wordsCount": 5, + "wordsLeft": 3 + } + ], + "assignedTeams": [ + { + "id": 1, + "wordsCount": 5 + } + ], + "fileIds": [ + 1 + ], + "progress": { + "total": 24, + "done": 15, + "percent": 62 + }, + "sourceLanguageId": "en", + "targetLanguageId": "fr", + "description": "Proofread all French strings", + "hash": "dac37aff364d83899128e68afe0de4994", + "translationUrl": "/proofread/9092638ac9f2a2d1b5571d08edc53763/all/en-fr/10?task=dac37aff364d83899128e68afe0de4994", + "wordsCount": 24, + "filesCount": 2, + "commentsCount": 0, + "deadline": "2019-09-27T07:00:14+00:00", + "timeRange": "string", + "workflowStepId": 10, + "createdAt": "2019-09-23T09:04:29+00:00", + "updatedAt": "2019-09-23T09:04:29+00:00" + } + } + ], + "pagination": { + "offset": 0, + "limit": 25 + } +} diff --git a/src/test/resources/api/tasks/singleStatusListTasks.json b/src/test/resources/api/tasks/singleStatusListTasks.json new file mode 100644 index 000000000..5ef26dde2 --- /dev/null +++ b/src/test/resources/api/tasks/singleStatusListTasks.json @@ -0,0 +1,55 @@ +{ + "data": [ + { + "data": { + "id": 2, + "projectId": 15, + "creatorId": 6, + "type": 1, + "status": "in_progress", + "title": "French", + "assignees": [ + { + "id": 1, + "username": "john_smith", + "fullName": "john_smith", + "avatarUrl": "", + "wordsCount": 5, + "wordsLeft": 3 + } + ], + "assignedTeams": [ + { + "id": 1, + "wordsCount": 5 + } + ], + "fileIds": [ + 1 + ], + "progress": { + "total": 24, + "done": 15, + "percent": 62 + }, + "sourceLanguageId": "en", + "targetLanguageId": "fr", + "description": "Proofread all French strings", + "hash": "dac37aff364d83899128e68afe0de4994", + "translationUrl": "/proofread/9092638ac9f2a2d1b5571d08edc53763/all/en-fr/10?task=dac37aff364d83899128e68afe0de4994", + "wordsCount": 24, + "filesCount": 2, + "commentsCount": 0, + "deadline": "2019-09-27T07:00:14+00:00", + "timeRange": "string", + "workflowStepId": 10, + "createdAt": "2019-09-23T09:04:29+00:00", + "updatedAt": "2019-09-23T09:04:29+00:00" + } + } + ], + "pagination": { + "offset": 0, + "limit": 25 + } +}