From 4b82adcf811c8c876519bda02127dc7ec4dbfb4a Mon Sep 17 00:00:00 2001 From: Thomas Couchoud <1688389+RakSrinaNa@users.noreply.github.com> Date: Mon, 29 Aug 2022 18:01:18 +0200 Subject: [PATCH] add CommunityMomentCallout_Claim GQL call --- .../miner/api/gql/GQLApi.java | 7 ++ .../CommunityMomentCalloutClaimData.java | 23 ++++ .../CommunityMomentCalloutClaimOperation.java | 27 +++++ .../InputData.java | 20 ++++ .../types/ClaimCommunityMomentPayload.java | 30 +++++ .../api/gql/data/types/CommunityMoment.java | 24 ++++ .../miner/api/gql/data/types/GQLType.java | 2 + .../gql/GQLApiClaimCommunityMomentTest.java | 107 ++++++++++++++++++ .../communityMomentCalloutClaim_success.json | 17 +++ 9 files changed, 257 insertions(+) create mode 100644 miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/CommunityMomentCalloutClaimData.java create mode 100644 miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/CommunityMomentCalloutClaimOperation.java create mode 100644 miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/InputData.java create mode 100644 miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/ClaimCommunityMomentPayload.java create mode 100644 miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/CommunityMoment.java create mode 100644 miner/src/test/java/fr/raksrinana/channelpointsminer/miner/api/gql/GQLApiClaimCommunityMomentTest.java create mode 100644 miner/src/test/resources/api/gql/communityMomentCalloutClaim_success.json diff --git a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/GQLApi.java b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/GQLApi.java index 5232f34a..f6c35164 100644 --- a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/GQLApi.java +++ b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/GQLApi.java @@ -11,6 +11,8 @@ import fr.raksrinana.channelpointsminer.miner.api.gql.data.chatroombanstatus.ChatRoomBanStatusOperation; import fr.raksrinana.channelpointsminer.miner.api.gql.data.claimcommunitypoints.ClaimCommunityPointsData; import fr.raksrinana.channelpointsminer.miner.api.gql.data.claimcommunitypoints.ClaimCommunityPointsOperation; +import fr.raksrinana.channelpointsminer.miner.api.gql.data.communitymomentcalloutclaim.CommunityMomentCalloutClaimData; +import fr.raksrinana.channelpointsminer.miner.api.gql.data.communitymomentcalloutclaim.CommunityMomentCalloutClaimOperation; import fr.raksrinana.channelpointsminer.miner.api.gql.data.dropshighlightserviceavailabledrops.DropsHighlightServiceAvailableDropsData; import fr.raksrinana.channelpointsminer.miner.api.gql.data.dropshighlightserviceavailabledrops.DropsHighlightServiceAvailableDropsOperation; import fr.raksrinana.channelpointsminer.miner.api.gql.data.dropspageclaimdroprewards.DropsPageClaimDropRewardsData; @@ -115,6 +117,11 @@ public Optional> claimCommunityPoints(@Not return postRequest(new ClaimCommunityPointsOperation(channelId, claimId)); } + @NotNull + public Optional> claimCommunityMoment(@NotNull String momentId){ + return postRequest(new CommunityMomentCalloutClaimOperation(momentId)); + } + @NotNull public Optional> joinRaid(@NotNull String raidId){ return postRequest(new JoinRaidOperation(raidId)); diff --git a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/CommunityMomentCalloutClaimData.java b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/CommunityMomentCalloutClaimData.java new file mode 100644 index 00000000..48483311 --- /dev/null +++ b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/CommunityMomentCalloutClaimData.java @@ -0,0 +1,23 @@ +package fr.raksrinana.channelpointsminer.miner.api.gql.data.communitymomentcalloutclaim; + +import com.fasterxml.jackson.annotation.JsonProperty; +import fr.raksrinana.channelpointsminer.miner.api.gql.data.types.ClaimCommunityMomentPayload; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.jetbrains.annotations.NotNull; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EqualsAndHashCode +@ToString +public class CommunityMomentCalloutClaimData{ + @JsonProperty("claimCommunityMoment") + @NotNull + private ClaimCommunityMomentPayload moment; +} diff --git a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/CommunityMomentCalloutClaimOperation.java b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/CommunityMomentCalloutClaimOperation.java new file mode 100644 index 00000000..f91c6ebb --- /dev/null +++ b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/CommunityMomentCalloutClaimOperation.java @@ -0,0 +1,27 @@ +package fr.raksrinana.channelpointsminer.miner.api.gql.data.communitymomentcalloutclaim; + +import fr.raksrinana.channelpointsminer.miner.api.gql.data.GQLResponse; +import fr.raksrinana.channelpointsminer.miner.api.gql.data.IGQLOperation; +import fr.raksrinana.channelpointsminer.miner.api.gql.data.PersistedQueryExtension; +import kong.unirest.core.GenericType; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; +import org.jetbrains.annotations.NotNull; + +@Getter +@EqualsAndHashCode(callSuper = true) +@ToString +public class CommunityMomentCalloutClaimOperation extends IGQLOperation{ + public CommunityMomentCalloutClaimOperation(@NotNull String momentId){ + super("CommunityMomentCallout_Claim"); + addPersistedQueryExtension(new PersistedQueryExtension(1, "e2d67415aead910f7f9ceb45a77b750a1e1d9622c936d832328a0689e054db62")); + addVariable("input", InputData.builder().momentId(momentId).build()); + } + + @Override + @NotNull + public GenericType> getResponseType(){ + return new GenericType<>(){}; + } +} diff --git a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/InputData.java b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/InputData.java new file mode 100644 index 00000000..250dfdec --- /dev/null +++ b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/communitymomentcalloutclaim/InputData.java @@ -0,0 +1,20 @@ +package fr.raksrinana.channelpointsminer.miner.api.gql.data.communitymomentcalloutclaim; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EqualsAndHashCode +@ToString +public class InputData{ + @JsonProperty("momentID") + private String momentId; +} diff --git a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/ClaimCommunityMomentPayload.java b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/ClaimCommunityMomentPayload.java new file mode 100644 index 00000000..d38fab45 --- /dev/null +++ b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/ClaimCommunityMomentPayload.java @@ -0,0 +1,30 @@ +package fr.raksrinana.channelpointsminer.miner.api.gql.data.types; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import fr.raksrinana.channelpointsminer.miner.util.json.UnknownDeserializer; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.jetbrains.annotations.Nullable; + +@JsonTypeName("ClaimCommunityMomentPayload") +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EqualsAndHashCode(callSuper = true) +@ToString +public class ClaimCommunityMomentPayload extends GQLType{ + @JsonProperty("moment") + @Nullable + private CommunityMoment moment; + @JsonProperty("error") + @JsonDeserialize(using = UnknownDeserializer.class) + @Nullable + private Object error; +} diff --git a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/CommunityMoment.java b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/CommunityMoment.java new file mode 100644 index 00000000..08b79b0c --- /dev/null +++ b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/CommunityMoment.java @@ -0,0 +1,24 @@ +package fr.raksrinana.channelpointsminer.miner.api.gql.data.types; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.jetbrains.annotations.NotNull; + +@JsonTypeName("CommunityMoment") +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EqualsAndHashCode(callSuper = true) +@ToString +public class CommunityMoment extends GQLType{ + @JsonProperty("id") + @NotNull + private String id; +} diff --git a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/GQLType.java b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/GQLType.java index a06a86d4..5a205877 100644 --- a/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/GQLType.java +++ b/miner/src/main/java/fr/raksrinana/channelpointsminer/miner/api/gql/data/types/GQLType.java @@ -56,6 +56,8 @@ @JsonSubTypes.Type(value = FollowEdge.class, name = "FollowEdge"), @JsonSubTypes.Type(value = FollowerEdge.class, name = "FollowerEdge"), @JsonSubTypes.Type(value = ChatRoomBanStatus.class, name = "ChatRoomBanStatus"), + @JsonSubTypes.Type(value = ClaimCommunityMomentPayload.class, name = "ClaimCommunityMomentPayload"), + @JsonSubTypes.Type(value = CommunityMoment.class, name = "CommunityMoment"), }) @EqualsAndHashCode public abstract class GQLType{ diff --git a/miner/src/test/java/fr/raksrinana/channelpointsminer/miner/api/gql/GQLApiClaimCommunityMomentTest.java b/miner/src/test/java/fr/raksrinana/channelpointsminer/miner/api/gql/GQLApiClaimCommunityMomentTest.java new file mode 100644 index 00000000..a0c47062 --- /dev/null +++ b/miner/src/test/java/fr/raksrinana/channelpointsminer/miner/api/gql/GQLApiClaimCommunityMomentTest.java @@ -0,0 +1,107 @@ +package fr.raksrinana.channelpointsminer.miner.api.gql; + +import fr.raksrinana.channelpointsminer.miner.api.gql.data.GQLResponse; +import fr.raksrinana.channelpointsminer.miner.api.gql.data.communitymomentcalloutclaim.CommunityMomentCalloutClaimData; +import fr.raksrinana.channelpointsminer.miner.api.gql.data.types.ClaimCommunityMomentPayload; +import fr.raksrinana.channelpointsminer.miner.api.gql.data.types.CommunityMoment; +import fr.raksrinana.channelpointsminer.miner.api.passport.TwitchLogin; +import fr.raksrinana.channelpointsminer.miner.tests.TestUtils; +import fr.raksrinana.channelpointsminer.miner.tests.UnirestMockExtension; +import kong.unirest.core.MockClient; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import java.util.Map; +import static kong.unirest.core.HttpMethod.POST; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +@ExtendWith(UnirestMockExtension.class) +class GQLApiClaimCommunityMomentTest{ + private static final String ACCESS_TOKEN = "access-token"; + private static final String MOMENT_ID = "moment-id"; + private static final String VALID_QUERY = "{\"extensions\":{\"persistedQuery\":{\"sha256Hash\":\"e2d67415aead910f7f9ceb45a77b750a1e1d9622c936d832328a0689e054db62\",\"version\":1}},\"operationName\":\"CommunityMomentCallout_Claim\",\"variables\":{\"input\":{\"momentID\":\"%s\"}}}"; + + @InjectMocks + private GQLApi tested; + + @Mock + private TwitchLogin twitchLogin; + + @BeforeEach + void setUp(){ + when(twitchLogin.getAccessToken()).thenReturn(ACCESS_TOKEN); + } + + @Test + void nominalClaimed(MockClient unirest){ + var expected = GQLResponse. builder() + .extensions(Map.of( + "durationMilliseconds", 9, + "operationName", "CommunityMomentCallout_Claim", + "requestID", "request-id" + )) + .data(CommunityMomentCalloutClaimData.builder() + .moment(ClaimCommunityMomentPayload.builder() + .moment(CommunityMoment.builder() + .id(MOMENT_ID) + .build()) + .build()) + .build()) + .build(); + + unirest.expect(POST, "https://gql.twitch.tv/gql") + .header("Authorization", "OAuth " + ACCESS_TOKEN) + .body(VALID_QUERY.formatted(MOMENT_ID)) + .thenReturn(TestUtils.getAllResourceContent("api/gql/communityMomentCalloutClaim_success.json")) + .withStatus(200); + + assertThat(tested.claimCommunityMoment(MOMENT_ID)).isPresent().get().isEqualTo(expected); + + unirest.verifyAll(); + } + + @Test + void invalidCredentials(MockClient unirest){ + unirest.expect(POST, "https://gql.twitch.tv/gql") + .header("Authorization", "OAuth " + ACCESS_TOKEN) + .body(VALID_QUERY.formatted(MOMENT_ID)) + .thenReturn(TestUtils.getAllResourceContent("api/gql/invalidAuth.json")) + .withStatus(401); + + assertThrows(RuntimeException.class, () -> tested.claimCommunityMoment(MOMENT_ID)); + + unirest.verifyAll(); + } + + @Test + void invalidRequest(MockClient unirest){ + unirest.expect(POST, "https://gql.twitch.tv/gql") + .header("Authorization", "OAuth " + ACCESS_TOKEN) + .body(VALID_QUERY.formatted(MOMENT_ID)) + .thenReturn(TestUtils.getAllResourceContent("api/gql/invalidRequest.json")) + .withStatus(200); + + assertThat(tested.claimCommunityMoment(MOMENT_ID)).isEmpty(); + + unirest.verifyAll(); + } + + @Test + void invalidResponse(MockClient unirest){ + unirest.expect(POST, "https://gql.twitch.tv/gql") + .header("Authorization", "OAuth " + ACCESS_TOKEN) + .body(VALID_QUERY.formatted(MOMENT_ID)) + .thenReturn() + .withStatus(500); + + assertThat(tested.claimCommunityMoment(MOMENT_ID)).isEmpty(); + + unirest.verifyAll(); + } +} \ No newline at end of file diff --git a/miner/src/test/resources/api/gql/communityMomentCalloutClaim_success.json b/miner/src/test/resources/api/gql/communityMomentCalloutClaim_success.json new file mode 100644 index 00000000..226c3825 --- /dev/null +++ b/miner/src/test/resources/api/gql/communityMomentCalloutClaim_success.json @@ -0,0 +1,17 @@ +{ + "data" : { + "claimCommunityMoment" : { + "moment" : { + "id" : "moment-id", + "__typename" : "CommunityMoment" + }, + "error" : null, + "__typename" : "ClaimCommunityMomentPayload" + } + }, + "extensions" : { + "durationMilliseconds" : 9, + "operationName" : "CommunityMomentCallout_Claim", + "requestID" : "request-id" + } +} \ No newline at end of file