Repository: nicklaw5/helix
Pull request #81 (2021-04-18 20:51:15)

Add "Check User Subscription" feature
Update EventSub subscription : EventSubTypeModeratorRemove and
EventSubTypeModeratorAdd are no more beta (2021‑03‑26)

Update Subscription struct with new fields (BroadcasterLogin, GifterID,
GifterLogin, GifterNameUser, UserLogin)


Patch:
diff --git a/README.md b/README.md
index 76f4c12..09fc3e6 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,8 @@ looking for the Twitch API docs, see the [Twitch Developer website](https://dev.
 - [x] Get Stream Markers
 - [x] Get Channel Information
 - [x] Modify Channel Information
-- [ ] Get Broadcaster Subscriptions
+- [x] Get Broadcaster Subscriptions
+- [x] Check User Subscription
 - [ ] Get All Stream Tags
 - [ ] Get Stream Tags
 - [ ] Replace Stream Tags
@@ -72,6 +73,16 @@ looking for the Twitch API docs, see the [Twitch Developer website](https://dev.
 - [x] Get Videos
 - [x] Get Webhook Subscriptions
 - [x] Create / Remove / List EventSub Subscriptions
+- [ ] Create Extension Secret
+- [ ] Get Extension Secret
+- [ ] Revoke Extension Secrets
+- [ ] Get Live Channels with Extension Activated
+- [ ] Set Extension Required Configuration
+- [ ] Set Extension Configuration Segment
+- [ ] Get Extension Channel Configuration
+- [ ] Get Extension Configuration Segment
+- [ ] Send Extension PubSub Message
+- [ ] Send Extension Chat Message
 
 ## Quick Usage Example
 
diff --git a/docs/subscriptions_docs.md b/docs/subscriptions_docs.md
index 21a482f..3237647 100644
--- a/docs/subscriptions_docs.md
+++ b/docs/subscriptions_docs.md
@@ -22,3 +22,27 @@ if err != nil {
 
 fmt.Printf("%+v\n", resp)
 ```
+
+## Check User Subscription
+
+This is an example of how to check if a user is subscribed to a broadcaster.
+
+```go
+client, err := helix.NewClient(&helix.Options{
+    ClientID:        "your-client-id",
+    UserAccessToken: "your-user-access-token",
+})
+if err != nil {
+    // handle error
+}
+
+resp, err := client.CheckUserSubsription(&helix.UserSubscriptionsParams{
+    BroadcasterID: "29776980",
+    UserID:        "145328278",
+})
+if err != nil {
+    // handle error
+}
+
+fmt.Printf("%+v\n", resp)
+```
diff --git a/drops.go b/drops.go
index ca8f3ae..4ce7b0d 100644
--- a/drops.go
+++ b/drops.go
@@ -6,7 +6,7 @@ type GetDropEntitlementsParams struct {
 	UserID string `query:"user_id"`
 	GameID string `query:"game_id"`
 	After  string `query:"after"`
-	First  int    `query:"first,20"` // Limit 100
+	First  int    `query:"first,20"` // Limit 1000
 }
 
 // Entitlement ...
diff --git a/eventsub.go b/eventsub.go
index 11a6e77..31abcc7 100644
--- a/eventsub.go
+++ b/eventsub.go
@@ -5,7 +5,6 @@ import (
 	"crypto/sha256"
 	"encoding/hex"
 	"fmt"
-	"log"
 	"net/http"
 	"net/url"
 	"strings"
@@ -380,9 +379,6 @@ func (c *Client) RemoveEventSubSubscription(id string) (*RemoveEventSubSubscript
 
 // Creates an EventSub subscription
 func (c *Client) CreateEventSubSubscription(payload *EventSubSubscription) (*EventSubSubscriptionsResponse, error) {
-	if payload.Type == EventSubTypeModeratorAdd || payload.Type == EventSubTypeModeratorRemove {
-		log.Println("warning: the EventSub subscription type is still in Beta and may stop working at any time.")
-	}
 	if payload.Transport.Method == "webhook" && !strings.HasPrefix(payload.Transport.Callback, "https://") {
 		return nil, fmt.Errorf("error: callback must use https")
 	}
diff --git a/subscriptions.go b/subscriptions.go
index 2446862..9648a54 100644
--- a/subscriptions.go
+++ b/subscriptions.go
@@ -2,13 +2,29 @@ package helix
 
 // Subscription ...
 type Subscription struct {
-	BroadcasterID   string `json:"broadcaster_id"`
-	BroadcasterName string `json:"broadcaster_name"`
-	IsGift          bool   `json:"is_gift"`
-	Tier            string `json:"tier"`
-	PlanName        string `json:"plan_name"`
-	UserID          string `json:"user_id"`
-	UserName        string `json:"user_name"`
+	BroadcasterID    string `json:"broadcaster_id"`
+	BroadcasterLogin string `json:"broadcaster_login"`
+	BroadcasterName  string `json:"broadcaster_name"`
+	IsGift           bool   `json:"is_gift"`
+	GifterID         string `json:"gifter_id"`
+	GifterLogin      string `json:"gifter_login"`
+	GifterName       string `json:"gifter_name"`
+	Tier             string `json:"tier"`
+	PlanName         string `json:"plan_name"`
+	UserID           string `json:"user_id"`
+	UserName         string `json:"user_name"`
+	UserLogin        string `json:"user_login"`
+}
+
+// UserSubscription ...
+type UserSubscription struct {
+	BroadcasterID    string `json:"broadcaster_id"`
+	BroadcasterLogin string `json:"broadcaster_login"`
+	BroadcasterName  string `json:"broadcaster_name"`
+	IsGift           bool   `json:"is_gift"`
+	GifterLogin      string `json:"gifter_login"`
+	GifterName       string `json:"gifter_name"`
+	Tier             string `json:"tier"`
 }
 
 // ManySubscriptions ...
@@ -17,16 +33,36 @@ type ManySubscriptions struct {
 	Pagination    Pagination     `json:"pagination"`
 }
 
+// ManyUserSubscription ...
+type ManyUserSubscriptions struct {
+	UserSubscriptions []UserSubscription `json:"data"`
+}
+
 // SubscriptionsResponse ...
 type SubscriptionsResponse struct {
 	ResponseCommon
 	Data ManySubscriptions
 }
 
+// UserSubscriptionResponse ...
+type UserSubscriptionResponse struct {
+	ResponseCommon
+	Data ManyUserSubscriptions
+}
+
 // SubscriptionsParams ...
 type SubscriptionsParams struct {
 	BroadcasterID string   `query:"broadcaster_id"` // Limit 1
 	UserID        []string `query:"user_id"`        // Limit 100
+	After         string   `query:"after"`
+	Before        string   `query:"before"`
+	First         int      `query:"first,20"` // Limit 100
+}
+
+// UserSubscriptionsParams ...
+type UserSubscriptionsParams struct {
+	BroadcasterID string `query:"broadcaster_id"`
+	UserID        string `query:"user_id"`
 }
 
 // GetSubscriptions gets subscriptions about one Twitch broadcaster.
@@ -46,3 +82,19 @@ func (c *Client) GetSubscriptions(params *SubscriptionsParams) (*SubscriptionsRe
 
 	return subscriptions, nil
 }
+
+// CheckUserSubsription Check if a specific user is subscribed to a specific channel
+//
+// Required scope: user:read:subscriptions
+func (c *Client) CheckUserSubsription(params *UserSubscriptionsParams) (*UserSubscriptionResponse, error) {
+	resp, err := c.get("/subscriptions/user", &ManyUserSubscriptions{}, params)
+	if err != nil {
+		return nil, err
+	}
+
+	subscriptions := &UserSubscriptionResponse{}
+	resp.HydrateResponseCommon(&subscriptions.ResponseCommon)
+	subscriptions.Data.UserSubscriptions = resp.Data.(*ManyUserSubscriptions).UserSubscriptions
+
+	return subscriptions, nil
+}


Test patch:
diff --git a/subscriptions_test.go b/subscriptions_test.go
index ecdab3c..b20a9fd 100644
--- a/subscriptions_test.go
+++ b/subscriptions_test.go
@@ -20,7 +20,7 @@ func TestGetSubscriptions(t *testing.T) {
 			&Options{ClientID: "my-client-id", UserAccessToken: "my-access-token"},
 			"123",
 			[]string{},
-			`{"data": [{"broadcaster_id":"123","broadcaster_name":"test_user","is_gift":true,"tier":"3000","plan_name":"The Ninjas","user_id":"123","user_name":"test_user"}],"pagination":{"cursor":"xxxx"}}`,
+			`{"data": [{"broadcaster_id":"123","broadcaster_login":"test_user","broadcaster_name":"test_user","is_gift":true,"gifter_id":"456","gifter_login":"another_user","gifter_name":"Another_User","tier":"3000","plan_name":"The Ninjas","user_id":"123","user_id":"123","user_login":"test_user","user_name":"test_user"}],"pagination":{"cursor":"xxxx"}}`,
 		},
 		{
 			http.StatusBadRequest,
@@ -61,3 +61,61 @@ func TestGetSubscriptions(t *testing.T) {
 		}
 	}
 }
+
+
+func TestChechUserSubscription(t *testing.T) {
+	t.Parallel()
+
+	testCases := []struct {
+		statusCode    int
+		options       *Options
+		BroadcasterID string
+		UserID        string
+		respBody      string
+	}{
+		{
+			http.StatusOK,
+			&Options{ClientID: "my-client-id", UserAccessToken: "my-access-token"},
+			"123",
+			"123",
+			`{"data":[{"broadcaster_id":"122330828","broadcaster_name":"test_user","broadcaster_login":"test_user","is_gift":false,"tier":"1000"}]}`,
+		},
+		{
+			http.StatusBadRequest,
+			&Options{ClientID: "my-client-id", UserAccessToken: "my-access-token"},
+			"123",
+			"",
+			`{"error":"Bad Request","status":400,"message":"Missing required parameter \"user_id\""}`,
+		},
+	}
+
+	for _, testCase := range testCases {
+		c := newMockClient(testCase.options, newMockHandler(testCase.statusCode, testCase.respBody, nil))
+
+		resp, err := c.CheckUserSubsription(&UserSubscriptionsParams{
+			BroadcasterID: testCase.BroadcasterID,
+			UserID:        testCase.UserID,
+		})
+		if err != nil {
+			t.Error(err)
+		}
+
+		if resp.StatusCode != testCase.statusCode {
+			t.Errorf("expected status code to be \"%d\", got \"%d\"", testCase.statusCode, resp.StatusCode)
+		}
+
+		// Test error cases
+		if testCase.statusCode != http.StatusOK {
+			if resp.Error != "Bad Request" {
+				t.Errorf("expected error to be \"%s\", got \"%s\"", "Bad Request", resp.Error)
+			}
+
+			errMsg := "Missing required parameter \"user_id\""
+			if resp.ErrorMessage != errMsg {
+				t.Errorf("expected error message to be \"%s\", got \"%s\"", errMsg, resp.ErrorMessage)
+			}
+
+			continue
+		}
+	}
+}