blob: 9df0eb07b26e5ef61681e100b7511ed0df2120ac [file] [log] [blame]
package com.intellij.tasks.gitlab;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.intellij.openapi.util.Comparing;
import com.intellij.tasks.Task;
import com.intellij.tasks.TaskRepositoryType;
import com.intellij.tasks.gitlab.model.GitlabIssue;
import com.intellij.tasks.gitlab.model.GitlabProject;
import com.intellij.tasks.impl.gson.GsonUtil;
import com.intellij.tasks.impl.httpclient.NewBaseRepositoryImpl;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.annotations.Tag;
import com.intellij.util.xmlb.annotations.Transient;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.protocol.HttpContext;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import static com.intellij.tasks.impl.httpclient.ResponseUtil.GsonMultipleObjectsDeserializer;
import static com.intellij.tasks.impl.httpclient.ResponseUtil.GsonSingleObjectDeserializer;
/**
* @author Mikhail Golubev
*/
@Tag("Gitlab")
public class GitlabRepository extends NewBaseRepositoryImpl {
@NonNls public static final String REST_API_PATH_PREFIX = "/api/v3/";
private static final Pattern ID_PATTERN = Pattern.compile("\\d+");
public static final Gson GSON = GsonUtil.createDefaultBuilder().create();
public static final TypeToken<List<GitlabProject>> LIST_OF_PROJECTS_TYPE = new TypeToken<List<GitlabProject>>() {
};
public static final TypeToken<List<GitlabIssue>> LIST_OF_ISSUES_TYPE = new TypeToken<List<GitlabIssue>>() {
};
public static final GitlabProject UNSPECIFIED_PROJECT = new GitlabProject() {
@Override
public String getName() {
return "-- from all projects --";
}
@Override
public int getId() {
return -1;
}
};
private GitlabProject myCurrentProject;
private List<GitlabProject> myProjects = null;
/**
* Serialization constructor
*/
@SuppressWarnings("UnusedDeclaration")
public GitlabRepository() {
}
/**
* Normal instantiation constructor
*/
public GitlabRepository(TaskRepositoryType type) {
super(type);
}
/**
* Cloning constructor
*/
public GitlabRepository(GitlabRepository other) {
super(other);
myCurrentProject = other.myCurrentProject;
}
@Override
public boolean equals(Object o) {
if (!super.equals(o)) return false;
GitlabRepository repository = (GitlabRepository)o;
if (!Comparing.equal(myCurrentProject, repository.myCurrentProject)) return false;
return true;
}
@NotNull
@Override
public GitlabRepository clone() {
return new GitlabRepository(this);
}
@Override
public Task[] getIssues(@Nullable String query, int offset, int limit, boolean withClosed) throws Exception {
return ContainerUtil.map2Array(fetchIssues((offset / limit) + 1, limit), GitlabTask.class, new Function<GitlabIssue, GitlabTask>() {
@Override
public GitlabTask fun(GitlabIssue issue) {
return new GitlabTask(GitlabRepository.this, issue);
}
});
}
@Nullable
@Override
public Task findTask(@NotNull String id) throws Exception {
// doesn't work now, because Gitlab's REST API doesn't provide endpoint to find task
// by its global ID, only by project ID and task's local ID (iid).
//GitlabIssue issue = fetchIssue(Integer.parseInt(id));
//return issue == null ? null : new GitlabTask(this, issue);
return null;
}
@Nullable
@Override
public CancellableConnection createCancellableConnection() {
return new HttpTestConnection(new HttpGet(getIssuesUrl()));
}
/**
* Always forcibly attempts do fetch new projects from server.
*/
@NotNull
public List<GitlabProject> fetchProjects() throws Exception {
HttpGet request = new HttpGet(getRestApiUrl("projects"));
ResponseHandler<List<GitlabProject>> handler = new GsonMultipleObjectsDeserializer<GitlabProject>(GSON, LIST_OF_PROJECTS_TYPE);
myProjects = getHttpClient().execute(request, handler);
return Collections.unmodifiableList(myProjects);
}
@SuppressWarnings("UnusedDeclaration")
@NotNull
public GitlabProject fetchProject(int id) throws Exception {
HttpGet request = new HttpGet(getRestApiUrl("project", id));
return getHttpClient().execute(request, new GsonSingleObjectDeserializer<GitlabProject>(GSON, GitlabProject.class));
}
@NotNull
public List<GitlabIssue> fetchIssues(int pageNumber, int pageSize) throws Exception {
ensureProjectsDiscovered();
ResponseHandler<List<GitlabIssue>> handler = new GsonMultipleObjectsDeserializer<GitlabIssue>(GSON, LIST_OF_ISSUES_TYPE);
return getHttpClient().execute(new HttpGet(getIssuesUrl()), handler);
}
private String getIssuesUrl() {
if (myCurrentProject != null && myCurrentProject != UNSPECIFIED_PROJECT) {
return getRestApiUrl("projects", myCurrentProject.getId(), "issues");
}
return getRestApiUrl("issues");
}
@SuppressWarnings("UnusedDeclaration")
@Nullable
public GitlabIssue fetchIssue(int id) throws Exception {
ensureProjectsDiscovered();
HttpGet request = new HttpGet(getRestApiUrl("issues", id));
ResponseHandler<GitlabIssue> handler = new GsonSingleObjectDeserializer<GitlabIssue>(GSON, GitlabIssue.class, true);
return getHttpClient().execute(request, handler);
}
@Override
public String getPresentableName() {
String name = getUrl();
if (myCurrentProject != null && myCurrentProject != UNSPECIFIED_PROJECT) {
name += "/" + myCurrentProject.getName();
}
return name;
}
@Nullable
@Override
public String extractId(@NotNull String taskName) {
return ID_PATTERN.matcher(taskName).matches() ? taskName : null;
}
@Override
public boolean isConfigured() {
return super.isConfigured() && !myPassword.isEmpty();
}
@NotNull
@Override
public String getRestApiPathPrefix() {
return REST_API_PATH_PREFIX;
}
@Nullable
@Override
protected HttpRequestInterceptor createRequestInterceptor() {
return new HttpRequestInterceptor() {
@Override
public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
request.addHeader("PRIVATE-TOKEN", myPassword);
//request.addHeader("Accept", "application/json");
}
};
}
public void setCurrentProject(@Nullable GitlabProject project) {
myCurrentProject = project != null && project.getId() == -1 ? UNSPECIFIED_PROJECT : project;
}
public GitlabProject getCurrentProject() {
return myCurrentProject;
}
/**
* May return cached projects or make request to receive new ones.
*/
@NotNull
public List<GitlabProject> getProjects() {
try {
ensureProjectsDiscovered();
}
catch (Exception ignored) {
return Collections.emptyList();
}
return Collections.unmodifiableList(myProjects);
}
private void ensureProjectsDiscovered() throws Exception {
if (myProjects == null) {
fetchProjects();
}
}
@TestOnly
@Transient
public void setProjects(@NotNull List<GitlabProject> projects) {
myProjects = projects;
}
}