Skip to content

Commit 414972f

Browse files
authored
Merge pull request #301 from Simply-Stream/fix/scopes-shoutout
Fix scope name for mock-api POST /chat/shoutouts endpoint
2 parents 5e37b40 + c8e1bcf commit 414972f

File tree

1 file changed

+133
-133
lines changed

1 file changed

+133
-133
lines changed
+133-133
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,133 @@
1-
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2-
// SPDX-License-Identifier: Apache-2.0
3-
package chat
4-
5-
import (
6-
"net/http"
7-
8-
"github.com/twitchdev/twitch-cli/internal/database"
9-
"github.com/twitchdev/twitch-cli/internal/mock_api/authentication"
10-
"github.com/twitchdev/twitch-cli/internal/mock_api/mock_errors"
11-
)
12-
13-
var shoutoutsMethodsSupported = map[string]bool{
14-
http.MethodGet: false,
15-
http.MethodPost: true,
16-
http.MethodDelete: false,
17-
http.MethodPatch: false,
18-
http.MethodPut: false,
19-
}
20-
21-
var shoutoutsScopesByMethod = map[string][]string{
22-
http.MethodGet: {},
23-
http.MethodPost: {"moderator:manage:shoutout"},
24-
http.MethodDelete: {},
25-
http.MethodPatch: {},
26-
http.MethodPut: {},
27-
}
28-
29-
type PostShoutoutsRequestBody struct {
30-
SlowMode *bool `json:"slow_mode"`
31-
SlowModeWaitTime *int `json:"slow_mode_wait_time"`
32-
FollowerMode *bool `json:"follower_mode"`
33-
FollowerModeDuration *int `json:"follower_mode_duration"`
34-
SubscriberMode *bool `json:"subscriber_mode"`
35-
EmoteMode *bool `json:"emote_mode"`
36-
UniqueChatMode *bool `json:"unique_chat_mode"`
37-
NonModeratorChatDelay *bool `json:"non_moderator_chat_delay"`
38-
NonModeratorChatDelayDuration *int `json:"non_moderator_chat_delay_duration"`
39-
}
40-
type Shoutouts struct{}
41-
42-
func (e Shoutouts) Path() string { return "/chat/shoutouts" }
43-
44-
func (e Shoutouts) GetRequiredScopes(method string) []string {
45-
return shoutoutsScopesByMethod[method]
46-
}
47-
48-
func (e Shoutouts) ValidMethod(method string) bool {
49-
return shoutoutsMethodsSupported[method]
50-
}
51-
52-
func (e Shoutouts) ServeHTTP(w http.ResponseWriter, r *http.Request) {
53-
db = r.Context().Value("db").(database.CLIDatabase)
54-
55-
switch r.Method {
56-
case http.MethodPost:
57-
postShoutouts(w, r)
58-
break
59-
default:
60-
w.WriteHeader(http.StatusMethodNotAllowed)
61-
}
62-
}
63-
64-
func postShoutouts(w http.ResponseWriter, r *http.Request) {
65-
userCtx := r.Context().Value("auth").(authentication.UserAuthentication)
66-
if !userCtx.MatchesModeratorIDParam(r) {
67-
mock_errors.WriteUnauthorized(w, "Moderator ID does not match token.")
68-
return
69-
}
70-
71-
fromBroadcasterId := r.URL.Query().Get("from_broadcaster_id")
72-
if fromBroadcasterId == "" {
73-
mock_errors.WriteBadRequest(w, "Missing required parameter from_broadcaster_id")
74-
return
75-
}
76-
77-
toBroadcasterId := r.URL.Query().Get("to_broadcaster_id")
78-
if toBroadcasterId == "" {
79-
mock_errors.WriteBadRequest(w, "Missing required parameter to_broadcaster_id")
80-
return
81-
}
82-
83-
moderatorID := r.URL.Query().Get("moderator_id")
84-
if moderatorID == "" {
85-
mock_errors.WriteBadRequest(w, "Missing required parameter moderator_id")
86-
return
87-
}
88-
89-
fromBroadcaster, err := db.NewQuery(r, 100).GetUser(database.User{ID: fromBroadcasterId})
90-
if err != nil {
91-
mock_errors.WriteServerError(w, "error fetching fromBrodcasterId")
92-
return
93-
}
94-
if fromBroadcaster.ID == "" {
95-
mock_errors.WriteBadRequest(w, "Invalid from_broadcaser_id: No broadcaster by that ID exists")
96-
return
97-
}
98-
99-
toBroadcaster, err := db.NewQuery(r, 100).GetUser(database.User{ID: toBroadcasterId})
100-
if err != nil {
101-
mock_errors.WriteServerError(w, "error fetching toBrodcasterId")
102-
return
103-
}
104-
if toBroadcaster.ID == "" {
105-
mock_errors.WriteBadRequest(w, "Invalid to_broadcaser_id: No broadcaster by that ID exists")
106-
return
107-
}
108-
109-
// Verify user is a moderator or is the broadcaster
110-
isModerator := false
111-
if fromBroadcasterId == moderatorID {
112-
isModerator = true
113-
} else {
114-
moderatorListDbr, err := db.NewQuery(r, 1000).GetModeratorsForBroadcaster(fromBroadcasterId)
115-
if err != nil {
116-
mock_errors.WriteServerError(w, err.Error())
117-
return
118-
}
119-
for _, mod := range moderatorListDbr.Data.([]database.Moderator) {
120-
if mod.UserID == moderatorID {
121-
isModerator = true
122-
}
123-
}
124-
}
125-
if !isModerator {
126-
mock_errors.WriteUnauthorized(w, "The user specified in parameter moderator_id is not one of the broadcaster's moderators")
127-
return
128-
}
129-
130-
// No connection to chat on here, and no way to GET or PATCH announcements via API
131-
// For the time being, we just ingest it and pretend it worked (HTTP 204)
132-
w.WriteHeader(http.StatusNoContent)
133-
}
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package chat
4+
5+
import (
6+
"net/http"
7+
8+
"github.com/twitchdev/twitch-cli/internal/database"
9+
"github.com/twitchdev/twitch-cli/internal/mock_api/authentication"
10+
"github.com/twitchdev/twitch-cli/internal/mock_api/mock_errors"
11+
)
12+
13+
var shoutoutsMethodsSupported = map[string]bool{
14+
http.MethodGet: false,
15+
http.MethodPost: true,
16+
http.MethodDelete: false,
17+
http.MethodPatch: false,
18+
http.MethodPut: false,
19+
}
20+
21+
var shoutoutsScopesByMethod = map[string][]string{
22+
http.MethodGet: {},
23+
http.MethodPost: {"moderator:manage:shoutouts"},
24+
http.MethodDelete: {},
25+
http.MethodPatch: {},
26+
http.MethodPut: {},
27+
}
28+
29+
type PostShoutoutsRequestBody struct {
30+
SlowMode *bool `json:"slow_mode"`
31+
SlowModeWaitTime *int `json:"slow_mode_wait_time"`
32+
FollowerMode *bool `json:"follower_mode"`
33+
FollowerModeDuration *int `json:"follower_mode_duration"`
34+
SubscriberMode *bool `json:"subscriber_mode"`
35+
EmoteMode *bool `json:"emote_mode"`
36+
UniqueChatMode *bool `json:"unique_chat_mode"`
37+
NonModeratorChatDelay *bool `json:"non_moderator_chat_delay"`
38+
NonModeratorChatDelayDuration *int `json:"non_moderator_chat_delay_duration"`
39+
}
40+
type Shoutouts struct{}
41+
42+
func (e Shoutouts) Path() string { return "/chat/shoutouts" }
43+
44+
func (e Shoutouts) GetRequiredScopes(method string) []string {
45+
return shoutoutsScopesByMethod[method]
46+
}
47+
48+
func (e Shoutouts) ValidMethod(method string) bool {
49+
return shoutoutsMethodsSupported[method]
50+
}
51+
52+
func (e Shoutouts) ServeHTTP(w http.ResponseWriter, r *http.Request) {
53+
db = r.Context().Value("db").(database.CLIDatabase)
54+
55+
switch r.Method {
56+
case http.MethodPost:
57+
postShoutouts(w, r)
58+
break
59+
default:
60+
w.WriteHeader(http.StatusMethodNotAllowed)
61+
}
62+
}
63+
64+
func postShoutouts(w http.ResponseWriter, r *http.Request) {
65+
userCtx := r.Context().Value("auth").(authentication.UserAuthentication)
66+
if !userCtx.MatchesModeratorIDParam(r) {
67+
mock_errors.WriteUnauthorized(w, "Moderator ID does not match token.")
68+
return
69+
}
70+
71+
fromBroadcasterId := r.URL.Query().Get("from_broadcaster_id")
72+
if fromBroadcasterId == "" {
73+
mock_errors.WriteBadRequest(w, "Missing required parameter from_broadcaster_id")
74+
return
75+
}
76+
77+
toBroadcasterId := r.URL.Query().Get("to_broadcaster_id")
78+
if toBroadcasterId == "" {
79+
mock_errors.WriteBadRequest(w, "Missing required parameter to_broadcaster_id")
80+
return
81+
}
82+
83+
moderatorID := r.URL.Query().Get("moderator_id")
84+
if moderatorID == "" {
85+
mock_errors.WriteBadRequest(w, "Missing required parameter moderator_id")
86+
return
87+
}
88+
89+
fromBroadcaster, err := db.NewQuery(r, 100).GetUser(database.User{ID: fromBroadcasterId})
90+
if err != nil {
91+
mock_errors.WriteServerError(w, "error fetching fromBrodcasterId")
92+
return
93+
}
94+
if fromBroadcaster.ID == "" {
95+
mock_errors.WriteBadRequest(w, "Invalid from_broadcaser_id: No broadcaster by that ID exists")
96+
return
97+
}
98+
99+
toBroadcaster, err := db.NewQuery(r, 100).GetUser(database.User{ID: toBroadcasterId})
100+
if err != nil {
101+
mock_errors.WriteServerError(w, "error fetching toBrodcasterId")
102+
return
103+
}
104+
if toBroadcaster.ID == "" {
105+
mock_errors.WriteBadRequest(w, "Invalid to_broadcaser_id: No broadcaster by that ID exists")
106+
return
107+
}
108+
109+
// Verify user is a moderator or is the broadcaster
110+
isModerator := false
111+
if fromBroadcasterId == moderatorID {
112+
isModerator = true
113+
} else {
114+
moderatorListDbr, err := db.NewQuery(r, 1000).GetModeratorsForBroadcaster(fromBroadcasterId)
115+
if err != nil {
116+
mock_errors.WriteServerError(w, err.Error())
117+
return
118+
}
119+
for _, mod := range moderatorListDbr.Data.([]database.Moderator) {
120+
if mod.UserID == moderatorID {
121+
isModerator = true
122+
}
123+
}
124+
}
125+
if !isModerator {
126+
mock_errors.WriteUnauthorized(w, "The user specified in parameter moderator_id is not one of the broadcaster's moderators")
127+
return
128+
}
129+
130+
// No connection to chat on here, and no way to GET or PATCH announcements via API
131+
// For the time being, we just ingest it and pretend it worked (HTTP 204)
132+
w.WriteHeader(http.StatusNoContent)
133+
}

0 commit comments

Comments
 (0)