Skip to content

Commit

Permalink
Merge pull request #225 from jackmcguire1/feat/warn
Browse files Browse the repository at this point in the history
feat: warn chat user endpoint
  • Loading branch information
nicklaw5 authored Jul 9, 2024
2 parents 22863cc + 0bf715b commit 227361a
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 0 deletions.
1 change: 1 addition & 0 deletions SUPPORTED_ENDPOINTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,4 @@
- [x] Delete Videos
- [x] Send Whisper
- [x] Get Webhook Subscriptions
- [x] Warn Chat User
28 changes: 28 additions & 0 deletions docs/moderation_docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,31 @@ if err != nil {

fmt.Printf("%+v\n", resp)
```

## Warn Chat User

Requires a user access token that includes the moderator:manage:warnings scope. Query parameter moderator_id must match the user_id in the user access token.

```go
client, err := helix.NewClient(&helix.Options{
ClientID: "your-client-id",
UserAccessToken: "your-user-access-token",
})
if err != nil {
// handle error
}

resp, err := client.SendModeratorWarnMessage(
&SendModeratorWarnChatMessageParams{
BroadcasterID: "1234",
ModeratorID: "5678",
UserID: "9876",
Reason: "Test warning message",
},
)
if err != nil {
// handle error
}

fmt.Printf("%+v\n", resp)
```
56 changes: 56 additions & 0 deletions moderation.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,59 @@ func (c *Client) GetModeratedChannels(params *GetModeratedChannelsParams) (*GetM

return moderatedChannels, nil
}

type SendModeratorWarnChatMessageParams struct {
// The ID of the broadcaster whose chat room the message will be sent to
BroadcasterID string `query:"broadcaster_id"`

// The ID of the twitch user who requested the warning.
ModeratorID string `query:"moderator_id"`

// The ID of the user sent the WARN message
UserID string `json:"user_id"`

// The warn message to send.
Reason string `json:"reason"`
}

type ModeratorWarnChatMessage struct {
BroadcasterID string `json:"broadcaster_id"`
ModeratorID string `json:"moderator_id"`
UserID string `json:"user_id"`
Reason string `json:"reason"`
}

type ManyModeratorWarnChatMessages struct {
Warnings []ModeratorWarnChatMessage `json:"data"`
}

type SendModeratorWarnChatResponse struct {
ResponseCommon

Data ManyModeratorWarnChatMessages
}

// SendModeratorWarnMessage Sends a warning message to a user in the broadcaster’s chat.
// Required moderator:manage:warnings
func (c *Client) SendModeratorWarnMessage(params *SendModeratorWarnChatMessageParams) (*SendModeratorWarnChatResponse, error) {
if params.BroadcasterID == "" {
return nil, errors.New("error: broadcaster id must be specified")
}
if params.ModeratorID == "" {
return nil, errors.New("error: moderator id must be specified")
}
if params.UserID == "" {
return nil, errors.New("error: user id must be specified")
}

resp, err := c.postAsJSON("moderation/warnings", &ManyModeratorWarnChatMessages{}, params)
if err != nil {
return nil, err
}

messageResponse := &SendModeratorWarnChatResponse{}
resp.HydrateResponseCommon(&messageResponse.ResponseCommon)
messageResponse.Data.Warnings = resp.Data.(*ManyModeratorWarnChatMessages).Warnings

return messageResponse, nil
}
138 changes: 138 additions & 0 deletions moderation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1117,3 +1117,141 @@ func TestGetModeratedChannels(t *testing.T) {
t.Error("expected error does match return error")
}
}

func TestSendModeratorWarnMessage(t *testing.T) {
t.Parallel()

testCases := []struct {
statusCode int
options *Options
params *SendModeratorWarnChatMessageParams
respBody string
errorMsg string
}{
{
http.StatusOK,
&Options{ClientID: "my-client-id", UserAccessToken: "moderator-access-token"},
&SendModeratorWarnChatMessageParams{
BroadcasterID: "1234",
ModeratorID: "5678",
UserID: "9876",
Reason: "Test warning message",
},
`{"data": [{"broadcaster_id": "1234", "moderator_id": "5678", "user_id": "9876", "reason": "Test warning message"}]}`,
"",
},
{
http.StatusOK,
&Options{ClientID: "my-client-id", UserAccessToken: "invalid-access-token"},
&SendModeratorWarnChatMessageParams{
BroadcasterID: "1234",
ModeratorID: "5678",
Reason: "Test warning message",
},
"",
"error: user id must be specified",
},
{
http.StatusOK,
&Options{ClientID: "my-client-id", UserAccessToken: "invalid-access-token"},
&SendModeratorWarnChatMessageParams{
UserID: "1234",
ModeratorID: "5678",
Reason: "Test warning message",
},
"",
"error: broadcaster id must be specified",
},
{
http.StatusOK,
&Options{ClientID: "my-client-id", UserAccessToken: "invalid-access-token"},
&SendModeratorWarnChatMessageParams{
UserID: "1234",
BroadcasterID: "12345",
Reason: "Test warning message",
},
"",
"error: moderator id must be specified",
},
{
http.StatusUnauthorized,
&Options{ClientID: "my-client-id", UserAccessToken: "invalid-access-token"},
&SendModeratorWarnChatMessageParams{
BroadcasterID: "1234",
ModeratorID: "5678",
UserID: "9876",
Reason: "Test warning message",
},
`{"error":"Unauthorized","status":401,"message":"Invalid OAuth token"}`,
"",
},
// Add more test cases as needed
}

for _, testCase := range testCases {
c := newMockClient(testCase.options, newMockHandler(testCase.statusCode, testCase.respBody, nil))

resp, err := c.SendModeratorWarnMessage(testCase.params)
if err != nil {
if err.Error() != testCase.errorMsg {
t.Errorf("expected error message to be %s, got %s", testCase.errorMsg, err.Error())
}
continue
}

if resp.StatusCode != testCase.statusCode {
t.Errorf("expected status code to be %d, got %d", testCase.statusCode, resp.StatusCode)
}

if resp.StatusCode > http.StatusOK {
continue
}

if len(resp.Data.Warnings) == 0 {
continue
}
warning := resp.Data.Warnings[0]

if warning.BroadcasterID != testCase.params.BroadcasterID {
t.Errorf("expected broadcaster id to be %s, got %s", testCase.params.BroadcasterID, warning.BroadcasterID)
}

if warning.ModeratorID != testCase.params.ModeratorID {
t.Errorf("expected moderator id to be %s, got %s", testCase.params.ModeratorID, warning.ModeratorID)
}

if warning.UserID != testCase.params.UserID {
t.Errorf("expected user id to be %s, got %s", testCase.params.UserID, warning.UserID)
}

if warning.Reason != testCase.params.Reason {
t.Errorf("expected reason to be %s, got %s", testCase.params.Reason, warning.Reason)
}
}

// Test with HTTP Failure
options := &Options{
ClientID: "my-client-id",
HTTPClient: &badMockHTTPClient{
newMockHandler(0, "", nil),
},
}
c := &Client{
opts: options,
ctx: context.Background(),
}

_, err := c.SendModeratorWarnMessage(&SendModeratorWarnChatMessageParams{
BroadcasterID: "1234",
ModeratorID: "5678",
UserID: "9876",
Reason: "Test warning message",
})
if err == nil {
t.Error("expected error but got nil")
}

if err.Error() != "Failed to execute API request: Oops, that's bad :(" {
t.Error("expected error does match return error")
}
}

0 comments on commit 227361a

Please sign in to comment.