Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Twitch Creator Goals - Event Sub - SUPPORT #112

Merged
merged 5 commits into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/event.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ Used to either create or send mock events for use with local webhooks testing.
| `cheer` | Only usable with the `eventsub` transport |
| `drop` | Drops Entitlement event. |
| `gift` | A gifted subscription event. Triggers a basic tier 1 sub. |
| `goal-begin` | Channel creator goal start event. |
| `goal-end` | Channel creator goal end event. |
| `goal-progress` | Channel creator goal progress event. |
| `grant` | Authorization grant event. |
| `hype-train-begin` | Channel hype train start event. |
| `hype-train-end` | Channel hype train end event. |
Expand Down Expand Up @@ -131,6 +134,9 @@ Allows you to test if your webserver responds to subscription requests properly.
| `cheer` | Only usable with the `eventsub` transport |
| `drop` | Drops Entitlement event. |
| `gift` | A gifted subscription event. Triggers a basic tier 1 sub. |
| `goal-begin` | Channel creator goal start event. |
| `goal-end` | Channel creator goal end event. |
| `goal-progress` | Channel creator goal progress event. |
| `grant` | Authorization grant event. |
| `hype-train-begin` | Channel hype train start event. |
| `hype-train-end` | Channel hype train end event. |
Expand Down
3 changes: 3 additions & 0 deletions internal/events/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ var triggerSupported = map[string]bool{
"hype-train-begin": true,
"hype-train-progress": true,
"hype-train-end": true,
"goal-begin": true,
"goal-progress": true,
"goal-end": true,
}

var transportSupported = map[string]bool{
Expand Down
137 changes: 137 additions & 0 deletions internal/events/types/goal/goal_event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package goal

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.TransportEventSub: true,
}

var triggerSupported = []string{"goal-begin", "goal-progress", "goal-end"}

var triggerMapping = map[string]map[string]string{
models.TransportEventSub: {
"goal-progress": "channel.goal.progress",
"goal-begin": "channel.goal.begin",
"goal-end": "channel.goal.end",
},
}

type Event struct{}

func (e Event) GenerateEvent(params events.MockEventParameters) (events.MockEventResponse, error) {
var event []byte
var err error
var isAchieved *bool
var goalEndDate *string
var goalType string
var currentAmount int64
var targetAmount int64

goalStartedAt := util.GetTimestamp()
currentAmount = util.RandomInt(10 * 10)
targetAmount = util.RandomInt(10 * 100)

if params.Trigger == "goal-end" {
endDate := goalStartedAt.Add(time.Hour * 24).Format(time.RFC3339)
goalEndDate = &endDate

achieved := util.RandomInt(1) == 1
if achieved {
currentAmount = 100
targetAmount = 100
}

isAchieved = &achieved
}
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved

goalType = params.ItemName
if goalType == "" {
goalType = "follower"
}

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",
},
Cost: 0,
CreatedAt: util.GetTimestamp().Format(time.RFC3339Nano),
},
Event: models.GoalEventSubEvent{
ID: params.ID,
BroadcasterUserID: params.ToUserID,
BroadcasterUserLogin: params.ToUserName,
BroadcasterUserName: params.ToUserName,
Type: goalType,
Description: params.Description,
CurrentAmount: currentAmount,
TargetAmount: targetAmount,
StartedAt: goalStartedAt.Format(time.RFC3339Nano),
EndedAt: goalEndDate,
IsAchieved: isAchieved,
},
}

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(trigger string) bool {
for _, t := range triggerSupported {
if t == trigger {
return true
}
}
return false
}

func (e Event) GetTopic(transport string, trigger string) string {
return triggerMapping[transport][trigger]
}

func (e Event) GetEventSubAlias(t string) string {
// check for aliases
for trigger, topic := range triggerMapping[models.TransportEventSub] {
if topic == t {
return trigger
}
}
return ""
}
112 changes: 112 additions & 0 deletions internal/events/types/goal/goal_event_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package goal

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 user = "1234"

func TestEventSub(t *testing.T) {
a := test_setup.SetupTestEnv(t)

params := *&events.MockEventParameters{
ToUserID: user,
Description: "Twitch Subscriber Goal",
Transport: models.TransportEventSub,
Trigger: "goal-begin",
Status: "subscriber",
}

r, err := Event{}.GenerateEvent(params)
a.Nil(err)

var body models.GoalEventSubResponse
err = json.Unmarshal(r.JSON, &body)
a.Nil(err)

a.Equal("channel.goal.begin", body.Subscription.Type, "Expected event type %v, got %v", "channel.goal.begin", body.Subscription.Type)
a.Equal(user, body.Event.BroadcasterUserID, "Expected from user %v, got %v", r.ToUser, body.Event.BroadcasterUserID)
a.Equal("Twitch Subscriber Goal", body.Event.Description, "Expected from goal type %v, got %v", "Twitch Subscriber Goal", body.Event.Type)

params = *&events.MockEventParameters{
ToUserID: user,
Description: "Twitch Follower Goal",
Transport: models.TransportEventSub,
Trigger: "goal-progress",
}

r, err = Event{}.GenerateEvent(params)
a.Nil(err)

err = json.Unmarshal(r.JSON, &body)
a.Nil(err)

a.Equal("channel.goal.progress", body.Subscription.Type, "Expected event type %v, got %v", "channel.goal.progress", body.Subscription.Type)
a.Equal(user, body.Event.BroadcasterUserID, "Expected from user %v, got %v", r.ToUser, body.Event.BroadcasterUserID)

params = *&events.MockEventParameters{
ToUserID: user,
Description: "Twitch Follower Goal",
Transport: models.TransportEventSub,
Trigger: "goal-end",
}

r, err = Event{}.GenerateEvent(params)
a.Nil(err)

err = json.Unmarshal(r.JSON, &body)
a.Nil(err)

a.Equal("channel.goal.end", body.Subscription.Type, "Expected event type %v, got %v", "channel.goal.end", body.Subscription.Type)
a.Equal(user, body.Event.BroadcasterUserID, "Expected from user %v, got %v", r.ToUser, body.Event.BroadcasterUserID)
a.NotNil(body.Event.EndedAt, "Expected endedDate to be nil got %v", body.Event.EndedAt)
a.NotNil(body.Event.IsAchieved, "Expected endedDate to be nil got %v", body.Event.IsAchieved)
}

func TestFakeTransport(t *testing.T) {
a := test_setup.SetupTestEnv(t)

params := *&events.MockEventParameters{
FromUserID: user,
Transport: "fake_transport",
Trigger: "unsubscribe",
}

r, err := Event{}.GenerateEvent(params)
a.Nil(err)
a.Empty(r)
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved
}

func TestValidTrigger(t *testing.T) {
a := test_setup.SetupTestEnv(t)

r := Event{}.ValidTrigger("goal-begin")
a.Equal(true, r)

r = Event{}.ValidTrigger("goal-started")
a.Equal(false, r)
}

func TestValidTransport(t *testing.T) {
a := test_setup.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 := test_setup.SetupTestEnv(t)

r := Event{}.GetTopic(models.TransportEventSub, "goal-progress")
a.NotNil(r)
}
2 changes: 2 additions & 0 deletions internal/events/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/twitchdev/twitch-cli/internal/events/types/extension_transaction"
"github.com/twitchdev/twitch-cli/internal/events/types/follow"
"github.com/twitchdev/twitch-cli/internal/events/types/gift"
"github.com/twitchdev/twitch-cli/internal/events/types/goal"
"github.com/twitchdev/twitch-cli/internal/events/types/hype_train"
"github.com/twitchdev/twitch-cli/internal/events/types/moderator_change"
"github.com/twitchdev/twitch-cli/internal/events/types/poll"
Expand Down Expand Up @@ -49,6 +50,7 @@ func All() []events.MockEvent {
streamdown.Event{},
subscribe.Event{},
subscription_message.Event{},
goal.Event{},
}
}

Expand Down
20 changes: 20 additions & 0 deletions internal/models/goal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package models

type GoalEventSubEvent struct {
ID string `json:"id"`
BroadcasterUserID string `json:"broadcaster_user_id"`
BroadcasterUserName string `json:"broadcaster_user_name"`
BroadcasterUserLogin string `json:"broadcaster_user_login"`
Type string `json:"type"`
Description string `json:"description"`
IsAchieved *bool `json:"is_achieved,omitempty"`
CurrentAmount int64 `json:"current_amount"`
TargetAmount int64 `json:"target_amount"`
StartedAt string `json:"started_at"`
EndedAt *string `json:"ended_at,omitempty"`
}

type GoalEventSubResponse struct {
Subscription EventsubSubscription `json:"subscription"`
Event GoalEventSubEvent `json:"event"`
}