From dd9a1c1bcca1ae6d82afe9f2622a8ef4cd8ef8b1 Mon Sep 17 00:00:00 2001 From: Rasmus Karlsson Date: Sat, 8 Feb 2025 12:56:51 +0100 Subject: [PATCH 1/2] feat: Allow customizing `to-user-name`/`from-user-name` Example usage: `twitch-cli event trigger channel.ban --transport=websocket --to-user 11148817 --to-user-name pajlada` --- cmd/events/trigger.go | 4 ++ cmd/events/variables.go | 2 + docs/event.md | 56 ++++++++++++------------ internal/events/trigger/trigger_event.go | 14 +++++- 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/cmd/events/trigger.go b/cmd/events/trigger.go index af8811d..f50fd79 100644 --- a/cmd/events/trigger.go +++ b/cmd/events/trigger.go @@ -35,7 +35,9 @@ func TriggerCommand() (command *cobra.Command) { // per-topic flags command.Flags().StringVarP(&toUser, "to-user", "t", "", "User ID of the receiver of the event. For example, the user that receives a follow. In most contexts, this is the broadcaster.") + command.Flags().StringVarP(&toUserName, "to-user-name", "", "", "User Name of the receiver of the event. For example, the user that receives a follow. In most contexts, this is the broadcaster.") command.Flags().StringVarP(&fromUser, "from-user", "f", "", "User ID of the user sending the event, for example the user following another user.") + command.Flags().StringVarP(&fromUserName, "from-user-name", "", "", "User Name of the user sending the event, for example the user following another user.") command.Flags().StringVarP(&giftUser, "gift-user", "g", "", "Used only for \"gift\" events. Denotes the User ID of the gifting user.") command.Flags().BoolVarP(&isAnonymous, "anonymous", "a", false, "Denotes if the event is anonymous. Only applies to Gift and Sub events.") command.Flags().IntVarP(&count, "count", "c", 1, "Number of times to run an event. This can be used to simulate rapid events, such as multiple sub gift, or large number of cheers.") @@ -99,7 +101,9 @@ func triggerCmdRun(cmd *cobra.Command, args []string) error { Transport: transport, ForwardAddress: forwardAddress, FromUser: fromUser, + FromUserName: fromUserName, ToUser: toUser, + ToUserName: toUserName, GiftUser: giftUser, Secret: secret, IsAnonymous: isAnonymous, diff --git a/cmd/events/variables.go b/cmd/events/variables.go index 24cb596..3eba634 100644 --- a/cmd/events/variables.go +++ b/cmd/events/variables.go @@ -8,7 +8,9 @@ var ( transport string noConfig bool fromUser string + fromUserName string toUser string + toUserName string giftUser string subscriptionID string eventMessageID string diff --git a/docs/event.md b/docs/event.md index 9a88cb1..5c13e5f 100644 --- a/docs/event.md +++ b/docs/event.md @@ -88,33 +88,35 @@ This command can take either the Event or Alias listed as an argument. It is pre **Flags** -| Flag | Shorthand | Description | Example | Required? (Y/N) | -|---------------------------|-----------|---------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------| -| `--anonymous` | `-a` | Denotes if the event is anonymous. Only applies to Gift and Sub events. | `-a` | N | -| `--ban-end` | | Sets the timestamp a ban is intended to end at. If not set, the ban event will appear as permanent. | `--ban-end 10d20h12m35s` | N | -| `--ban-start` | | Sets the timestamp a ban started at. | `--ban-start 2017-04-13T14:34:23` | N | -| `--charity-current-value` | | For charity events, manually set the charity dollar value. | `--charity-current-value 11000` | N | -| `--charity-target-value` | | Only used for "charity-*" events. Manually set the target dollar value for charity events. (default 1500000) | `--charity-target-value 23400` | N | -| `--client-id` | | Manually set the Client ID used for revoke, grant, and bits transactions. | `--client-id 4ofh8m0706jqpholgk00u3xvb4spct` | N | -| `--cost` | `-C` | Amount of subscriptions, bits, or channel points redeemed/used in the event. | `-C 250` | N | -| `--count` | `-c` | Count of events to fire. This can be used to simulate an influx of events. | `-c 100` | N | -| `--description` | `-d` | Title the stream should be updated/started with. | `-d Awesome new title!` | N | -| `--event-status` | `-S` | Status of the Event object (.event.status in JSON); Currently applies to channel points redemptions. | `-S fulfilled` | N | -| `--forward-address` | `-F` | Web server address for where to send mock events. | `-F https://localhost:8080` | N | -| `--from-user` | `-f` | Denotes the sender's TUID of the event, for example the user that follows another user or the subscriber to a broadcaster. | `-f 44635596` | N | -| `--game-id` | `-G` | Game ID for Drop or other relevant events. | `-G 1234` | N | -| `--gift-user` | `-g` | Used only for subcription-based events, denotes the gifting user ID. | `-g 44635596` | N | -| `--item-id` | `-i` | Manually set the ID of the event payload item (for example the reward ID in redemption events or game in stream events). | `-i 032e4a6c-4aef-11eb-a9f5-1f703d1f0b92` | N | -| `--item-name` | `-n` | Manually set the name of the event payload item (for example the reward ID in redemption events or game name in stream events). | `-n "Science & Technology"` | N | -| `--no-config` | `-D` | Disables the use of the configuration values should they exist. | `-D` | N | -| `--secret` | `-s` | Webhook secret. If defined, signs all forwarded events with the SHA256 HMAC and must be 10-100 characters in length. | `-s testsecret` | N | -| `--session` | | WebSocket session to target. Only used when forwarding to WebSocket servers with --transport=websocket | `--session e411cc1e_a2613d4e` | N | -| `--subscription-id` | `-u` | Manually set the subscription/event ID of the event itself. | `-u 5d3aed06-d019-11ed-afa1-0242ac120002` | N | -| `--subscription-status` | `-r` | Status of the Subscription object (.subscription.status in JSON). Defaults to "enabled" | `-r revoked` | N | -| `--tier` | | Tier of the subscription. | `--tier 3000` | N | -| `--timestamp` | | Sets the timestamp to be used in payloads and headers. Must be in RFC3339Nano format. | `--timestamp 2017-04-13T14:34:23` | N | -| `--to-user` | `-t` | Denotes the receiver's TUID of the event, usually the broadcaster. | `-t 44635596` | N | -| `--transport` | `-T` | The method used to send events. Can either be `webhook` or `websocket`. Default is `webhook`. | `-T webhook` | N | +| Flag | Shorthand | Description | Example | Required? (Y/N) | +|---------------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------| +| `--anonymous` | `-a` | Denotes if the event is anonymous. Only applies to Gift and Sub events. | `-a` | N | +| `--ban-end` | | Sets the timestamp a ban is intended to end at. If not set, the ban event will appear as permanent. | `--ban-end 10d20h12m35s` | N | +| `--ban-start` | | Sets the timestamp a ban started at. | `--ban-start 2017-04-13T14:34:23` | N | +| `--charity-current-value` | | For charity events, manually set the charity dollar value. | `--charity-current-value 11000` | N | +| `--charity-target-value` | | Only used for "charity-*" events. Manually set the target dollar value for charity events. (default 1500000) | `--charity-target-value 23400` | N | +| `--client-id` | | Manually set the Client ID used for revoke, grant, and bits transactions. | `--client-id 4ofh8m0706jqpholgk00u3xvb4spct` | N | +| `--cost` | `-C` | Amount of subscriptions, bits, or channel points redeemed/used in the event. | `-C 250` | N | +| `--count` | `-c` | Count of events to fire. This can be used to simulate an influx of events. | `-c 100` | N | +| `--description` | `-d` | Title the stream should be updated/started with. | `-d Awesome new title!` | N | +| `--event-status` | `-S` | Status of the Event object (.event.status in JSON); Currently applies to channel points redemptions. | `-S fulfilled` | N | +| `--forward-address` | `-F` | Web server address for where to send mock events. | `-F https://localhost:8080` | N | +| `--from-user` | `-f` | Denotes the sender's TUID of the event, for example the user that follows another user or the subscriber to a broadcaster. | `-f 44635596` | N | +| `--from-user-name` | | Denotes the sender's Twitch Username of the event, for example the user that follows another user or the subscriber to a broadcaster. | `--from-user-name testname` | N | +| `--game-id` | `-G` | Game ID for Drop or other relevant events. | `-G 1234` | N | +| `--gift-user` | `-g` | Used only for subcription-based events, denotes the gifting user ID. | `-g 44635596` | N | +| `--item-id` | `-i` | Manually set the ID of the event payload item (for example the reward ID in redemption events or game in stream events). | `-i 032e4a6c-4aef-11eb-a9f5-1f703d1f0b92` | N | +| `--item-name` | `-n` | Manually set the name of the event payload item (for example the reward ID in redemption events or game name in stream events). | `-n "Science & Technology"` | N | +| `--no-config` | `-D` | Disables the use of the configuration values should they exist. | `-D` | N | +| `--secret` | `-s` | Webhook secret. If defined, signs all forwarded events with the SHA256 HMAC and must be 10-100 characters in length. | `-s testsecret` | N | +| `--session` | | WebSocket session to target. Only used when forwarding to WebSocket servers with --transport=websocket | `--session e411cc1e_a2613d4e` | N | +| `--subscription-id` | `-u` | Manually set the subscription/event ID of the event itself. | `-u 5d3aed06-d019-11ed-afa1-0242ac120002` | N | +| `--subscription-status` | `-r` | Status of the Subscription object (.subscription.status in JSON). Defaults to "enabled" | `-r revoked` | N | +| `--tier` | | Tier of the subscription. | `--tier 3000` | N | +| `--timestamp` | | Sets the timestamp to be used in payloads and headers. Must be in RFC3339Nano format. | `--timestamp 2017-04-13T14:34:23` | N | +| `--to-user` | `-t` | Denotes the receiver's TUID of the event, usually the broadcaster. | `-t 44635596` | N | +| `--to-user-name` | | Denotes the receiver's Twitch Username of the event, usually the broadcaster. | `--to-user-name testname` | N | +| `--transport` | `-T` | The method used to send events. Can either be `webhook` or `websocket`. Default is `webhook`. | `-T webhook` | N | **Examples** diff --git a/internal/events/trigger/trigger_event.go b/internal/events/trigger/trigger_event.go index 3d3f7da..ac2a549 100644 --- a/internal/events/trigger/trigger_event.go +++ b/internal/events/trigger/trigger_event.go @@ -27,7 +27,9 @@ type TriggerParameters struct { Transport string IsAnonymous bool FromUser string + FromUserName string ToUser string + ToUserName string GiftUser string EventStatus string SubscriptionStatus string @@ -80,10 +82,18 @@ func Fire(p TriggerParameters) (string, error) { p.ToUser = util.RandomUserID() } + if p.ToUserName == "" { + p.ToUserName = "testBroadcaster" + } + if p.FromUser == "" { p.FromUser = util.RandomUserID() } + if p.FromUserName == "" { + p.FromUserName = "testFromUser" + } + if p.GameID == "" { p.GameID = fmt.Sprint(util.RandomInt(10 * 1000)) } @@ -128,9 +138,9 @@ https://dev.twitch.tv/docs/eventsub/handling-webhook-events#processing-an-event` Trigger: p.Event, Transport: p.Transport, FromUserID: p.FromUser, - FromUserName: "testFromUser", + FromUserName: p.FromUserName, ToUserID: p.ToUser, - ToUserName: "testBroadcaster", + ToUserName: p.ToUserName, IsAnonymous: p.IsAnonymous, Cost: p.Cost, EventStatus: p.EventStatus, From 59d2379fe2774ecd29c98050063f28c7eb688f67 Mon Sep 17 00:00:00 2001 From: Rasmus Karlsson Date: Sat, 8 Feb 2025 15:10:35 +0100 Subject: [PATCH 2/2] feat: Add support for `channel.moderate` v2 topic --- cmd/events/trigger.go | 2 + cmd/events/variables.go | 1 + docs/event.md | 1 + internal/events/event.go | 1 + internal/events/trigger/trigger_event.go | 2 + .../channel_moderate_v2/channel_moderate.go | 160 ++++++++++++++++++ .../channel_moderate_test.go | 98 +++++++++++ internal/events/types/types.go | 2 + internal/models/channel_moderate.go | 147 ++++++++++++++++ 9 files changed, 414 insertions(+) create mode 100644 internal/events/types/channel_moderate_v2/channel_moderate.go create mode 100644 internal/events/types/channel_moderate_v2/channel_moderate_test.go create mode 100644 internal/models/channel_moderate.go diff --git a/cmd/events/trigger.go b/cmd/events/trigger.go index f50fd79..2b46ddc 100644 --- a/cmd/events/trigger.go +++ b/cmd/events/trigger.go @@ -59,6 +59,7 @@ func TriggerCommand() (command *cobra.Command) { command.Flags().StringVar(&websocketClient, "session", "", "Defines a specific websocket client/session to forward an event to. Used only with \"websocket\" transport.") command.Flags().StringVar(&banStart, "ban-start", "", "Sets the timestamp a ban started at.") command.Flags().StringVar(&banEnd, "ban-end", "", "Sets the timestamp a ban is intended to end at. If not set, the ban event will appear as permanent. This flag can take a timestamp or relative time (600, 600s, 10d4h12m55s)") + command.Flags().StringVar(&moderateAction, "moderate-action", "", "Specifies which moderate action to emit for \"channel.moderate\"") return } @@ -123,6 +124,7 @@ func triggerCmdRun(cmd *cobra.Command, args []string) error { WebSocketClient: websocketClient, BanStartTimestamp: banStart, BanEndTimestamp: banEnd, + ModerateAction: moderateAction, }) if err != nil { diff --git a/cmd/events/variables.go b/cmd/events/variables.go index 3eba634..4f9f329 100644 --- a/cmd/events/variables.go +++ b/cmd/events/variables.go @@ -32,4 +32,5 @@ var ( websocketClient string banStart string banEnd string + moderateAction string ) diff --git a/docs/event.md b/docs/event.md index 5c13e5f..633a0ed 100644 --- a/docs/event.md +++ b/docs/event.md @@ -117,6 +117,7 @@ This command can take either the Event or Alias listed as an argument. It is pre | `--to-user` | `-t` | Denotes the receiver's TUID of the event, usually the broadcaster. | `-t 44635596` | N | | `--to-user-name` | | Denotes the receiver's Twitch Username of the event, usually the broadcaster. | `--to-user-name testname` | N | | `--transport` | `-T` | The method used to send events. Can either be `webhook` or `websocket`. Default is `webhook`. | `-T webhook` | N | +| `--moderate-action` | | The moderate action used for the `channel.moderate` topic. If none is specified, a random event is sent. | `--moderate-action vip` | N | **Examples** diff --git a/internal/events/event.go b/internal/events/event.go index 4396724..9403cab 100644 --- a/internal/events/event.go +++ b/internal/events/event.go @@ -30,6 +30,7 @@ type MockEventParameters struct { ClientID string BanStartTimestamp string BanEndTimestamp string + ModerateAction string } type MockEventResponse struct { diff --git a/internal/events/trigger/trigger_event.go b/internal/events/trigger/trigger_event.go index ac2a549..615a59a 100644 --- a/internal/events/trigger/trigger_event.go +++ b/internal/events/trigger/trigger_event.go @@ -53,6 +53,7 @@ type TriggerParameters struct { WebSocketClient string BanStartTimestamp string BanEndTimestamp string + ModerateAction string } type TriggerResponse struct { @@ -157,6 +158,7 @@ https://dev.twitch.tv/docs/eventsub/handling-webhook-events#processing-an-event` GiftUser: p.GiftUser, BanStartTimestamp: p.BanStartTimestamp, BanEndTimestamp: p.BanEndTimestamp, + ModerateAction: p.ModerateAction, } e, err := types.GetByTriggerAndTransportAndVersion(p.Event, p.Transport, p.Version) diff --git a/internal/events/types/channel_moderate_v2/channel_moderate.go b/internal/events/types/channel_moderate_v2/channel_moderate.go new file mode 100644 index 0000000..d21284e --- /dev/null +++ b/internal/events/types/channel_moderate_v2/channel_moderate.go @@ -0,0 +1,160 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package channel_moderate_v2 + +import ( + "encoding/json" + "fmt" + "math/rand" + "strings" + + "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 triggerSupported = []string{"moderate"} + +var triggerMapping = map[string]map[string]string{ + models.TransportWebhook: { + "moderate": "channel.moderate", + }, + models.TransportWebSocket: { + "moderate": "channel.moderate", + }, +} + +type Event struct{} + +func (e Event) GenerateEvent(params events.MockEventParameters) (events.MockEventResponse, error) { + var supportedActions = []string{ + "vip", "unvip", + } + + var event []byte + var err error + + if params.ModerateAction == "" { + params.ModerateAction = supportedActions[rand.Intn(len(supportedActions))] + } + + switch params.Transport { + case models.TransportWebhook, models.TransportWebSocket: + body := &models.EventsubResponse{ + // make the eventsub response (if supported) + Subscription: models.EventsubSubscription{ + ID: params.SubscriptionID, + 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, + }, + } + eBody := models.ChannelModerateEventSubEvent{ + BroadcasterUserID: params.ToUserID, + BroadcasterUserLogin: params.ToUserName, + BroadcasterUserName: params.ToUserName, + ModeratorUserID: util.RandomUserID(), + ModeratorUserLogin: "CLIModerator", + ModeratorUserName: "CLIModerator", + } + switch params.ModerateAction { + case "vip": + eBody.Action = "vip" + eBody.Vip = &models.ChannelModerateVipAction{ + UserID: params.FromUserID, + UserLogin: params.FromUserName, + UserName: params.FromUserName, + } + case "unvip": + eBody.Action = "unvip" + eBody.Unvip = &models.ChannelModerateUnvipAction{ + UserID: params.FromUserID, + UserLogin: params.FromUserName, + UserName: params.FromUserName, + } + default: + return events.MockEventResponse{}, fmt.Errorf("\"%s\" is not a valid moderate action, supported actions are %v", params.ModerateAction, supportedActions) + } + body.Event = eBody + 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.EventMessageID, + JSON: event, + FromUser: params.FromUserID, + ToUser: params.ToUserID, + }, nil +} + +func (e Event) ValidTransport(t string) bool { + return transportsSupported[t] +} + +func (e Event) ValidTrigger(t string) bool { + for _, ts := range triggerSupported { + if ts == t { + 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 "2" +} diff --git a/internal/events/types/channel_moderate_v2/channel_moderate_test.go b/internal/events/types/channel_moderate_v2/channel_moderate_test.go new file mode 100644 index 0000000..40654d0 --- /dev/null +++ b/internal/events/types/channel_moderate_v2/channel_moderate_test.go @@ -0,0 +1,98 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package channel_moderate_v2 + +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: "stream-change", + SubscriptionStatus: "enabled", + } + + r, err := Event{}.GenerateEvent(params) + a.Nil(err) + + var body models.ChannelUpdateEventSubResponse + err = json.Unmarshal(r.JSON, &body) + a.Nil(err, "Error unmarshalling JSON") + + // write actual tests here (making sure you set appropriate values and the like) for eventsub + a.Equal(toUser, body.Event.BroadcasterUserID, "Expected Stream Channel %v, got %v", toUser, body.Event.BroadcasterUserID) + + // test for changing a title + params = events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: models.TransportWebhook, + Trigger: "stream_change", + SubscriptionStatus: "enabled", + GameID: "1234", + } + + r, err = Event{}.GenerateEvent(params) + a.Nil(err) + + err = json.Unmarshal(r.JSON, &body) + a.Nil(err) + + a.Equal(toUser, body.Event.BroadcasterUserID, "Expected Stream Channel %v, got %v", toUser, body.Event.BroadcasterUserID) + a.Equal("Example title from the CLI!", body.Event.StreamTitle, "Expected new stream title, got %v", body.Event.StreamTitle) + a.Equal("1234", body.Event.StreamCategoryID) +} + +func TestFakeTransport(t *testing.T) { + a := test_setup.SetupTestEnv(t) + + params := events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: "fake_transport", + Trigger: "stream-change", + 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("stream-change") + a.Equal(true, r) + + r = Event{}.ValidTrigger("not_trigger_keyword") + a.Equal(false, 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, "stream-change") + a.NotNil(r) +} diff --git a/internal/events/types/types.go b/internal/events/types/types.go index 77222aa..0fe81b3 100644 --- a/internal/events/types/types.go +++ b/internal/events/types/types.go @@ -13,6 +13,7 @@ import ( "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" + "github.com/twitchdev/twitch-cli/internal/events/types/channel_moderate_v2" "github.com/twitchdev/twitch-cli/internal/events/types/channel_points_redemption" "github.com/twitchdev/twitch-cli/internal/events/types/channel_points_reward" "github.com/twitchdev/twitch-cli/internal/events/types/channel_update_v1" @@ -65,6 +66,7 @@ func AllEvents() []events.MockEvent { shoutout.Event{}, channel_update_v1.Event{}, channel_update_v2.Event{}, + channel_moderate_v2.Event{}, streamup.Event{}, streamdown.Event{}, subscribe.Event{}, diff --git a/internal/models/channel_moderate.go b/internal/models/channel_moderate.go new file mode 100644 index 0000000..cb98ede --- /dev/null +++ b/internal/models/channel_moderate.go @@ -0,0 +1,147 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package models + +type ChannelModerateFollowersAction struct { + FollowDurationMinutes int `json:"follow_duration_minutes"` +} + +type ChannelModerateSlowAction struct { + WaitTimeSeconds int `json:"wait_time_seconds"` +} + +type ChannelModerateVipAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` +} + +type ChannelModerateUnvipAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` +} + +type ChannelModerateModAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` +} + +type ChannelModerateUnmodAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` +} + +type ChannelModerateBanAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + Reason string `json:"reason"` +} + +type ChannelModerateUnbanAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` +} + +type ChannelModerateTimeoutAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + Reason string `json:"reason"` + // TODO: This should be a timestamp type or something + ExpiresAt string `json:"expires_at"` +} + +type ChannelModerateUntimeoutAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` +} + +type ChannelModerateRaidAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + ViewerCount int `json:"viewer_count"` +} + +type ChannelModerateUnraidAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` +} + +type ChannelModerateDeleteAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + MessageID string `json:"message_id"` + MessageBody string `json:"message_body"` +} + +type ChannelModerateAutomodTermsAction struct { + Action string `json:"action"` + List string `json:"list"` + Terms []string `json:"terms"` + FromAutomod bool `json:"from_automod"` +} + +type ChannelModerateUnbanRequestAction struct { + IsApproved bool `json:"is_approved"` + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + ModeratorMessage string `json:"moderator_message"` +} + +type ChannelModerateWarnAction struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + Reason string `json:"reason"` + + ChatRulesCited []string `json:"chat_rules_cited"` +} + +type ChannelModerateEventSubEvent struct { + BroadcasterUserID string `json:"broadcaster_user_id"` + BroadcasterUserLogin string `json:"broadcaster_user_login"` + BroadcasterUserName string `json:"broadcaster_user_name"` + SourceBroadcasterUserID *string `json:"source_broadcaster_user_id"` + SourceBroadcasterUserLogin *string `json:"source_broadcaster_user_login"` + SourceBroadcasterUserName *string `json:"source_broadcaster_user_name"` + ModeratorUserID string `json:"moderator_user_id"` + ModeratorUserLogin string `json:"moderator_user_login"` + ModeratorUserName string `json:"moderator_user_name"` + Action string `json:"action"` + Followers *ChannelModerateFollowersAction `json:"followers"` + Slow *ChannelModerateSlowAction `json:"slow"` + Vip *ChannelModerateVipAction `json:"vip"` + Unvip *ChannelModerateUnvipAction `json:"unvip"` + Mod *ChannelModerateModAction `json:"mod"` + Unmod *ChannelModerateUnmodAction `json:"unmod"` + Ban *ChannelModerateBanAction `json:"ban"` + Unban *ChannelModerateUnbanAction `json:"unban"` + Timeout *ChannelModerateTimeoutAction `json:"timeout"` + Untimeout *ChannelModerateUntimeoutAction `json:"untimeout"` + Raid *ChannelModerateRaidAction `json:"raid"` + Unraid *ChannelModerateUnraidAction `json:"unraid"` + Delete *ChannelModerateDeleteAction `json:"delete"` + AutomodTerms *ChannelModerateAutomodTermsAction `json:"automod_terms"` + UnbanRequest *ChannelModerateUnbanRequestAction `json:"unban_request"` + Warn *ChannelModerateWarnAction `json:"warn"` + SharedChatBan *ChannelModerateBanAction `json:"shared_chat_ban"` + SharedChatUnban *ChannelModerateUnbanAction `json:"shared_chat_unban"` + SharedChatTimeout *ChannelModerateTimeoutAction `json:"shared_chat_timeout"` + SharedChatUntimeout *ChannelModerateUntimeoutAction `json:"shared_chat_untimeout"` + SharedChatDelete *ChannelModerateDeleteAction `json:"shared_chat_delete"` +} + +type ChannelModerateEventSubResponse struct { + Subscription EventsubSubscription `json:"subscription"` + Event ChannelModerateEventSubEvent `json:"event"` +}