From 85aa2ad4e6df8dba05950154b6e4e496891b7e78 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 16 Nov 2016 19:10:37 -0800 Subject: [PATCH] Added reaction API --- .../org/kohsuke/github/GHCommitComment.java | 27 ++++++++- src/main/java/org/kohsuke/github/GHIssue.java | 27 ++++++++- .../org/kohsuke/github/GHIssueComment.java | 29 +++++++++- .../github/GHPullRequestReviewComment.java | 27 ++++++++- .../java/org/kohsuke/github/GHReaction.java | 55 +++++++++++++++++++ .../java/org/kohsuke/github/Previews.java | 1 + .../java/org/kohsuke/github/Reactable.java | 23 ++++++++ .../org/kohsuke/github/ReactionContent.java | 40 ++++++++++++++ src/test/java/org/kohsuke/github/AppTest.java | 15 +++++ 9 files changed, 239 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHReaction.java create mode 100644 src/main/java/org/kohsuke/github/Reactable.java create mode 100644 src/main/java/org/kohsuke/github/ReactionContent.java diff --git a/src/main/java/org/kohsuke/github/GHCommitComment.java b/src/main/java/org/kohsuke/github/GHCommitComment.java index 79f19a6e6..3543b5fdb 100644 --- a/src/main/java/org/kohsuke/github/GHCommitComment.java +++ b/src/main/java/org/kohsuke/github/GHCommitComment.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.net.URL; import java.util.Date; +import static org.kohsuke.github.Previews.SQUIRREL_GIRL; + /** * A comment attached to a commit (or a specific line in a specific file of a commit.) * @@ -15,7 +17,7 @@ import java.util.Date; */ @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"}, justification = "JSON API") -public class GHCommitComment extends GHObject { +public class GHCommitComment extends GHObject implements Reactable { private GHRepository owner; String body, html_url, commit_id; @@ -86,6 +88,29 @@ public class GHCommitComment extends GHObject { this.body = body; } + @Preview @Deprecated + public GHReaction createReaction(ReactionContent content) throws IOException { + return new Requester(owner.root) + .withPreview(SQUIRREL_GIRL) + .with("content", content.getContent()) + .to(getApiTail()+"/reactions", GHReaction.class).wrap(owner.root); + } + + @Preview @Deprecated + public PagedIterable listReactions() { + return new PagedIterable() { + public PagedIterator _iterator(int pageSize) { + return new PagedIterator(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiTail()+"/reactions", GHReaction[].class, pageSize)) { + @Override + protected void wrapUp(GHReaction[] page) { + for (GHReaction c : page) + c.wrap(owner.root); + } + }; + } + }; + } + /** * Deletes this comment. */ diff --git a/src/main/java/org/kohsuke/github/GHIssue.java b/src/main/java/org/kohsuke/github/GHIssue.java index a5afad6d2..f02439daa 100644 --- a/src/main/java/org/kohsuke/github/GHIssue.java +++ b/src/main/java/org/kohsuke/github/GHIssue.java @@ -35,6 +35,8 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import static org.kohsuke.github.Previews.SQUIRREL_GIRL; + /** * Represents an issue on GitHub. * @@ -44,7 +46,7 @@ import java.util.Locale; * @see GitHub#searchIssues() * @see GHIssueSearchBuilder */ -public class GHIssue extends GHObject { +public class GHIssue extends GHObject implements Reactable{ GitHub root; GHRepository owner; @@ -217,6 +219,29 @@ public class GHIssue extends GHObject { }; } + @Preview @Deprecated + public GHReaction createReaction(ReactionContent content) throws IOException { + return new Requester(owner.root) + .withPreview(SQUIRREL_GIRL) + .with("content", content.getContent()) + .to(getApiRoute()+"/reactions", GHReaction.class).wrap(root); + } + + @Preview @Deprecated + public PagedIterable listReactions() { + return new PagedIterable() { + public PagedIterator _iterator(int pageSize) { + return new PagedIterator(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) { + @Override + protected void wrapUp(GHReaction[] page) { + for (GHReaction c : page) + c.wrap(owner.root); + } + }; + } + }; + } + protected String getApiRoute() { return getIssuesApiRoute(); } diff --git a/src/main/java/org/kohsuke/github/GHIssueComment.java b/src/main/java/org/kohsuke/github/GHIssueComment.java index 18d08bc7f..a98f6f639 100644 --- a/src/main/java/org/kohsuke/github/GHIssueComment.java +++ b/src/main/java/org/kohsuke/github/GHIssueComment.java @@ -26,12 +26,14 @@ package org.kohsuke.github; import java.io.IOException; import java.net.URL; +import static org.kohsuke.github.Previews.SQUIRREL_GIRL; + /** * Comment to the issue * * @author Kohsuke Kawaguchi */ -public class GHIssueComment extends GHObject { +public class GHIssueComment extends GHObject implements Reactable { GHIssue owner; private String body, gravatar_id; @@ -93,7 +95,30 @@ public class GHIssueComment extends GHObject { public void delete() throws IOException { new Requester(owner.root).method("DELETE").to(getApiRoute()); } - + + @Preview @Deprecated + public GHReaction createReaction(ReactionContent content) throws IOException { + return new Requester(owner.root) + .withPreview(SQUIRREL_GIRL) + .with("content", content.getContent()) + .to(getApiRoute()+"/reactions", GHReaction.class).wrap(owner.root); + } + + @Preview @Deprecated + public PagedIterable listReactions() { + return new PagedIterable() { + public PagedIterator _iterator(int pageSize) { + return new PagedIterator(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) { + @Override + protected void wrapUp(GHReaction[] page) { + for (GHReaction c : page) + c.wrap(owner.root); + } + }; + } + }; + } + private String getApiRoute() { return "/repos/"+owner.getRepository().getOwnerName()+"/"+owner.getRepository().getName()+"/issues/comments/" + id; } diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java index 8cb497e16..05784b507 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java @@ -26,6 +26,8 @@ package org.kohsuke.github; import java.io.IOException; import java.net.URL; +import static org.kohsuke.github.Previews.*; + /** * Review comment to the pull request * @@ -33,7 +35,7 @@ import java.net.URL; * @see GHPullRequest#listReviewComments() * @see GHPullRequest#createReviewComment(String, String, String, int) */ -public class GHPullRequestReviewComment extends GHObject { +public class GHPullRequestReviewComment extends GHObject implements Reactable { GHPullRequest owner; private String body; @@ -103,4 +105,27 @@ public class GHPullRequestReviewComment extends GHObject { public void delete() throws IOException { new Requester(owner.root).method("DELETE").to(getApiRoute()); } + + @Preview @Deprecated + public GHReaction createReaction(ReactionContent content) throws IOException { + return new Requester(owner.root) + .withPreview(SQUIRREL_GIRL) + .with("content", content.getContent()) + .to(getApiRoute()+"/reactions", GHReaction.class).wrap(owner.root); + } + + @Preview @Deprecated + public PagedIterable listReactions() { + return new PagedIterable() { + public PagedIterator _iterator(int pageSize) { + return new PagedIterator(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) { + @Override + protected void wrapUp(GHReaction[] page) { + for (GHReaction c : page) + c.wrap(owner.root); + } + }; + } + }; + } } diff --git a/src/main/java/org/kohsuke/github/GHReaction.java b/src/main/java/org/kohsuke/github/GHReaction.java new file mode 100644 index 000000000..55b26365e --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHReaction.java @@ -0,0 +1,55 @@ +package org.kohsuke.github; + +import java.io.IOException; +import java.net.URL; + +import static org.kohsuke.github.Previews.SQUIRREL_GIRL; + +/** + * Reaction to issue, comment, PR, and so on. + * + * @author Kohsuke Kawaguchi + * @see Reactable + */ +@Preview @Deprecated +public class GHReaction extends GHObject { + private GitHub root; + + private GHUser user; + private ReactionContent content; + + /*package*/ GHReaction wrap(GitHub root) { + this.root = root; + user.wrapUp(root); + return this; + } + + /** + * The kind of reaction left. + */ + public ReactionContent getContent() { + return content; + } + + /** + * User who left the reaction. + */ + public GHUser getUser() { + return user; + } + + /** + * Reaction has no HTML URL. Don't call this method. + */ + @Deprecated + public URL getHtmlUrl() { + return null; + } + + /** + * Removes this reaction. + */ + public void delete() throws IOException { + new Requester(root).method("DELETE").withPreview(SQUIRREL_GIRL).to("/reactions/"+id); + } +} diff --git a/src/main/java/org/kohsuke/github/Previews.java b/src/main/java/org/kohsuke/github/Previews.java index a5d061cbd..f95a28b42 100644 --- a/src/main/java/org/kohsuke/github/Previews.java +++ b/src/main/java/org/kohsuke/github/Previews.java @@ -6,4 +6,5 @@ package org.kohsuke.github; /*package*/ class Previews { static final String LOKI = "application/vnd.github.loki-preview+json"; static final String DRAX = "application/vnd.github.drax-preview+json"; + static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview"; } diff --git a/src/main/java/org/kohsuke/github/Reactable.java b/src/main/java/org/kohsuke/github/Reactable.java new file mode 100644 index 000000000..d8821362c --- /dev/null +++ b/src/main/java/org/kohsuke/github/Reactable.java @@ -0,0 +1,23 @@ +package org.kohsuke.github; + +import java.io.IOException; + +/** + * Those {@link GHObject}s that can have {@linkplain GHReaction reactions}. + * + * @author Kohsuke Kawaguchi + */ +@Preview @Deprecated +public interface Reactable { + /** + * List all the reactions left to this object. + */ + @Preview @Deprecated + PagedIterable listReactions(); + + /** + * Leaves a reaction to this object. + */ + @Preview @Deprecated + GHReaction createReaction(ReactionContent content) throws IOException; +} diff --git a/src/main/java/org/kohsuke/github/ReactionContent.java b/src/main/java/org/kohsuke/github/ReactionContent.java new file mode 100644 index 000000000..57a204b56 --- /dev/null +++ b/src/main/java/org/kohsuke/github/ReactionContent.java @@ -0,0 +1,40 @@ +package org.kohsuke.github; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Content of reactions. + * + * @author Kohsuke Kawaguchi + * @see API documentation + * @see GHReaction + */ +public enum ReactionContent { + PLUS_ONE("+1"), + MINUS_ONE("-1"), + LAUGH("laugh"), + CONFUSED("confused"), + HEART("heart"), + HOORAY("hooray"); + + private final String content; + + ReactionContent(String content) { + this.content = content; + } + + @JsonValue + public String getContent() { + return content; + } + + @JsonCreator + public static ReactionContent forContent(String content) { + for (ReactionContent c : ReactionContent.values()) { + if (c.getContent().equals(content)) + return c; + } + return null; + } +} diff --git a/src/test/java/org/kohsuke/github/AppTest.java b/src/test/java/org/kohsuke/github/AppTest.java index 5a2758257..15f4ba9c7 100755 --- a/src/test/java/org/kohsuke/github/AppTest.java +++ b/src/test/java/org/kohsuke/github/AppTest.java @@ -870,6 +870,21 @@ public class AppTest extends AbstractGitHubApiTestBase { System.out.println(r.getIssue(1)); } + @Test + public void reactions() throws Exception { + GHIssue i = gitHub.getRepository("kohsuke/github-api").getIssue(311); + + // retrieval + GHReaction r = i.listReactions().iterator().next(); + assert r.getUser().getName().equals("kohsuke"); + assert r.getContent()==ReactionContent.HEART; + + // CRUD + GHReaction a = i.createReaction(ReactionContent.HOORAY); + assert a.getUser().equals(gitHub.getMyself()); + a.delete(); + } + private void kohsuke() { String login = getUser().getLogin(); Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));