From a4ea3e18219a9299f836e136a0e3a3f81409abd5 Mon Sep 17 00:00:00 2001 From: Marc Szanto <11840265+Xemdo@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:06:54 -0700 Subject: [PATCH 1/3] Added channel.ad_break.begin --- .../events/types/ad_break/ad_break_begin.go | 133 ++++++++++++++++++ .../types/ad_break/ad_break_begin_test.go | 78 ++++++++++ internal/events/types/types.go | 2 + internal/models/ad_break.go | 20 +++ 4 files changed, 233 insertions(+) create mode 100644 internal/events/types/ad_break/ad_break_begin.go create mode 100644 internal/events/types/ad_break/ad_break_begin_test.go create mode 100644 internal/models/ad_break.go diff --git a/internal/events/types/ad_break/ad_break_begin.go b/internal/events/types/ad_break/ad_break_begin.go new file mode 100644 index 0000000..91a7d7b --- /dev/null +++ b/internal/events/types/ad_break/ad_break_begin.go @@ -0,0 +1,133 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package ad_break + +import ( + "encoding/json" + "strings" + "time" + + "github.com/twitchdev/twitch-cli/internal/events" + "github.com/twitchdev/twitch-cli/internal/models" + "github.com/twitchdev/twitch-cli/internal/util" +) + +var transportsSupported = map[string]bool{ + models.TransportWebhook: true, + models.TransportWebSocket: true, +} +var triggers = []string{"ad-begin"} + +var triggerMapping = map[string]map[string]string{ + models.TransportWebhook: { + "ad-begin": "channel.ad_break.begin", + }, + models.TransportWebSocket: { + "ad-begin": "channel.ad_break.begin", + }, +} + +type Event struct{} + +func (e Event) GenerateEvent(params events.MockEventParameters) (events.MockEventResponse, error) { + var event []byte + var err error + + switch params.Transport { + case models.TransportWebhook, models.TransportWebSocket: + body := models.EventsubResponse{ + Subscription: models.EventsubSubscription{ + ID: params.ID, + Status: params.SubscriptionStatus, + Type: triggerMapping[params.Transport][params.Trigger], + Version: e.SubscriptionVersion(), + Condition: models.EventsubCondition{ + BroadcasterUserID: params.ToUserID, + }, + Transport: models.EventsubTransport{ + Method: "webhook", + Callback: "null", + }, + Cost: 0, + CreatedAt: params.Timestamp, + }, + Event: models.AdBreakBeginEventSubEvent{ + RequesterUserID: params.FromUserID, + RequesterUserLogin: params.FromUserName, + RequesterUserName: params.FromUserName, + BroadcasterUserID: params.ToUserID, + BroadcasterUserLogin: params.ToUserName, + BroadcasterUserName: params.ToUserName, + Duration: 60, + IsAutomatic: false, + StartedAt: util.GetTimestamp().Format(time.RFC3339Nano), + }, + } + + event, err = json.Marshal(body) + if err != nil { + return events.MockEventResponse{}, err + } + + // Delete event info if Subscription.Status is not set to "enabled" + if !strings.EqualFold(params.SubscriptionStatus, "enabled") { + var i interface{} + if err := json.Unmarshal([]byte(event), &i); err != nil { + return events.MockEventResponse{}, err + } + if m, ok := i.(map[string]interface{}); ok { + delete(m, "event") // Matches JSON key defined in body variable above + } + + event, err = json.Marshal(i) + if err != nil { + return events.MockEventResponse{}, err + } + } + default: + return events.MockEventResponse{}, nil + } + + return events.MockEventResponse{ + ID: params.ID, + JSON: event, + FromUser: params.FromUserID, + ToUser: params.ToUserID, + }, nil +} + +func (e Event) ValidTransport(transport string) bool { + return transportsSupported[transport] +} + +func (e Event) ValidTrigger(trigger string) bool { + for _, t := range triggers { + if t == trigger { + return true + } + } + return false +} +func (e Event) GetTopic(transport string, trigger string) string { + return triggerMapping[transport][trigger] +} +func (e Event) GetAllTopicsByTransport(transport string) []string { + allTopics := []string{} + for _, topic := range triggerMapping[transport] { + allTopics = append(allTopics, topic) + } + return allTopics +} +func (e Event) GetEventSubAlias(t string) string { + // check for aliases + for trigger, topic := range triggerMapping[models.TransportWebhook] { + if topic == t { + return trigger + } + } + return "" +} + +func (e Event) SubscriptionVersion() string { + return "1" +} diff --git a/internal/events/types/ad_break/ad_break_begin_test.go b/internal/events/types/ad_break/ad_break_begin_test.go new file mode 100644 index 0000000..a91d7ea --- /dev/null +++ b/internal/events/types/ad_break/ad_break_begin_test.go @@ -0,0 +1,78 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package ad_break + +import ( + "encoding/json" + "testing" + + "github.com/twitchdev/twitch-cli/internal/events" + "github.com/twitchdev/twitch-cli/internal/models" + "github.com/twitchdev/twitch-cli/test_setup" +) + +var fromUser = "1234" +var toUser = "4567" + +func TestEventSub(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + params := events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: models.TransportWebhook, + Trigger: "subscribe", + SubscriptionStatus: "enabled", + } + + r, err := Event{}.GenerateEvent(params) + a.Nil(err) + + var body models.SubEventSubResponse + err = json.Unmarshal(r.JSON, &body) + a.Nil(err) + + a.Equal(toUser, body.Event.BroadcasterUserID, "Expected to user %v, got %v", toUser, body.Event.BroadcasterUserID) + a.Equal(fromUser, body.Event.UserID, "Expected from user %v, got %v", r.ToUser, body.Event.UserID) +} + +func TestFakeTransport(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + params := events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: "fake_transport", + Trigger: triggers[0], + SubscriptionStatus: "enabled", + } + + r, err := Event{}.GenerateEvent(params) + a.Nil(err) + a.Empty(r) +} +func TestValidTrigger(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + r := Event{}.ValidTrigger("notreal") + a.Equal(false, r) + + r = Event{}.ValidTrigger("follow") + a.Equal(true, r) +} + +func TestValidTransport(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + r := Event{}.ValidTransport(models.TransportWebhook) + a.Equal(true, r) + + r = Event{}.ValidTransport("noteventsub") + a.Equal(false, r) +} +func TestGetTopic(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + r := Event{}.GetTopic(models.TransportWebhook, "follow") + a.NotNil(r) +} diff --git a/internal/events/types/types.go b/internal/events/types/types.go index 3cd7c05..db1dd37 100644 --- a/internal/events/types/types.go +++ b/internal/events/types/types.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/twitchdev/twitch-cli/internal/events" + "github.com/twitchdev/twitch-cli/internal/events/types/ad_break" "github.com/twitchdev/twitch-cli/internal/events/types/authorization_grant" "github.com/twitchdev/twitch-cli/internal/events/types/authorization_revoke" "github.com/twitchdev/twitch-cli/internal/events/types/ban" @@ -41,6 +42,7 @@ import ( func AllEvents() []events.MockEvent { return []events.MockEvent{ + ad_break.Event{}, authorization_grant.Event{}, authorization_revoke.Event{}, ban.Event{}, diff --git a/internal/models/ad_break.go b/internal/models/ad_break.go new file mode 100644 index 0000000..c02dac7 --- /dev/null +++ b/internal/models/ad_break.go @@ -0,0 +1,20 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package models + +type AdBreakBeginEventSubEvent struct { + BroadcasterUserID string `json:"broadcaster_user_id"` + BroadcasterUserLogin string `json:"broadcaster_user_login"` + BroadcasterUserName string `json:"broadcaster_user_name"` + RequesterUserID string `json:"requester_user_id"` + RequesterUserLogin string `json:"requester_user_login"` + RequesterUserName string `json:"requester_user_name"` + Duration int `json:"duration_seconds"` + IsAutomatic bool `json:"is_automatic"` + StartedAt string `json:"started_at"` +} + +type AdBreakBeginEventSubResponse struct { + Subscription EventsubSubscription `json:"subscription"` + Event AdBreakBeginEventSubEvent `json:"event"` +} From 3c1437c84d835bba25b9680f3124dd6d8851f55d Mon Sep 17 00:00:00 2001 From: Marc Szanto <11840265+Xemdo@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:14:06 -0700 Subject: [PATCH 2/3] Forgot ad break begin test --- internal/events/types/ad_break/ad_break_begin_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/events/types/ad_break/ad_break_begin_test.go b/internal/events/types/ad_break/ad_break_begin_test.go index a91d7ea..c4e6f97 100644 --- a/internal/events/types/ad_break/ad_break_begin_test.go +++ b/internal/events/types/ad_break/ad_break_begin_test.go @@ -33,7 +33,6 @@ func TestEventSub(t *testing.T) { a.Nil(err) a.Equal(toUser, body.Event.BroadcasterUserID, "Expected to user %v, got %v", toUser, body.Event.BroadcasterUserID) - a.Equal(fromUser, body.Event.UserID, "Expected from user %v, got %v", r.ToUser, body.Event.UserID) } func TestFakeTransport(t *testing.T) { @@ -57,7 +56,7 @@ func TestValidTrigger(t *testing.T) { r := Event{}.ValidTrigger("notreal") a.Equal(false, r) - r = Event{}.ValidTrigger("follow") + r = Event{}.ValidTrigger("ad-begin") a.Equal(true, r) } @@ -73,6 +72,6 @@ func TestValidTransport(t *testing.T) { func TestGetTopic(t *testing.T) { a := test_setup.SetupTestEnv(t) - r := Event{}.GetTopic(models.TransportWebhook, "follow") + r := Event{}.GetTopic(models.TransportWebhook, "ad-begin") a.NotNil(r) } From 52093027842f26a5dc9d42af27b7cf743841d76a Mon Sep 17 00:00:00 2001 From: Marc Szanto <11840265+Xemdo@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:42:56 -0700 Subject: [PATCH 3/3] Added unban requests events --- internal/events/types/types.go | 2 + .../types/unban_requests/unban_requests.go | 161 ++++++++++++++++++ .../unban_requests/unban_requests_test.go | 89 ++++++++++ internal/models/unban_requests.go | 34 ++++ 4 files changed, 286 insertions(+) create mode 100644 internal/events/types/unban_requests/unban_requests.go create mode 100644 internal/events/types/unban_requests/unban_requests_test.go create mode 100644 internal/models/unban_requests.go diff --git a/internal/events/types/types.go b/internal/events/types/types.go index db1dd37..77222aa 100644 --- a/internal/events/types/types.go +++ b/internal/events/types/types.go @@ -36,6 +36,7 @@ import ( "github.com/twitchdev/twitch-cli/internal/events/types/subscribe" "github.com/twitchdev/twitch-cli/internal/events/types/subscription_message" "github.com/twitchdev/twitch-cli/internal/events/types/unban" + "github.com/twitchdev/twitch-cli/internal/events/types/unban_requests" user_update "github.com/twitchdev/twitch-cli/internal/events/types/user" "github.com/twitchdev/twitch-cli/internal/models" ) @@ -69,6 +70,7 @@ func AllEvents() []events.MockEvent { subscribe.Event{}, subscription_message.Event{}, unban.Event{}, + unban_requests.Event{}, user_update.Event{}, } } diff --git a/internal/events/types/unban_requests/unban_requests.go b/internal/events/types/unban_requests/unban_requests.go new file mode 100644 index 0000000..06ec354 --- /dev/null +++ b/internal/events/types/unban_requests/unban_requests.go @@ -0,0 +1,161 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package unban_requests + +import ( + "encoding/json" + "strings" + "time" + + "github.com/twitchdev/twitch-cli/internal/events" + "github.com/twitchdev/twitch-cli/internal/models" + "github.com/twitchdev/twitch-cli/internal/util" +) + +var transportsSupported = map[string]bool{ + models.TransportWebhook: true, + models.TransportWebSocket: true, +} +var triggers = []string{"unban-request-create", "unban-request-resolve"} + +var triggerMapping = map[string]map[string]string{ + models.TransportWebhook: { + "unban-request-create": "channel.unban_request.create", + "unban-request-resolve": "channel.unban_request.resolve", + }, + models.TransportWebSocket: { + "unban-request-create": "channel.unban_request.create", + "unban-request-resolve": "channel.unban_request.resolve", + }, +} + +type Event struct{} + +func (e Event) GenerateEvent(params events.MockEventParameters) (events.MockEventResponse, error) { + var event []byte + var err error + + var unbanRequestEvent interface{} + + if params.Trigger == "unban-request-create" { + unbanRequestEvent = models.UnbanRequestCreateEventSubEvent{ + BroadcasterUserID: params.ToUserID, + BroadcasterUserName: params.ToUserName, + BroadcasterUserLogin: strings.ToLower(params.ToUserName), + UserID: params.FromUserID, + UserName: params.FromUserName, + UserLogin: strings.ToLower(params.FromUserName), + Text: "Please unban me!", + CreatedAt: util.GetTimestamp().Add(-30 * time.Minute).Format(time.RFC3339Nano), + } + } + + if params.Trigger == "unban-request-resolve" { + mod_user := util.RandomUserID() + mod_user_lower := strings.ToLower(mod_user) + mod_user_id := util.RandomUserID() + + unbanRequestEvent = models.UnbanRequestResolveEventSubEvent{ + ID: util.RandomGUID(), + BroadcasterUserID: params.ToUserID, + BroadcasterUserName: params.ToUserName, + BroadcasterUserLogin: strings.ToLower(params.ToUserName), + ModeratorUserID: &mod_user_id, + ModeratorUserName: &mod_user, + ModeratorUserLogin: &mod_user_lower, + UserID: params.FromUserID, + UserName: params.FromUserName, + UserLogin: strings.ToLower(params.FromUserName), + ResolutionText: "We forgive you", + Status: "approved", + } + } + + switch params.Transport { + case models.TransportWebhook, models.TransportWebSocket: + body := models.EventsubResponse{ + Subscription: models.EventsubSubscription{ + ID: params.ID, + Type: triggerMapping[params.Transport][params.Trigger], + Version: e.SubscriptionVersion(), + Status: params.SubscriptionStatus, + Cost: 0, + Condition: models.EventsubCondition{ + BroadcasterUserID: params.ToUserID, + ModeratorUserID: params.FromUserID, + }, + Transport: models.EventsubTransport{ + Method: "webhook", + Callback: "null", + }, + CreatedAt: params.Timestamp, + }, + Event: unbanRequestEvent, + } + + event, err = json.Marshal(body) + if err != nil { + return events.MockEventResponse{}, err + } + + // Delete event info if Subscription.Status is not set to "enabled" + if !strings.EqualFold(params.SubscriptionStatus, "enabled") { + var i interface{} + if err := json.Unmarshal([]byte(event), &i); err != nil { + return events.MockEventResponse{}, err + } + if m, ok := i.(map[string]interface{}); ok { + delete(m, "event") // Matches JSON key defined in body variable above + } + + event, err = json.Marshal(i) + if err != nil { + return events.MockEventResponse{}, err + } + } + default: + return events.MockEventResponse{}, nil + } + + return events.MockEventResponse{ + ID: params.ID, + JSON: event, + ToUser: params.ToUserID, + }, nil +} + +func (e Event) ValidTransport(transport string) bool { + return transportsSupported[transport] +} + +func (e Event) ValidTrigger(trigger string) bool { + for _, t := range triggers { + if t == trigger { + return true + } + } + return false +} +func (e Event) GetTopic(transport string, trigger string) string { + return triggerMapping[transport][trigger] +} +func (e Event) GetAllTopicsByTransport(transport string) []string { + allTopics := []string{} + for _, topic := range triggerMapping[transport] { + allTopics = append(allTopics, topic) + } + return allTopics +} +func (e Event) GetEventSubAlias(t string) string { + // check for aliases + for trigger, topic := range triggerMapping[models.TransportWebhook] { + if topic == t { + return trigger + } + } + return "" +} + +func (e Event) SubscriptionVersion() string { + return "1" +} diff --git a/internal/events/types/unban_requests/unban_requests_test.go b/internal/events/types/unban_requests/unban_requests_test.go new file mode 100644 index 0000000..a59af8e --- /dev/null +++ b/internal/events/types/unban_requests/unban_requests_test.go @@ -0,0 +1,89 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package unban_requests + +import ( + "encoding/json" + "testing" + + "github.com/twitchdev/twitch-cli/internal/events" + "github.com/twitchdev/twitch-cli/internal/models" + "github.com/twitchdev/twitch-cli/test_setup" +) + +var fromUser = "1234" +var toUser = "4567" + +func TestEventSubUnbanRequests(t *testing.T) { + testEventSubUnbanRequests(t, "unban-request-create") + testEventSubUnbanRequests(t, "unban-request-resolve") +} + +func testEventSubUnbanRequests(t *testing.T, trigger string) { + a := test_setup.SetupTestEnv(t) + params := events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: models.TransportWebhook, + Trigger: trigger, + SubscriptionStatus: "enabled", + } + + r, err := Event{}.GenerateEvent(params) + a.Nil(err, "Error generating body.") + + var body models.UnbanRequestCreateEventSubResponse + + err = json.Unmarshal(r.JSON, &body) + a.Nil(err, "Error unmarshalling JSON") + + a.Equal(toUser, body.Event.BroadcasterUserID, "Expected to user %v, got %v", toUser, body.Event.BroadcasterUserID) + if trigger == "unban-request-create" { + a.Equal(fromUser, body.Event.UserID, "Expected from user %v, got %v", r.ToUser, body.Event.UserID) + } +} + +func TestFakeTransport(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + params := events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: "fake_transport", + Trigger: "unban-request-create", + } + + r, err := Event{}.GenerateEvent(params) + a.Nil(err) + a.Empty(r) +} + +func TestValidTrigger(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + r := Event{}.ValidTrigger("unban-request-create") + a.Equal(true, r) + + r = Event{}.ValidTrigger("unban-request-resolve") + a.Equal(true, r) +} + +func TestValidTransport(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + r := Event{}.ValidTransport(models.TransportWebhook) + a.Equal(true, r) + + r = Event{}.ValidTransport("noteventsub") + a.Equal(false, r) +} + +func TestGetTopic(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + r := Event{}.GetTopic(models.TransportWebhook, "unban-request-create") + a.NotNil(r) + + r = Event{}.GetTopic(models.TransportWebhook, "unban-request-resolve") + a.NotNil(r) +} diff --git a/internal/models/unban_requests.go b/internal/models/unban_requests.go new file mode 100644 index 0000000..062deb6 --- /dev/null +++ b/internal/models/unban_requests.go @@ -0,0 +1,34 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package models + +type UnbanRequestCreateEventSubEvent struct { + BroadcasterUserID string `json:"broadcaster_user_id"` + BroadcasterUserLogin string `json:"broadcaster_user_login"` + BroadcasterUserName string `json:"broadcaster_user_name"` + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + Text string `json:"text"` + CreatedAt string `json:"created_at"` +} + +type UnbanRequestCreateEventSubResponse struct { + Subscription EventsubSubscription `json:"subscription"` + Event TransactionEventSubEvent `json:"event"` +} + +type UnbanRequestResolveEventSubEvent struct { + ID string `json:"id"` + BroadcasterUserID string `json:"broadcaster_user_id"` + BroadcasterUserLogin string `json:"broadcaster_user_login"` + BroadcasterUserName string `json:"broadcaster_user_name"` + ModeratorUserID *string `json:"moderator_user_id"` + ModeratorUserLogin *string `json:"moderator_user_login"` + ModeratorUserName *string `json:"moderator_user_name"` + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + ResolutionText string `json:"resolution_text"` + Status string `json:"status"` +}