diff --git a/docs/event.md b/docs/event.md index 40e33e30..3cd44eab 100644 --- a/docs/event.md +++ b/docs/event.md @@ -17,7 +17,7 @@ Used to either create or send mock events for use with local webhooks testing. **Args** | Argument | Description | -| ------------------- | ---------------------------------------------------------------------------------------------------------- | +|---------------------|------------------------------------------------------------------------------------------------------------| | `subscribe` | A standard subscription event. Triggers a basic tier 1 sub. | | `unsubscribe` | A standard unsubscribe event. Triggers a basic tier 1 sub. | | `gift` | A gifted subscription event. Triggers a basic tier 1 sub. | @@ -31,10 +31,13 @@ Used to either create or send mock events for use with local webhooks testing. | `raid` | Channel Raid event with a random viewer count. | | `revoke` | User authorization revoke event. Uses local Client as set in `twitch configure` or generates one randomly. | | `stream-change` | Stream Changed event. | -| `streamup` | Stream online event. | -| `streamdown` | Sstream offline event. | +| `streamup` | Stream online event. | +| `streamdown` | Sstream offline event. | | `add-moderator` | Channel moderator add event. | | `remove-moderator` | Channel moderator removal event. | +| `ban` | Channel ban event. | +| `unban` | Channel unban event. | + **Flags** @@ -102,7 +105,7 @@ Allows you to test if your webserver responds to subscription requests properly. **Args** | Argument | Description | -| ------------------- | ---------------------------------------------------------------------------------------------------------- | +|---------------------|------------------------------------------------------------------------------------------------------------| | `subscribe` | A standard subscription event. Triggers a basic tier 1 sub. | | `unsubscribe` | A standard unsubscribe event. Triggers a basic tier 1 sub. | | `gift` | A gifted subscription event. Triggers a basic tier 1 sub. | @@ -115,11 +118,13 @@ Allows you to test if your webserver responds to subscription requests properly. | `update-redemption` | Channel Points EventSub event for a redemption being updated. | | `raid` | Channel Raid event with a random viewer count. | | `revoke` | User authorization revoke event. Uses local Client as set in `twitch configure` or generates one randomly. | -| `stream_change` | Stream changed event. | -| `streamup` | Stream online event. | -| `streamdown` | Stream offline event. | +| `stream-change` | Stream Changed event. | +| `streamup` | Stream online event. | +| `streamdown` | Sstream offline event. | | `add-moderator` | Channel moderator add event. | | `remove-moderator` | Channel moderator removal event. | +| `ban` | Channel ban event. | +| `unban` | Channel unban event. | **Flags** diff --git a/internal/events/event.go b/internal/events/event.go index 8302c682..6b6dd4f9 100644 --- a/internal/events/event.go +++ b/internal/events/event.go @@ -17,6 +17,7 @@ type MockEventParameters struct { Status string ItemID string Cost int64 + IsPermanent bool StreamTitle string } diff --git a/internal/events/models.go b/internal/events/models.go index a4f9afc9..e2ee9d32 100644 --- a/internal/events/models.go +++ b/internal/events/models.go @@ -16,6 +16,8 @@ var triggerSupported = map[string]bool{ "remove-reward": true, "add-moderator": true, "remove-moderator": true, + "ban": true, + "unban": true, } var transportSupported = map[string]bool{ diff --git a/internal/events/types/ban/ban.go b/internal/events/types/ban/ban.go new file mode 100644 index 00000000..83db53e7 --- /dev/null +++ b/internal/events/types/ban/ban.go @@ -0,0 +1,127 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package ban + +import ( + "encoding/json" + "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.TransportWebSub: true, + models.TransportEventSub: true, +} + +var triggerSupported = []string{"ban", "unban"} + +var triggerMapping = map[string]map[string]string{ + models.TransportWebSub: { + "ban": "moderation.user.ban", + "unban": "moderation.user.unban", + }, + models.TransportEventSub: { + "ban": "channel.ban", + "unban": "channel.unban", + }, +} + +type Event struct{} + +func (e Event) GenerateEvent(params events.MockEventParameters) (events.MockEventResponse, error) { + var event []byte + var err error + + switch params.Transport { + case models.TransportEventSub: + body := *&models.EventsubResponse{ + Subscription: models.EventsubSubscription{ + ID: params.ID, + Status: "enabled", + Type: triggerMapping[params.Transport][params.Trigger], + Version: "1", + Condition: models.EventsubCondition{ + BroadcasterUserID: params.ToUserID, + }, + Transport: models.EventsubTransport{ + Method: "webhook", + Callback: "null", + }, + CreatedAt: util.GetTimestamp().Format(time.RFC3339Nano), + }, + Event: models.BanEventSubEvent{ + UserID: params.FromUserID, + UserLogin: params.FromUserName, + UserName: params.FromUserName, + BroadcasterUserID: params.ToUserID, + BroadcasterUserLogin: params.ToUserName, + BroadcasterUserName: params.ToUserName, + ModeratorUserId: util.RandomUserID(), + ModeratorUserLogin: "CLIModerator", + ModeratorUserName: "CLIModerator", + Reason: "This is a test event", + EndsAt: util.GetTimestamp().Format(time.RFC3339Nano), + IsPermanent: params.IsPermanent, + }, + } + + event, err = json.Marshal(body) + if err != nil { + return events.MockEventResponse{}, err + } + + case models.TransportWebSub: + body := *&models.BanWebSubResponse{ + Data: []models.BanWebSubResponseData{ + { + ID: params.ID, + EventType: triggerMapping[params.Transport][params.Trigger], + EventTimestamp: util.GetTimestamp().Format(time.RFC3339), + Version: "v1", + EventData: models.BanWebSubEventData{ + BroadcasterID: params.ToUserID, + BroadcasterUserLogin: params.ToUserName, + BroadcasterName: params.ToUserName, + UserID: params.FromUserID, + UserLogin: params.FromUserName, + UserName: params.FromUserName, + ExpiresAt: util.GetTimestamp().Add(1 * time.Hour).Format(time.RFC3339), + }, + }, + }} + + event, err = json.Marshal(body) + 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(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] +} diff --git a/internal/events/types/ban/ban_test.go b/internal/events/types/ban/ban_test.go new file mode 100644 index 00000000..e370b350 --- /dev/null +++ b/internal/events/types/ban/ban_test.go @@ -0,0 +1,136 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package ban + +import ( + "encoding/json" + "testing" + + "github.com/twitchdev/twitch-cli/internal/events" + "github.com/twitchdev/twitch-cli/internal/models" + "github.com/twitchdev/twitch-cli/internal/util" +) + +var fromUser = "1234" +var toUser = "4567" + +func TestEventSubBan(t *testing.T) { + a := util.SetupTestEnv(t) + params := events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: models.TransportEventSub, + Trigger: "ban", + } + + r, err := Event{}.GenerateEvent(params) + a.Nil(err, "Error generating body.") + + var body models.BanEventSubResponse + + 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) + a.Equal(fromUser, body.Event.UserID, "Expected from user %v, got %v", r.ToUser, body.Event.UserID) + + // test for unban + params = events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: models.TransportEventSub, + Trigger: "unban", + } + + r, err = Event{}.GenerateEvent(params) + a.Nil(err) + + 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", fromUser, body.Event.UserID) +} + +func TestWebSubBan(t *testing.T) { + a := util.SetupTestEnv(t) + + params := *&events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: models.TransportWebSub, + Trigger: "ban", + } + + r, err := Event{}.GenerateEvent(params) + a.Nil(err) + + var body models.BanWebSubResponse + err = json.Unmarshal(r.JSON, &body) + a.Nil(err) + + a.Equal(toUser, body.Data[0].EventData.BroadcasterID, "Expected to user %v, got %v", toUser, body.Data[0].EventData.BroadcasterID) + a.Equal(fromUser, body.Data[0].EventData.UserID, "Expected from user %v, got %v", fromUser, body.Data[0].EventData.UserID) + + params = *&events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: models.TransportWebSub, + Trigger: "unban", + } + + r, err = Event{}.GenerateEvent(params) + a.Nil(err) + + err = json.Unmarshal(r.JSON, &body) + a.Nil(err) + + a.Equal(toUser, body.Data[0].EventData.BroadcasterID, "Expected to user %v, got %v", toUser, body.Data[0].EventData.BroadcasterID) + a.Equal(fromUser, body.Data[0].EventData.UserID, "Expected from user %v, got %v", fromUser, body.Data[0].EventData.UserID) + +} + +func TestFakeTransport(t *testing.T) { + a := util.SetupTestEnv(t) + + params := events.MockEventParameters{ + FromUserID: fromUser, + ToUserID: toUser, + Transport: "fake_transport", + Trigger: "unban", + } + + r, err := Event{}.GenerateEvent(params) + a.Nil(err) + a.Empty(r) +} + +func TestValidTrigger(t *testing.T) { + a := util.SetupTestEnv(t) + + r := Event{}.ValidTrigger("ban") + a.Equal(true, r) + + r = Event{}.ValidTrigger("unban") + a.Equal(true, r) + + r = Event{}.ValidTrigger("notban") + a.Equal(false, r) +} + +func TestValidTransport(t *testing.T) { + a := util.SetupTestEnv(t) + + r := Event{}.ValidTransport(models.TransportEventSub) + a.Equal(true, r) + + r = Event{}.ValidTransport("noteventsub") + a.Equal(false, r) +} + +func TestGetTopic(t *testing.T) { + a := util.SetupTestEnv(t) + + r := Event{}.GetTopic(models.TransportEventSub, "ban") + a.NotNil(r) +} diff --git a/internal/events/types/types.go b/internal/events/types/types.go index 9b96decd..4549244a 100644 --- a/internal/events/types/types.go +++ b/internal/events/types/types.go @@ -18,6 +18,7 @@ import ( "github.com/twitchdev/twitch-cli/internal/events/types/streamdown" "github.com/twitchdev/twitch-cli/internal/events/types/streamup" "github.com/twitchdev/twitch-cli/internal/events/types/subscribe" + "github.com/twitchdev/twitch-cli/internal/events/types/ban" ) func All() []events.MockEvent { @@ -34,6 +35,7 @@ func All() []events.MockEvent { streamup.Event{}, streamdown.Event{}, moderator_change.Event{}, + ban.Event{}, } } diff --git a/internal/models/ban.go b/internal/models/ban.go new file mode 100644 index 00000000..0ade7f7e --- /dev/null +++ b/internal/models/ban.go @@ -0,0 +1,45 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package models + +type BanEventSubEvent struct { + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + 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"` + Reason string `json:"reason"` + EndsAt string `json:"ends_at"` + IsPermanent bool `json:"is_permanent"` +} + +type BanEventSubResponse struct { + Subscription EventsubSubscription `json:"ban"` + Event BanEventSubEvent `json:"event"` +} + +type BanWebSubResponse struct { + Data []BanWebSubResponseData `json:"data"` +} + +type BanWebSubResponseData struct { + ID string `json:"id"` + EventType string `json:"event_type"` + EventTimestamp string `json:"event_timestamp"` + Version string `json:"version"` + EventData BanWebSubEventData `json:"event_data"` +} + +type BanWebSubEventData struct { + BroadcasterID string `json:"broadcaster_id"` + BroadcasterUserLogin string `json:"broadcaster_login"` + BroadcasterName string `json:"broadcaster_name"` + UserID string `json:"user_id"` + UserLogin string `json:"user_login"` + UserName string `json:"user_name"` + ExpiresAt string `json:"expires_at"` +}