Compare commits

..

15 Commits
1.0 ... master

Author SHA1 Message Date
Roman Pedchenko
f16e8ff7da
- fixed version 2020-02-27 16:12:01 +02:00
Roman Pedchenko
2f14392e1e
Merge pull request #11 from billlhead/master
Fixes errors with loading issues without limits and searching for issues containing white spaces
2020-02-27 16:06:56 +02:00
Bill Kachirsky
1f7fcd7d03 Encode query string to fix problems of searching for issues with a whitespace in it. 2020-02-27 01:54:52 -08:00
Bill Kachirsky
e5e3e84b23 Fix error of only loading one issue if no limit (-1) is set. 2020-02-27 01:48:56 -08:00
Roman Pedchenko
dba6bf0408
- fixed version 2019-04-04 16:24:25 +03:00
Roman Pedchenko
dc98e2adac
#9: - reworked offset/limit processing; - implemented 'assigned to me' filter 2019-04-04 16:17:57 +03:00
Roman Pedchenko
01a7e1a17f
#9: - added offset/limit processing 2019-04-04 01:44:13 +03:00
Roman Pedchenko
ad26a2bb52
- changed plugin version 2019-01-27 15:27:30 +02:00
Roman Pedchenko
d7d60548a9
#2, #7: changed login method to token authorization, got rid of project search limitations by implementing manual project name input 2019-01-27 15:26:26 +02:00
Roman Pedchenko
f94722bcc7
#8: - fixed "Unauthorized" exception 2019-01-27 12:24:05 +02:00
Roman Pedchenko
f62d7081a5
- added project filter
- fixed some serialization issues
- made some code optimizations
2018-08-01 11:43:07 +03:00
Roman Pedchenko
356b9ec312
- fixed plugin version 2018-07-22 18:03:50 +03:00
Roman Pedchenko
a3ef8bb4ab
- fixed an issue reading bug
- forced projects reload after clicking the 'test connection' button
2018-07-22 17:59:29 +03:00
Roman Pedchenko
9bf3d8236f
- fixed plugin version 2018-07-11 02:01:37 +03:00
Roman Pedchenko
19f52092b2 - fixed default url 2018-07-03 00:04:09 +03:00
11 changed files with 438 additions and 271 deletions

View File

@ -7,7 +7,7 @@
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="jdk" jdkName="IntelliJ IDEA IU-173.4674.60" jdkType="IDEA JDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

View File

@ -1,7 +1,11 @@
<!--
~ Copyright © 2020 by elfuego.biz
-->
<idea-plugin> <idea-plugin>
<id>biz.elfuego.idea.issues.gitea</id> <id>biz.elfuego.idea.issues.gitea</id>
<name>Gitea issues plugin</name> <name>Gitea issues</name>
<version>1.0</version> <version>1.6</version>
<vendor email="support@elfuego.biz" url="http://elfuego.biz">elfuego.biz</vendor> <vendor email="support@elfuego.biz" url="http://elfuego.biz">elfuego.biz</vendor>
<description><![CDATA[ <description><![CDATA[
@ -9,7 +13,8 @@
]]></description> ]]></description>
<change-notes><![CDATA[ <change-notes><![CDATA[
First implementation.<br> Fixes errors with loading issues without limits (contributed by billlhead).<br>
Fixes searching for issues containing white spaces (contributed by billlhead).<br>
]]> ]]>
</change-notes> </change-notes>
@ -24,5 +29,4 @@
<actions> <actions>
</actions> </actions>
</idea-plugin> </idea-plugin>

View File

@ -1,16 +1,17 @@
/* /*
* Copyright © 2018 by elfuego.biz * Copyright © 2019 by elfuego.biz
*/ */
package biz.elfuego.idea.issues.gitea; package biz.elfuego.idea.issues.gitea;
import biz.elfuego.idea.issues.gitea.model.GiteaProject;
import biz.elfuego.idea.issues.gitea.model.GiteaTask; import biz.elfuego.idea.issues.gitea.model.GiteaTask;
import biz.elfuego.idea.issues.gitea.model.GiteaUser;
import biz.elfuego.idea.issues.gitea.util.Consts; import biz.elfuego.idea.issues.gitea.util.Consts;
import biz.elfuego.idea.issues.gitea.util.Consts.CommentFields; import biz.elfuego.idea.issues.gitea.util.Consts.CommentFields;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.tasks.Comment; import com.intellij.tasks.Comment;
@ -18,12 +19,9 @@ import com.intellij.tasks.CustomTaskState;
import com.intellij.tasks.Task; import com.intellij.tasks.Task;
import com.intellij.tasks.impl.BaseRepositoryImpl; import com.intellij.tasks.impl.BaseRepositoryImpl;
import com.intellij.tasks.impl.SimpleComment; import com.intellij.tasks.impl.SimpleComment;
import com.intellij.util.xmlb.annotations.AbstractCollection;
import com.intellij.util.xmlb.annotations.Tag; import com.intellij.util.xmlb.annotations.Tag;
import com.intellij.util.xmlb.annotations.Transient;
import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.httpclient.methods.StringRequestEntity;
@ -32,7 +30,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -44,9 +45,15 @@ import static biz.elfuego.idea.issues.gitea.util.Utils.*;
*/ */
@Tag("Gitea") @Tag("Gitea")
class GiteaRepository extends BaseRepositoryImpl { class GiteaRepository extends BaseRepositoryImpl {
private static final Logger logger = Logger.getInstance(GiteaRepository.class);
private static final int DEFAULT_PAGE = 10;
private String userId = null; private String userId = null;
private List<GiteaProject> projects = new ArrayList<>(); private String userLogin = null;
private GiteaProject selectedProject = null; private String repoName = null;
private String projName = null;
private String token = null;
private boolean assigned = false;
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
public GiteaRepository() { public GiteaRepository() {
@ -64,20 +71,40 @@ class GiteaRepository extends BaseRepositoryImpl {
public GiteaRepository(GiteaRepository other) { public GiteaRepository(GiteaRepository other) {
super(other); super(other);
userId = other.userId; userId = other.userId;
projects = other.projects; userLogin = other.userLogin;
selectedProject = other.selectedProject; repoName = other.repoName;
projName = other.projName;
token = other.token;
assigned = other.assigned;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof GiteaRepository))
return false;
GiteaRepository other = (GiteaRepository) o;
return equal(userId, other.userId) &&
equal(userLogin, other.userLogin) &&
equal(repoName, other.repoName) &&
equal(projName, other.projName) &&
equal(token, other.token) &&
equal(assigned, other.assigned);
}
private boolean equal(Object o1, Object o2) {
return o1 == null && o2 == null || o1 != null && o1.equals(o2);
} }
@Nullable @Nullable
@Override @Override
public Task findTask(@NotNull String s) throws Exception { public Task findTask(@NotNull String s) /*throws Exception*/ {
// TODO // TODO
return null; return null;
} }
@Override @Override
public Task[] getIssues(@Nullable String query, int offset, int limit, boolean withClosed, @NotNull ProgressIndicator cancelled) throws Exception { public Task[] getIssues(@Nullable String query, int offset, int limit, boolean withClosed, @NotNull ProgressIndicator cancelled) throws Exception {
return getIssues(); return findIssues(query, offset, limit, withClosed, cancelled);
} }
@NotNull @NotNull
@ -147,20 +174,24 @@ class GiteaRepository extends BaseRepositoryImpl {
"application/json", "application/json",
"UTF-8" "UTF-8"
); );
HttpMethod patchTask = getPatchMethod(getApiUrl() + Consts.EndPoint.REPOS + selectedProject.getName() HttpMethod patchTask = getPatchMethod(getApiUrl() + Consts.EndPoint.REPOS + getProject()
+ Consts.EndPoint.ISSUES + "/" + giteaTask.getId(), data); + Consts.EndPoint.ISSUES + "/" + giteaTask.getId(), data);
executeMethod(patchTask); executeMethod(patchTask);
} }
@Override @Override
protected int getFeatures() { protected int getFeatures() {
return NATIVE_SEARCH | STATE_UPDATING; return STATE_UPDATING;
} }
private void doTest() throws Exception { private void doTest() throws Exception {
userId = null; userId = null;
userLogin = null;
checkSetup(); checkSetup();
JsonElement response = executeMethod(new GetMethod(getApiUrl() + Consts.EndPoint.ME)); GetMethod method = new GetMethod(getApiUrl() + Consts.EndPoint.ME);
JsonElement response = executeMethod(method);
if (response == null)
throw new Exception(String.format("%s: %d, %s", Consts.ERROR, method.getStatusCode(), method.getStatusText()));
final JsonObject obj = getObject(response); final JsonObject obj = getObject(response);
if (obj.has("id") && obj.has("login")) if (obj.has("id") && obj.has("login"))
return; return;
@ -181,10 +212,13 @@ class GiteaRepository extends BaseRepositoryImpl {
if (result && StringUtil.isEmpty(this.getUrl())) { if (result && StringUtil.isEmpty(this.getUrl())) {
result = false; result = false;
} }
if (result && StringUtil.isEmpty(this.getUsername())) { if (result && StringUtil.isEmpty(this.getRepoName())) {
result = false; result = false;
} }
if (result && StringUtil.isEmpty(this.getPassword())) { if (result && StringUtil.isEmpty(this.getProjName())) {
result = false;
}
if (result && StringUtil.isEmpty(this.getToken())) {
result = false; result = false;
} }
return result; return result;
@ -197,14 +231,19 @@ class GiteaRepository extends BaseRepositoryImpl {
result += "Server"; result += "Server";
errors++; errors++;
} }
if (StringUtil.isEmpty(getUsername())) { if (StringUtil.isEmpty(getRepoName())) {
result += !StringUtils.isEmpty(result) ? " & " : ""; result += !StringUtils.isEmpty(result) ? " & " : "";
result += "Username"; result += "Repo name";
errors++; errors++;
} }
if (StringUtil.isEmpty(getPassword())) { if (StringUtil.isEmpty(getProjName())) {
result += !StringUtils.isEmpty(result) ? " & " : ""; result += !StringUtils.isEmpty(result) ? " & " : "";
result += "Password"; result += "Project name";
errors++;
}
if (StringUtil.isEmpty(getToken())) {
result += !StringUtils.isEmpty(result) ? " & " : "";
result += "Token";
errors++; errors++;
} }
if (!result.isEmpty()) { if (!result.isEmpty()) {
@ -213,48 +252,85 @@ class GiteaRepository extends BaseRepositoryImpl {
} }
private Task[] getIssues() throws Exception { private Task[] getIssues() throws Exception {
if (ifNoSelectedProj()) return new Task[]{}; return findIssues(null, -1, -1, false, null);
ensureUserId(); }
List<GiteaTaskImpl> result = new ArrayList<>();
final String url = getApiUrl() + Consts.EndPoint.REPOS + selectedProject.getName() + Consts.EndPoint.ISSUES; private Task[] findIssues(String query, int offset, int limit, boolean withClosed, @SuppressWarnings("unused") ProgressIndicator cancelled) throws Exception {
final JsonElement response = executeMethod(new GetMethod(url)); if (!ensureUserId())
return new Task[]{};
StringBuilder qu = new StringBuilder();
if (query != null)
qu.append("?q=").append(URLEncoder.encode(query, "UTF-8"));
if (withClosed)
qu.append("&state=closed");
qu.append("&page=");
if (qu.length() > 0)
qu.setCharAt(0, '?');
List<GiteaTaskImpl> result = new ArrayList<>();
final String url = getApiUrl() + Consts.EndPoint.REPOS + getProject() + Consts.EndPoint.ISSUES + qu.toString();
int firstPage = offset / DEFAULT_PAGE;
for (int p = firstPage + 1; ; p++) {
if (!loadPage(url, result, p, limit - result.size(),
assigned ? ((task) -> task.isAssignedTo(userLogin)) : null))
break;
}
Collections.sort(result);
return result.toArray(new Task[0]);
}
private boolean loadPage(String url, List<GiteaTaskImpl> result, int page, int limit, Function<GiteaTask, Boolean> val) throws Exception {
final JsonElement response = executeMethod(new GetMethod(url + page));
if (response == null)
return false;
JsonArray tasks = getArray(response); JsonArray tasks = getArray(response);
if (tasks.size() < 1)
return false;
for (int i = 0; i < tasks.size(); i++) { for (int i = 0; i < tasks.size(); i++) {
JsonObject current = tasks.get(i).getAsJsonObject(); JsonObject current = tasks.get(i).getAsJsonObject();
GiteaTask raw = new GiteaTask(selectedProject, current); GiteaTask raw = new GiteaTask(getProject(), current);
if (!raw.isValid()) { if (!raw.isValid())
continue;
if (val != null && !val.apply(raw))
continue; continue;
}
GiteaTaskImpl mapped = new GiteaTaskImpl(this, raw); GiteaTaskImpl mapped = new GiteaTaskImpl(this, raw);
result.add(mapped); result.add(mapped);
if (limit > -1) {
limit--;
if (limit < 1)
return false;
}
} }
Collections.sort(result); return true;
Task[] primArray = new Task[result.size()];
return result.toArray(primArray);
} }
private boolean ifNoSelectedProj() { private String getProject() {
return selectedProject == null || selectedProject.getId().equals("-1"); return String.format("%s/%s", repoName, projName);
} }
public Comment[] getComments(GiteaTaskImpl task) throws Exception { Comment[] getComments(GiteaTaskImpl task) throws Exception {
if (ifNoSelectedProj()) return new Comment[]{}; if (!ensureUserId())
ensureUserId(); return new Comment[]{};
List<SimpleComment> result = new ArrayList<>(); List<SimpleComment> result = new ArrayList<>();
final String url = getApiUrl() + Consts.EndPoint.REPOS + selectedProject.getName() + Consts.EndPoint.ISSUES final String url = getApiUrl() + Consts.EndPoint.REPOS + getProject() + Consts.EndPoint.ISSUES
+ "/" + task.getId() + Consts.EndPoint.COMMENTS; + "/" + task.getId() + Consts.EndPoint.COMMENTS;
final JsonElement response = executeMethod(new GetMethod(url)); final JsonElement response = executeMethod(new GetMethod(url));
if (response == null)
return new Comment[]{};
JsonArray comments = getArray(response); JsonArray comments = getArray(response);
for (int i = 0; i < comments.size(); i++) { for (int i = 0; i < comments.size(); i++) {
JsonObject current = comments.get(i).getAsJsonObject(); JsonObject current = comments.get(i).getAsJsonObject();
Date date = getDate(current, CommentFields.DATE); Date date = getDate(current, CommentFields.DATE);
String text = getString(current, CommentFields.TEXT, ""); String text = getString(current, CommentFields.TEXT, "");
JsonObject user = getObject(current, CommentFields.USER); JsonObject juser = getObject(current, CommentFields.USER);
String author = getString(user, CommentFields.FULLNAME, ""); String author = "";
if (author.isEmpty()) if (!juser.isJsonNull()) {
author = getString(user, CommentFields.USERNAME, ""); GiteaUser user = new GiteaUser(juser);
author = user.getName();
}
result.add(new SimpleComment(date, author, text)); result.add(new SimpleComment(date, author, text));
} }
Comment[] primArray = new Comment[result.size()]; Comment[] primArray = new Comment[result.size()];
@ -262,16 +338,16 @@ class GiteaRepository extends BaseRepositoryImpl {
} }
private JsonElement executeMethod(@NotNull HttpMethod method) throws Exception { private JsonElement executeMethod(@NotNull HttpMethod method) throws Exception {
method.addRequestHeader("Authorization", "token " + token);
method.addRequestHeader("Content-type", "application/json"); method.addRequestHeader("Content-type", "application/json");
List authPrefs = Collections.singletonList(AuthPolicy.BASIC);
method.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
getHttpClient().executeMethod(method); getHttpClient().executeMethod(method);
if (method.getStatusCode() != HttpStatus.SC_OK && method.getStatusCode() != HttpStatus.SC_CREATED) { if (method.getStatusCode() != HttpStatus.SC_OK && method.getStatusCode() != HttpStatus.SC_CREATED) {
throw new Exception("Request failed with HTTP error: " + method.getStatusText()); logger.warn(String.format("HTTP error: %d, %s", method.getStatusCode(), method.getStatusText()));
return null;
} }
return new JsonParser().parse(new InputStreamReader(method.getResponseBodyAsStream(), "UTF-8")); return new JsonParser().parse(new InputStreamReader(method.getResponseBodyAsStream(), StandardCharsets.UTF_8));
} }
private HttpMethod getPatchMethod(String url, StringRequestEntity data) { private HttpMethod getPatchMethod(String url, StringRequestEntity data) {
@ -285,42 +361,43 @@ class GiteaRepository extends BaseRepositoryImpl {
return patchMethod; return patchMethod;
} }
private void ensureUserId() throws Exception { @SuppressWarnings("BooleanMethodIsAlwaysInverted")
if (userId == null || userId.isEmpty()) { private boolean ensureUserId() throws Exception {
if (userLogin == null || userLogin.isEmpty()) {
JsonElement result = executeMethod(new GetMethod(getApiUrl() + Consts.EndPoint.ME)); JsonElement result = executeMethod(new GetMethod(getApiUrl() + Consts.EndPoint.ME));
userId = result.getAsJsonObject().get("login").getAsJsonPrimitive().getAsString(); if (result == null)
return false;
userId = result.getAsJsonObject().get("id").getAsJsonPrimitive().getAsString();
userLogin = result.getAsJsonObject().get("login").getAsJsonPrimitive().getAsString();
} }
} return true;
@Transient
List<GiteaProject> getProjectList() throws Exception {
ensureUserId();
if (projects == null || projects.isEmpty()) {
JsonElement response = executeMethod(new GetMethod(getApiUrl() + Consts.EndPoint.REPOS_SEARCH + userId));
JsonArray query = getOkData(response);
List<GiteaProject> result = new ArrayList<>();
for (int i = 0; i < query.size(); i++) {
JsonObject current = getObject(query.get(i));
GiteaProject project = new GiteaProject().setId(getString(current, "id", ""))
.setName(getString(current, "full_name", ""));
if (!project.isValid()) {
continue;
}
result.add(project);
}
projects = result;
}
return projects;
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public GiteaProject getSelectedProject() { public String getRepoName() {
return selectedProject; return repoName;
}
public void setRepoName(String repoName) {
this.repoName = repoName;
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public void setSelectedProject(GiteaProject selectedProject) { public String getProjName() {
this.selectedProject = selectedProject; return projName;
}
public void setProjName(String projName) {
this.projName = projName;
}
@SuppressWarnings("WeakerAccess")
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
} }
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
@ -334,13 +411,20 @@ class GiteaRepository extends BaseRepositoryImpl {
} }
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
@AbstractCollection(surroundWithTag = false, elementTag = "GiteaProject", elementTypes = GiteaProject.class) public String getUserLogin() {
public List<GiteaProject> getProjects() { return userLogin;
return projects;
} }
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
public void setProjects(List<GiteaProject> projects) { public void setUserLogin(String userLogin) {
this.projects = projects; this.userLogin = userLogin;
}
public void setAssigned(boolean assigned) {
this.assigned = assigned;
}
public boolean getAssigned() {
return assigned;
} }
} }

View File

@ -1,104 +1,101 @@
/* /*
* Copyright © 2018 by elfuego.biz * Copyright © 2019 by elfuego.biz
*/ */
package biz.elfuego.idea.issues.gitea; package biz.elfuego.idea.issues.gitea;
import biz.elfuego.idea.issues.gitea.model.GiteaProject;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.tasks.config.BaseRepositoryEditor; import com.intellij.tasks.config.BaseRepositoryEditor;
import com.intellij.tasks.impl.TaskUiUtil;
import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBLabel;
import com.intellij.util.Consumer; import com.intellij.util.Consumer;
import com.intellij.util.ui.FormBuilder; import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.UIUtil; import org.jdesktop.swingx.HorizontalLayout;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import javax.swing.*; import javax.swing.*;
import java.util.List;
/** /**
* @author Roman Pedchenko <elfuego@elfuego.biz> * @author Roman Pedchenko <elfuego@elfuego.biz>
* @date 2018.06.30 * @date 2018.06.30
*/ */
public class GiteaRepositoryEditor extends BaseRepositoryEditor<GiteaRepository> { public class GiteaRepositoryEditor extends BaseRepositoryEditor<GiteaRepository> {
private JBLabel projectLabel; private JBLabel repoLabel;
private ComboBox projectBox; private JTextField repoName;
private JTextField projName;
private JBLabel tokenLabel;
private JPasswordField token;
private JBLabel assignedLabel;
private JCheckBox assignedCheckBox;
GiteaRepositoryEditor(GiteaRepository repository, Project project, Consumer<GiteaRepository> consumer) { GiteaRepositoryEditor(GiteaRepository repository, Project project, Consumer<GiteaRepository> consumer) {
super(project, repository, consumer); super(project, repository, consumer);
installListener(projectBox); repoName.setText(repository.getRepoName());
projName.setText(repository.getProjName());
token.setText(repository.getToken());
assignedCheckBox.setSelected(repository.getAssigned());
installListener(repoName);
installListener(projName);
installListener(token);
installListener(assignedCheckBox);
UIUtil.invokeLaterIfNeeded(new Runnable() { myUserNameText.setVisible(false);
@Override myPasswordText.setVisible(false);
public void run() { myUserNameText.setEnabled(false);
initialize(); myPasswordText.setEnabled(false);
} myUsernameLabel.setVisible(false);
}); myPasswordLabel.setVisible(false);
}
private void initialize() {
if (myRepository.isConfigured()) {
new FetchProjectsTask().queue();
}
} }
@Nullable @Nullable
@Override @Override
protected JComponent createCustomPanel() { protected JComponent createCustomPanel() {
projectBox = new ComboBox(300); JPanel panel = new JPanel();
projectBox.setRenderer(new TaskUiUtil.SimpleComboBoxRenderer("Set URL, username, and password")); panel.setLayout(new HorizontalLayout());
projectLabel = new JBLabel("Project:", SwingConstants.RIGHT); repoName = new JTextField(20);
projectLabel.setLabelFor(projectBox); repoLabel = new JBLabel("Repository:", SwingConstants.RIGHT);
repoLabel.setLabelFor(panel);
panel.add(repoName);
projName = new JTextField(30);
JBLabel projLabel = new JBLabel(" / Project: ", SwingConstants.RIGHT);
projLabel.setLabelFor(projName);
panel.add(projLabel);
panel.add(projName);
token = new JPasswordField();
tokenLabel = new JBLabel("Token:", SwingConstants.RIGHT);
tokenLabel.setLabelFor(token);
assignedCheckBox = new JCheckBox();
assignedLabel = new JBLabel("Only issues assigned to me:", SwingConstants.RIGHT);
assignedLabel.setLabelFor(assignedCheckBox);
return new FormBuilder().setAlignLabelOnRight(true) return new FormBuilder().setAlignLabelOnRight(true)
.addLabeledComponent(projectLabel, projectBox) .addLabeledComponent(repoLabel, panel)
.addLabeledComponent(tokenLabel, token)
.addLabeledComponent(assignedLabel, assignedCheckBox)
.getPanel(); .getPanel();
} }
@Override @Override
public void setAnchor(@Nullable JComponent anchor) { public void setAnchor(@Nullable JComponent anchor) {
super.setAnchor(anchor); super.setAnchor(anchor);
projectLabel.setAnchor(anchor); repoLabel.setAnchor(anchor);
} tokenLabel.setAnchor(anchor);
// assignedLabel.setAnchor(anchor);
@Override
protected void afterTestConnection(boolean connectionSuccessful) {
if (connectionSuccessful) {
new FetchProjectsTask().queue();
}
} }
@Override @Override
public void apply() { public void apply() {
super.apply(); super.apply();
myRepository.setSelectedProject((GiteaProject) projectBox.getSelectedItem()); myRepository.setRepoName(repoName.getText());
myRepository.setProjName(projName.getText());
//noinspection deprecation
myRepository.setToken(token.getText());
myRepository.setAssigned(assignedCheckBox.isSelected());
myTestButton.setEnabled(myRepository.isConfigured()); myTestButton.setEnabled(myRepository.isConfigured());
} }
private class FetchProjectsTask extends TaskUiUtil.ComboBoxUpdater<GiteaProject> {
private FetchProjectsTask() {
super(GiteaRepositoryEditor.this.myProject, "Downloading Gitea projects...", projectBox);
}
@Override
public GiteaProject getExtraItem() {
return GiteaProject.UNSPECIFIED_PROJECT;
}
@Nullable
@Override
public GiteaProject getSelectedItem() {
return myRepository.getSelectedProject();
}
@NotNull
@Override
protected List<GiteaProject> fetch(@NotNull ProgressIndicator indicator) throws Exception {
return myRepository.getProjectList();
}
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 by elfuego.biz * Copyright © 2019 by elfuego.biz
*/ */
package biz.elfuego.idea.issues.gitea; package biz.elfuego.idea.issues.gitea;

View File

@ -1,9 +1,8 @@
/* /*
* Copyright © 2018 by elfuego.biz * Copyright © 2019 by elfuego.biz
*/ */
package biz.elfuego.idea.issues.gitea; package biz.elfuego.idea.issues.gitea;
import biz.elfuego.idea.issues.gitea.model.GiteaProject;
import biz.elfuego.idea.issues.gitea.model.GiteaTask; import biz.elfuego.idea.issues.gitea.model.GiteaTask;
import biz.elfuego.idea.issues.gitea.util.Consts; import biz.elfuego.idea.issues.gitea.util.Consts;
import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.IconLoader;
@ -22,10 +21,10 @@ import java.util.Date;
* @date 2018.06.30 * @date 2018.06.30
*/ */
public class GiteaTaskImpl extends Task implements Comparable<GiteaTaskImpl> { public class GiteaTaskImpl extends Task implements Comparable<GiteaTaskImpl> {
private GiteaProject project; private final String project;
private GiteaRepository repository; private final GiteaRepository repository;
private Comment[] comments; private Comment[] comments;
GiteaTask task; final GiteaTask task;
GiteaTaskImpl(@NotNull GiteaRepository repository, @NotNull GiteaTask task) { GiteaTaskImpl(@NotNull GiteaRepository repository, @NotNull GiteaTask task) {
this.repository = repository; this.repository = repository;
@ -107,7 +106,7 @@ public class GiteaTaskImpl extends Task implements Comparable<GiteaTaskImpl> {
@Nullable @Nullable
@Override @Override
public String getIssueUrl() { public String getIssueUrl() {
return repository.getUrl() + "/" + project.getName() + Consts.EndPoint.ISSUES + "/" + task.getId(); return repository.getUrl() + "/" + project + Consts.EndPoint.ISSUES + "/" + task.getId();
} }
@Override @Override

View File

@ -1,71 +0,0 @@
/*
* Copyright © 2018 by elfuego.biz
*/
package biz.elfuego.idea.issues.gitea.model;
import biz.elfuego.idea.issues.gitea.util.Consts;
/**
* @author Roman Pedchenko <elfuego@elfuego.biz>
* @date 2018.06.30
*/
public class GiteaProject {
private String id;
private String name;
public String getId() {
return id;
}
public GiteaProject setId(String mProjectId) {
this.id = mProjectId;
return this;
}
public String getName() {
return name;
}
public GiteaProject setName(String mProjectTitle) {
this.name = mProjectTitle;
return this;
}
public boolean isValid() {
return !(id.equals("") || name.equals(""));
}
@Override
public String toString() {
return name != null ? name : super.toString();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
GiteaProject that = (GiteaProject) o;
return (id != null ? id.equals(that.id) : that.id == null) && (name != null ? name.equals(that.name) : that.name == null);
}
public static final GiteaProject UNSPECIFIED_PROJECT = new GiteaProject() {
@Override
public String getName() {
return "-- Select A Project (Required) --";
}
@Override
public String getId() {
return Consts.UNSPEC_PROJ_ID;
}
@Override
public String toString() {
return getName();
}
};
}

View File

@ -1,41 +1,46 @@
/* /*
* Copyright © 2018 by elfuego.biz * Copyright © 2019 by elfuego.biz
*/ */
package biz.elfuego.idea.issues.gitea.model; package biz.elfuego.idea.issues.gitea.model;
import biz.elfuego.idea.issues.gitea.util.Consts.TaskFields; import biz.elfuego.idea.issues.gitea.util.Consts.TaskFields;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import org.apache.http.util.TextUtils; import org.apache.http.util.TextUtils;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import static biz.elfuego.idea.issues.gitea.util.Utils.getDate; import static biz.elfuego.idea.issues.gitea.util.Utils.*;
import static biz.elfuego.idea.issues.gitea.util.Utils.getString;
/** /**
* @author Roman Pedchenko <elfuego@elfuego.biz> * @author Roman Pedchenko <elfuego@elfuego.biz>
* @date 2018.06.30 * @date 2018.06.30
*/ */
public class GiteaTask { public class GiteaTask {
private GiteaProject project; private String project;
private String id; private String id;
private String title; private String title;
private String description; private String description;
private Date createdAt; private Date createdAt;
private Date updatedAt; private Date updatedAt;
private String state; private String state;
private String assignee; private GiteaUser assignee;
private List<GiteaUser> assignees;
public GiteaTask(GiteaProject project, JsonObject json) { public GiteaTask(String project, JsonObject json) throws Exception {
this.project = project; this.project = project;
this.fromJson(json); this.fromJson(json);
} }
public GiteaProject getProject() { public String getProject() {
return project; return project;
} }
public void setProject(GiteaProject project) { @SuppressWarnings("unused")
public void setProject(String project) {
this.project = project; this.project = project;
} }
@ -88,20 +93,28 @@ public class GiteaTask {
return state; return state;
} }
@SuppressWarnings("WeakerAccess")
public void setState(String state) { public void setState(String state) {
this.state = state; this.state = state;
} }
public String getAssignee() { @SuppressWarnings("unused")
public GiteaUser getAssignee() {
return assignee; return assignee;
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public void setAssignee(String assignee) { public void setAssignee(GiteaUser assignee) {
this.assignee = assignee; this.assignee = assignee;
} }
public List<GiteaUser> getAssignees() {
return assignees;
}
public void setAssignees(List<GiteaUser> assignees) {
this.assignees = assignees;
}
public boolean isValid() { public boolean isValid() {
return !(TextUtils.isEmpty(id) || return !(TextUtils.isEmpty(id) ||
TextUtils.isEmpty(title) || TextUtils.isEmpty(title) ||
@ -110,27 +123,32 @@ public class GiteaTask {
TextUtils.isEmpty(state)); TextUtils.isEmpty(state));
} }
private void fromJson(JsonObject current) { public boolean isAssignedTo(String login) {
if (current.has(TaskFields.ID)) { if (assignee != null && assignee.getLogin().equals(login))
this.setId(getString(current, TaskFields.ID, "")); return true;
} if (assignees != null)
if (current.has(TaskFields.TITLE)) { for (GiteaUser u : assignees)
this.setTitle(getString(current, TaskFields.TITLE, "")); if (u.getLogin().equals(login))
} return true;
if (current.has(TaskFields.DESCRIPTION)) { return false;
this.setDescription(getString(current, TaskFields.DESCRIPTION, "")); }
}
if (current.has(TaskFields.CREATEDAT)) { private void fromJson(JsonObject current) throws Exception {
this.setCreatedAt(getDate(current, TaskFields.CREATEDAT)); this.setId(getString(current, TaskFields.NUMBER, ""));
} this.setTitle(getString(current, TaskFields.TITLE, ""));
if (current.has(TaskFields.UPDATEDAT)) { this.setDescription(getString(current, TaskFields.DESCRIPTION, ""));
this.setUpdatedAt(getDate(current, TaskFields.UPDATEDAT)); this.setCreatedAt(getDate(current, TaskFields.CREATEDAT));
} this.setUpdatedAt(getDate(current, TaskFields.UPDATEDAT));
if (current.has(TaskFields.STATE)) { this.setState(getString(current, TaskFields.STATE, ""));
this.setState(getString(current, TaskFields.STATE, "")); if (current.has(TaskFields.ASSIGNEE) && current.get(TaskFields.ASSIGNEE).isJsonObject())
} this.setAssignee(new GiteaUser(getObject(current, TaskFields.ASSIGNEE)));
if (current.has(TaskFields.ASSIGNEE)) { if (current.has(TaskFields.ASSIGNEES) && current.get(TaskFields.ASSIGNEES).isJsonArray()) {
this.setAssignee(getString(current, TaskFields.ASSIGNEE, "")); JsonArray arr = getArray(current.get(TaskFields.ASSIGNEES));
List<GiteaUser> assignees1 = new ArrayList<>();
for (JsonElement el : arr)
if (el.isJsonObject())
assignees1.add(new GiteaUser(getObject(el)));
this.setAssignees(assignees1);
} }
} }
} }

View File

@ -0,0 +1,108 @@
/*
* Copyright © 2019 by elfuego.biz
*/
package biz.elfuego.idea.issues.gitea.model;
import biz.elfuego.idea.issues.gitea.util.Consts;
import com.google.gson.JsonObject;
import static biz.elfuego.idea.issues.gitea.util.Utils.getString;
/**
* @author Roman Pedchenko <elfuego@elfuego.biz>
* @date 2019.04.04
*/
public class GiteaUser {
private String id;
private String login;
private String username;
private String full_name;
private String email;
private String avatar_url;
private String language;
public GiteaUser(JsonObject json) {
this.fromJson(json);
}
public String getId() {
return id;
}
@SuppressWarnings("WeakerAccess")
public void setId(String id) {
this.id = id;
}
public String getLogin() {
return login;
}
@SuppressWarnings("WeakerAccess")
public void setLogin(String login) {
this.login = login;
}
public String getUsername() {
return username;
}
@SuppressWarnings("WeakerAccess")
public void setUsername(String username) {
this.username = username;
}
public String getFull_name() {
return full_name;
}
@SuppressWarnings("WeakerAccess")
public void setFull_name(String full_name) {
this.full_name = full_name;
}
public String getEmail() {
return email;
}
@SuppressWarnings("WeakerAccess")
public void setEmail(String email) {
this.email = email;
}
public String getAvatar_url() {
return avatar_url;
}
@SuppressWarnings("WeakerAccess")
public void setAvatar_url(String avatar_url) {
this.avatar_url = avatar_url;
}
public String getLanguage() {
return language;
}
@SuppressWarnings("WeakerAccess")
public void setLanguage(String language) {
this.language = language;
}
public String getName() {
if (!full_name.isEmpty())
return full_name;
if (!username.isEmpty())
return username;
return login;
}
private void fromJson(JsonObject current) {
this.setId(getString(current, Consts.UserFields.ID, ""));
this.setLogin(getString(current, Consts.UserFields.LOGIN, ""));
this.setUsername(getString(current, Consts.UserFields.USERNAME, ""));
this.setFull_name(getString(current, Consts.UserFields.FULL_NAME, ""));
this.setEmail(getString(current, Consts.UserFields.EMAIL, ""));
this.setAvatar_url(getString(current, Consts.UserFields.AVATAR_URL, ""));
this.setLanguage(getString(current, Consts.UserFields.LANGUAGE, ""));
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 by elfuego.biz * Copyright © 2019 by elfuego.biz
*/ */
package biz.elfuego.idea.issues.gitea.util; package biz.elfuego.idea.issues.gitea.util;
@ -11,8 +11,25 @@ public class Consts {
public static final String ERROR = "Error communicating to the server"; public static final String ERROR = "Error communicating to the server";
public static final String UNSPEC_PROJ_ID = "--"; public static final String UNSPEC_PROJ_ID = "--";
public enum ProjectFilter {
GENERAL("General search"),
CONTRUBUTOR("Owned and participated by me"),
OWNER("Owned by me");
private final String message;
ProjectFilter(String message) {
this.message = message;
}
@Override
public String toString() {
return this.message;
}
}
public interface Url { public interface Url {
String DEFAULT = "https://git2.elfuego.biz:444"; String DEFAULT = "https://try.gitea.io";
} }
public interface EndPoint { public interface EndPoint {
@ -21,28 +38,39 @@ public class Consts {
String REPOS = "/repos/"; String REPOS = "/repos/";
String ISSUES = "/issues"; String ISSUES = "/issues";
String COMMENTS = "/comments"; String COMMENTS = "/comments";
String REPOS_SEARCH = REPOS + "search?uid="; String REPOS_SEARCH = REPOS + "search";
String REPOS_SEARCH_UID = REPOS + "search?uid=";
String REPOS_SEARCH_UID_EX = REPOS + "search?exclusive=true&uid=";
} }
public enum States { public enum States {
OPEN, CLOSED; OPEN, CLOSED
} }
public interface TaskFields { public interface TaskFields {
static final String ID = "id"; String NUMBER = "number";
static final String TITLE = "title"; String TITLE = "title";
static final String DESCRIPTION = "body"; String DESCRIPTION = "body";
static final String CREATEDAT = "created_at"; String CREATEDAT = "created_at";
static final String UPDATEDAT = "updated_at"; String UPDATEDAT = "updated_at";
static final String STATE = "state"; String STATE = "state";
static final String ASSIGNEE = "assignee"; String ASSIGNEE = "assignee";
String ASSIGNEES = "assignees";
} }
public interface CommentFields { public interface CommentFields {
static final String DATE = "updated_at"; String DATE = "updated_at";
static final String TEXT = "body"; String TEXT = "body";
static final String USER = "user"; String USER = "user";
static final String FULLNAME = "full_name"; }
static final String USERNAME = "username";
public interface UserFields {
String ID = "id";
String LOGIN = "login";
String FULL_NAME = "full_name";
String EMAIL = "email";
String AVATAR_URL = "avatar_url";
String LANGUAGE = "language";
String USERNAME = "username";
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 by elfuego.biz * Copyright © 2019 by elfuego.biz
*/ */
package biz.elfuego.idea.issues.gitea.util; package biz.elfuego.idea.issues.gitea.util;
@ -44,7 +44,7 @@ public class Utils {
int inset = 6; int inset = 6;
String s0 = input.substring(0, input.length() - inset); String s0 = input.substring(0, input.length() - inset);
String s1 = input.substring(input.length() - inset, input.length()); String s1 = input.substring(input.length() - inset);
input = s0 + "GMT" + s1; input = s0 + "GMT" + s1;
} }