diff --git a/src/main/java/org/gitlab4j/api/EpicsApi.java b/src/main/java/org/gitlab4j/api/EpicsApi.java
index 0366932e6855222b79239303462adaaf3809d8b7..42a5c3c221019d4b80a3b228eaa16cfa31a0f0b1 100644
--- a/src/main/java/org/gitlab4j/api/EpicsApi.java
+++ b/src/main/java/org/gitlab4j/api/EpicsApi.java
@@ -12,6 +12,7 @@ import javax.ws.rs.core.Response;
import org.gitlab4j.api.models.ChildEpic;
import org.gitlab4j.api.models.CreatedChildEpic;
import org.gitlab4j.api.models.Epic;
+import org.gitlab4j.api.models.EpicFilter;
import org.gitlab4j.api.models.EpicIssue;
import org.gitlab4j.api.models.EpicIssueLink;
import org.gitlab4j.api.models.LinkType;
@@ -54,7 +55,7 @@ public class EpicsApi extends AbstractApi {
*
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
* @param page the page to get
- * @param perPage the number of issues per page
+ * @param perPage the number of epics per page
* @return a list of all epics of the requested group and its subgroups in the specified range
* @throws GitLabApiException if any exception occurs
*/
@@ -69,7 +70,7 @@ public class EpicsApi extends AbstractApi {
*
GitLab Endpoint: GET /groups/:id/epics
*
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
- * @param itemsPerPage the number of issues per page
+ * @param itemsPerPage the number of epics per page
* @return the Pager of all epics of the requested group and its subgroups
* @throws GitLabApiException if any exception occurs
*/
@@ -123,20 +124,28 @@ public class EpicsApi extends AbstractApi {
* @param sortOrder return epics sorted in ASC or DESC order. Default is DESC
* @param search search epics against their title and description
* @param page the page to get
- * @param perPage the number of issues per page
+ * @param perPage the number of epics per page
* @return a list of matching epics of the requested group and its subgroups in the specified range
* @throws GitLabApiException if any exception occurs
*/
public List getEpics(Object groupIdOrPath, Long authorId, String labels,
EpicOrderBy orderBy, SortOrder sortOrder, String search, int page, int perPage) throws GitLabApiException {
- GitLabApiForm formData = new GitLabApiForm(page, perPage)
- .withParam("author_id", authorId)
- .withParam("labels", labels)
- .withParam("order_by", orderBy)
- .withParam("sort", sortOrder)
- .withParam("search", search);
- Response response = get(Response.Status.OK, formData.asMap(), "groups", getGroupIdOrPath(groupIdOrPath), "epics");
- return (response.readEntity(new GenericType>() { }));
+ EpicFilter filter = createEpicFilter(authorId, labels, orderBy, sortOrder, search);
+ return getEpics(groupIdOrPath, filter);
+ }
+
+ /**
+ * Gets all epics of the requested group and its subgroups using the specified page and per page setting.
+ *
+ * GitLab Endpoint: GET /groups/:id/epics
+ *
+ * @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
+ * @param filter epic filter
+ * @return a list of matching epics of the requested group and its subgroups in the specified range
+ * @throws GitLabApiException if any exception occurs
+ */
+ public List getEpics(Object groupIdOrPath, EpicFilter filter) throws GitLabApiException {
+ return getEpics(groupIdOrPath, getDefaultPerPage(), filter).all();
}
/**
@@ -148,7 +157,7 @@ public class EpicsApi extends AbstractApi {
* @param authorId returns epics created by the given user id
* @param labels return epics matching a comma separated list of labels names.
* Label names from the epic group or a parent group can be used
- * @param itemsPerPage the number of issues per page
+ * @param itemsPerPage the number of epics per page
* @param orderBy return epics ordered by CREATED_AT or UPDATED_AT. Default is CREATED_AT
* @param sortOrder return epics sorted in ASC or DESC order. Default is DESC
* @param search search epics against their title and description
@@ -157,13 +166,32 @@ public class EpicsApi extends AbstractApi {
*/
public Pager getEpics(Object groupIdOrPath, Long authorId, String labels,
EpicOrderBy orderBy, SortOrder sortOrder, String search, int itemsPerPage) throws GitLabApiException {
- GitLabApiForm formData = new GitLabApiForm()
- .withParam("author_id", authorId)
- .withParam("labels", labels)
- .withParam("order_by", orderBy)
- .withParam("sort", sortOrder)
- .withParam("search", search);
- return (new Pager(this, Epic.class, itemsPerPage, formData.asMap(), "groups", getGroupIdOrPath(groupIdOrPath), "epics"));
+ EpicFilter filter = createEpicFilter(authorId, labels, orderBy, sortOrder, search);
+ return getEpics(groupIdOrPath, itemsPerPage, filter);
+ }
+
+ /**
+ * Gets all epics of the requested group and its subgroups using the specified page and per page setting.
+ *
+ * GitLab Endpoint: GET /groups/:id/epics
+ *
+ * @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
+ * @param filter epic filter
+ * @param itemsPerPage the number of epics per page
+ * @return a list of matching epics of the requested group and its subgroups in the specified range
+ * @throws GitLabApiException if any exception occurs
+ */
+ public Pager getEpics(Object groupIdOrPath, int itemsPerPage, EpicFilter filter) throws GitLabApiException {
+ return (new Pager(this, Epic.class, itemsPerPage, filter.getQueryParams().asMap(), "groups", getGroupIdOrPath(groupIdOrPath), "epics"));
+ }
+
+ private EpicFilter createEpicFilter(Long authorId, String labels, EpicOrderBy orderBy, SortOrder sortOrder, String search) {
+ return new EpicFilter()
+ .withAuthorId(authorId)
+ .withLabels(labels)
+ .withOrderBy(orderBy)
+ .withSortOrder(sortOrder)
+ .withSearch(search);
}
/**
@@ -369,7 +397,7 @@ public class EpicsApi extends AbstractApi {
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
* @param epicIid the IID of the epic to get issues for
* @param page the page to get
- * @param perPage the number of issues per page
+ * @param perPage the number of epics per page
* @return a list of all issues belonging to the specified epic in the specified range
* @throws GitLabApiException if any exception occurs
*/
@@ -385,7 +413,7 @@ public class EpicsApi extends AbstractApi {
*
* @param groupIdOrPath the group ID, path of the group, or a Group instance holding the group ID or path
* @param epicIid the IID of the epic to get issues for
- * @param itemsPerPage the number of issues per page
+ * @param itemsPerPage the number of epics per page
* @return the Pager of all issues belonging to the specified epic
* @throws GitLabApiException if any exception occurs
*/
diff --git a/src/main/java/org/gitlab4j/api/GitLabApiForm.java b/src/main/java/org/gitlab4j/api/GitLabApiForm.java
index b9c09e608b410654f9c5fac8193307e06b490293..f58deeb198f57a8a2f2fe9169d10084ba93584fe 100644
--- a/src/main/java/org/gitlab4j/api/GitLabApiForm.java
+++ b/src/main/java/org/gitlab4j/api/GitLabApiForm.java
@@ -159,8 +159,7 @@ public class GitLabApiForm extends Form {
for (Entry variable : variables.entrySet()) {
Object value = variable.getValue();
if (value != null) {
- this.param(name + "[][key]", variable.getKey());
- this.param(name + "[][value]", value.toString());
+ this.param(name + "[" + variable.getKey() + "]", value.toString());
}
}
diff --git a/src/main/java/org/gitlab4j/api/models/EpicFilter.java b/src/main/java/org/gitlab4j/api/models/EpicFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..a30bf0bd0c87b38541f48dd6a6fb07f9aca447b3
--- /dev/null
+++ b/src/main/java/org/gitlab4j/api/models/EpicFilter.java
@@ -0,0 +1,293 @@
+package org.gitlab4j.api.models;
+
+import org.gitlab4j.api.Constants.EpicOrderBy;
+import org.gitlab4j.api.Constants.SortOrder;
+
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.gitlab4j.api.GitLabApiForm;
+import org.gitlab4j.api.models.AbstractEpic.EpicState;
+import org.gitlab4j.api.utils.ISO8601;
+import org.gitlab4j.api.utils.JacksonJsonEnumHelper;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * This class is used to filter Groups when getting lists of epics.
+ */
+public class EpicFilter {
+
+ private Long authorId;
+ private String authorUsername;
+ private String labels;
+ private EpicOrderBy orderBy;
+ private SortOrder sort;
+ private String search;
+ private EpicState state;
+ private Date createdAfter;
+ private Date updatedAfter;
+ private Date updatedBefore;
+ private Boolean includeAncestorGroups;
+ private Boolean includeDescendantGroups;
+ private String myReactionEmoji;
+ private Map not;
+
+ public enum EpicField {
+
+ AUTHOR_ID, AUTHOR_USERNAME, LABELS;
+
+ private static JacksonJsonEnumHelper enumHelper = new JacksonJsonEnumHelper<>(EpicField.class);
+
+ @JsonCreator
+ public static EpicField forValue(String value) {
+ return enumHelper.forValue(value);
+ }
+
+ @JsonValue
+ public String toValue() {
+ return (enumHelper.toString(this));
+ }
+
+ @Override
+ public String toString() {
+ return (enumHelper.toString(this));
+ }
+ }
+
+ /**
+ * Add 'author id' filter.
+ *
+ * @param authorId the author id filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withAuthorId(Long authorId) {
+ this.authorId = authorId;
+ return (this);
+ }
+
+ /**
+ * Add 'author username' filter.
+ *
+ * @param authorUsername the 'author username' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withAuthorUsername(String authorUsername) {
+ this.authorUsername = authorUsername;
+ return (this);
+ }
+
+ /**
+ * Add 'labels' filter.
+ *
+ * @param labels the labels filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withLabels(String labels) {
+ this.labels = labels;
+ return (this);
+ }
+
+ /**
+ * Add 'order by' filter.
+ *
+ * @param orderBy the 'order by' filter
+ * @return the reference to this GroupFilter instance
+ */
+ public EpicFilter withOrderBy(EpicOrderBy orderBy) {
+ this.orderBy = orderBy;
+ return (this);
+ }
+
+ /**
+ * Add 'sort' filter.
+ *
+ * @param sort sort direction, ASC or DESC
+ * @return the reference to this GroupFilter instance
+ */
+ public EpicFilter withSortOrder(SortOrder sort) {
+ this.sort = sort;
+ return (this);
+ }
+
+ /**
+ * Add 'search' filter.
+ *
+ * @param search the 'search' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withSearch(String search) {
+ this.search = search;
+ return (this);
+ }
+
+ /**
+ * Add 'state' filter.
+ *
+ * @param state the 'state' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withState(EpicState state) {
+ this.state = state;
+ return (this);
+ }
+
+ /**
+ * Add 'created after' filter.
+ *
+ * @param createdAfter the 'created after' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withCreatedAfter(Date createdAfter) {
+ this.createdAfter = createdAfter;
+ return (this);
+ }
+
+ /**
+ * Add 'updated after' filter.
+ *
+ * @param updatedAfter the 'updated after' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withUpdatedAfter(Date updatedAfter) {
+ this.updatedAfter = updatedAfter;
+ return (this);
+ }
+
+ /**
+ * Add 'updated before' filter.
+ *
+ * @param updatedBefore the 'updated before' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withUpdatedBefore(Date updatedBefore) {
+ this.updatedBefore = updatedBefore;
+ return (this);
+ }
+
+ /**
+ * Add 'include ancestor groups' filter.
+ *
+ * @param includeAncestorGroups the 'include ancestor groups' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withIncludeAncestorGroups(Boolean includeAncestorGroups) {
+ this.includeAncestorGroups = includeAncestorGroups;
+ return (this);
+ }
+
+ /**
+ * Add 'include descendant groups' filter.
+ *
+ * @param includeDescendantGroups the 'include descendant groups' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withIncludeDescendantGroups(Boolean includeDescendantGroups) {
+ this.includeDescendantGroups = includeDescendantGroups;
+ return (this);
+ }
+
+ /**
+ * Add 'my reaction emoji' filter.
+ *
+ * @param myReactionEmoji the 'my reaction emoji' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withMyReactionEmoji(String myReactionEmoji) {
+ this.myReactionEmoji = myReactionEmoji;
+ return (this);
+ }
+
+ /**
+ * Add 'not' filter.
+ *
+ * @param not the 'not' filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withNot(Map not) {
+ this.not = not;
+ return (this);
+ }
+
+ /**
+ * Add author_id to the 'not' filter entry.
+ *
+ * @param authorId the id of the author to add to the filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withoutAuthorId(Long authorId) {
+ return withNot(EpicField.AUTHOR_ID, authorId);
+ }
+
+ /**
+ * Add author_username to the 'not' filter entry.
+ *
+ * @param authorUsername the username of the author to add to the filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withoutAuthorUsername(String authorUsername) {
+ return withNot(EpicField.AUTHOR_USERNAME, authorUsername);
+ }
+
+ /**
+ * Add labels to the 'not' filter entry.
+ *
+ * @param labels the labels to add to the filter
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withoutLabels(String... labels) {
+ return withNot(EpicField.LABELS, String.join(",", labels));
+ }
+
+ /**
+ * Add 'not' filter entry.
+ *
+ * @param field the field to be added to the 'not' value
+ * @param value the value for the entry
+ * @return the reference to this EpicFilter instance
+ */
+ public EpicFilter withNot(EpicField field, Object value) {
+ if(not == null) {
+ not = new LinkedHashMap<>();
+ }
+ not.put(field, value);
+ return (this);
+ }
+
+ /**
+ * Get the query params specified by this filter.
+ *
+ * @return a GitLabApiForm instance holding the query parameters for this GroupFilter instance
+ */
+ public GitLabApiForm getQueryParams() {
+ return (new GitLabApiForm()
+ .withParam("author_id", authorId)
+ .withParam("author_username", authorUsername)
+ .withParam("labels", labels)
+ .withParam("order_by", orderBy)
+ .withParam("sort", sort)
+ .withParam("search", search)
+ .withParam("state", state)
+ .withParam("created_after", ISO8601.toString(createdAfter, false))
+ .withParam("updated_after", ISO8601.toString(updatedAfter, false))
+ .withParam("updated_before", ISO8601.toString(updatedBefore, false))
+ .withParam("include_ancestor_groups", includeAncestorGroups)
+ .withParam("include_descendant_groups", includeDescendantGroups)
+ .withParam("my_reaction_emoji", myReactionEmoji)
+ .withParam("not", toStringMap(not), false)
+ );
+ }
+
+ private Map toStringMap(Map map) {
+ if(map == null) {
+ return null;
+ }
+ Map result = new LinkedHashMap<>();
+ for (Map.Entry entry : map.entrySet()) {
+ result.put(entry.getKey().toString(), entry.getValue());
+ }
+ return result;
+ }
+}