Repository: nicklaw5/helix
Pull request #184 (2023-02-21 04:09:00)

Added user chat color endpoints
Added [GetUserChatColor](https://dev.twitch.tv/docs/api/reference/#update-user-chat-color) and [UpdateUserChatColor](https://dev.twitch.tv/docs/api/reference/#get-user-chat-color).


Patch:
diff --git a/SUPPORTED_ENDPOINTS.md b/SUPPORTED_ENDPOINTS.md
index 9fdfa40..11657a6 100644
--- a/SUPPORTED_ENDPOINTS.md
+++ b/SUPPORTED_ENDPOINTS.md
@@ -38,8 +38,8 @@
 - [x] Update Chat Settings
 - [x] Send Chat Announcement
 - [ ] Send a Shoutout
-- [ ] Get User Chat Color
-- [ ] Update User Chat Color
+- [x] Get User Chat Color
+- [x] Update User Chat Color
 - [x] Create Clip
 - [x] Get Clips
 - [x] Get Code Status
diff --git a/chat.go b/chat.go
index 6d9a68f..4e6ec5d 100644
--- a/chat.go
+++ b/chat.go
@@ -348,3 +348,83 @@ func (c *Client) UpdateChatSettings(params *UpdateChatSettingsParams) (*UpdateCh
 
 	return settings, nil
 }
+
+// UserChatColorResponse is the response from GetUserChatColor
+type UserChatColorResponse struct {
+	ResponseCommon
+	Data GetUserChatColorResponse
+}
+
+// GetUserChatColorParams are the parameters for GetUserChatColor
+type GetUserChatColorParams struct {
+	UserID string `json:"user_id"`
+}
+
+// GetUserChatColorResponse is the response data in UserChatColorResponse
+type GetUserChatColorResponse struct {
+	Data []GetUserChatColorUser `json:"data"`
+}
+
+// GetUserChatColorUser describes the user and their color
+type GetUserChatColorUser struct {
+	UserID    string `json:"user_id"`
+	UserLogin string `json:"user_login"`
+	UserName  string `json:"user_name"`
+	Color     string `json:"color"`
+}
+
+// GetUserChatColor fetches the color used for the user’s name in chat.
+func (c *Client) GetUserChatColor(params *GetUserChatColorParams) (*UserChatColorResponse, error) {
+	resp, err := c.get("/chat/color", &GetUserChatColorResponse{}, params)
+	if err != nil {
+		return nil, err
+	}
+
+	userColor := &UserChatColorResponse{}
+	resp.HydrateResponseCommon(&userColor.ResponseCommon)
+
+	return userColor, nil
+}
+
+// UpdateUserChatColorResponse is the response for UpdateUserChatColor
+type UpdateUserChatColorResponse struct {
+	ResponseCommon
+}
+
+// UpdateUserChatColorParams are the parameters for UpdateUserChatColor
+type UpdateUserChatColorParams struct {
+	UserID string `json:"user_id"`
+	Color  string `json:"color"`
+}
+
+// UpdateUserChatcolor updates the color used for the user’s name in chat.
+//
+// Required scope: user:manage:chat_color
+//
+// Prime and Turbo users can specify a Hex color code, everyone can use the default colors:
+//   - blue
+//   - blue_violet
+//   - cadet_blue
+//   - chocolate
+//   - coral
+//   - dodger_blue
+//   - firebrick
+//   - golden_rod
+//   - green
+//   - hot_pink
+//   - orange_red
+//   - red
+//   - sea_green
+//   - spring_green
+//   - yellow_green
+func (c *Client) UpdateUserChatColor(params *UpdateUserChatColorParams) (*UpdateUserChatColorResponse, error) {
+	resp, err := c.put("/chat/color", nil, params)
+	if err != nil {
+		return nil, err
+	}
+
+	update := &UpdateUserChatColorResponse{}
+	resp.HydrateResponseCommon(&update.ResponseCommon)
+
+	return update, nil
+}
diff --git a/docs/chat_docs.md b/docs/chat_docs.md
index 4ebfefb..6b70cf5 100644
--- a/docs/chat_docs.md
+++ b/docs/chat_docs.md
@@ -128,3 +128,45 @@ if err != nil {
 
 fmt.Printf("%+v\n", resp)
 ```
+
+## Get User Chat Color
+Gets the color used for the user’s name in chat.
+
+```go
+client, err := helix.NewClient(&helix.Options{
+    ClientID: "your-client-id",
+})
+if err != nil {
+    // handle error
+}
+
+resp, err := client.GetUserChatColor(&GetUserChatColorParams{
+    UserID: "22484632",
+})
+if err != nil {
+    // handle error
+}
+
+fmt.Printf("%+v\n", resp)
+```
+
+## Update User Chat Color
+Updates the color used for the user’s name in chat.
+```go
+client, err := helix.NewClient(&helix.Options{
+    ClientID: "your-client-id",
+})
+if err != nil {
+    // handle error
+}
+
+resp, err := client.UpdateUserChatColor(&UpdateUserChatColorParams{
+    UserID: "22484632",
+    Color: "blue"
+})
+if err != nil {
+    // handle error
+}
+
+fmt.Printf("%+v\n", resp)
+```
\ No newline at end of file


Test patch:
diff --git a/chat_test.go b/chat_test.go
index 9ddcb39..e8f108d 100644
--- a/chat_test.go
+++ b/chat_test.go
@@ -826,3 +826,119 @@ func TestUpdateChatSettings(t *testing.T) {
 		t.Errorf("expected error does match return error, got '%s'", err.Error())
 	}
 }
+
+func TestGetUserChatColor(t *testing.T) {
+	t.Parallel()
+
+	testCases := []struct {
+		statusCode int
+		options    *Options
+		UserID     string
+		respBody   string
+	}{
+		{
+			http.StatusOK,
+			&Options{ClientID: "my-client-id"},
+			"22484632",
+			`{"data": [{"user_id": "11111","user_name": "SpeedySpeedster1","user_login": "speedyspeedster1","color": "#9146FF"},{"user_id": "44444","user_name": "SpeedySpeedster2","user_login": "speedyspeedster2","color": ""}]}`,
+		},
+		{
+			http.StatusBadRequest,
+			&Options{ClientID: "my-client-id"},
+			"22484632",
+			`{"error":"Bad Request","status":400,"message":"The ID in the user_id query parameter is not valid."}`,
+		},
+	}
+
+	for _, testCase := range testCases {
+		c := newMockClient(testCase.options, newMockHandler(testCase.statusCode, testCase.respBody, nil))
+
+		resp, err := c.GetUserChatColor(&GetUserChatColorParams{
+			UserID: testCase.UserID,
+		})
+		if err != nil {
+			t.Error(err)
+		}
+
+		if resp.StatusCode != testCase.statusCode {
+			t.Errorf("expected status code to be %d, got %d", testCase.statusCode, resp.StatusCode)
+		}
+
+		if resp.StatusCode == http.StatusBadRequest {
+			if resp.Error != "Bad Request" {
+				t.Errorf("expected error to be %s, got %s", "Bad Request", resp.Error)
+			}
+
+			if resp.ErrorStatus != http.StatusBadRequest {
+				t.Errorf("expected error status to be %d, got %d", http.StatusBadRequest, resp.ErrorStatus)
+			}
+
+			expectedErrMsg := "The ID in the user_id query parameter is not valid."
+			if resp.ErrorMessage != expectedErrMsg {
+				t.Errorf("expected error message to be %s, got %s", expectedErrMsg, resp.ErrorMessage)
+			}
+
+			continue
+		}
+	}
+}
+
+func TestUpdateUserChatColor(t *testing.T) {
+	t.Parallel()
+
+	testCases := []struct {
+		statusCode int
+		options    *Options
+		UserID     string
+		Color      string
+		respBody   string
+	}{
+		{
+			http.StatusOK,
+			&Options{ClientID: "my-client-id"},
+			"22484632",
+			"blue",
+			``,
+		},
+		{
+			http.StatusBadRequest,
+			&Options{ClientID: "my-client-id"},
+			"22484632",
+			"bad_color",
+			`{"error":"Bad Request","status":400,"message":"The named color in the color query parameter is not valid."}`,
+		},
+	}
+
+	for _, testCase := range testCases {
+		c := newMockClient(testCase.options, newMockHandler(testCase.statusCode, testCase.respBody, nil))
+
+		resp, err := c.UpdateUserChatColor(&UpdateUserChatColorParams{
+			UserID: testCase.UserID,
+			Color:  testCase.Color,
+		})
+		if err != nil {
+			t.Error(err)
+		}
+
+		if resp.StatusCode != testCase.statusCode {
+			t.Errorf("expected status code to be %d, got %d", testCase.statusCode, resp.StatusCode)
+		}
+
+		if resp.StatusCode == http.StatusBadRequest {
+			if resp.Error != "Bad Request" {
+				t.Errorf("expected error to be %s, got %s", "Bad Request", resp.Error)
+			}
+
+			if resp.ErrorStatus != http.StatusBadRequest {
+				t.Errorf("expected error status to be %d, got %d", http.StatusBadRequest, resp.ErrorStatus)
+			}
+
+			expectedErrMsg := "The named color in the color query parameter is not valid."
+			if resp.ErrorMessage != expectedErrMsg {
+				t.Errorf("expected error message to be %s, got %s", expectedErrMsg, resp.ErrorMessage)
+			}
+
+			continue
+		}
+	}
+}