-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrest.go
More file actions
157 lines (138 loc) · 5.23 KB
/
Copy pathrest.go
File metadata and controls
157 lines (138 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package nerimity
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
// APIError is returned when the Nerimity REST API responds with a non-2xx
// status. Body holds the raw response body for inspection.
type APIError struct {
Status int
Body string
}
func (e *APIError) Error() string {
return fmt.Sprintf("nerimity: API returned %d: %s", e.Status, e.Body)
}
// doJSON performs a JSON request. If body is non-nil it is marshalled as the
// request body; if out is non-nil the response body is unmarshalled into it.
// authToken, when non-empty, is sent as the Authorization header (Nerimity uses
// the raw token, with no "Bearer" prefix).
func (c *Client) doJSON(ctx context.Context, method, url string, body, out any, authToken string) error {
var reader io.Reader
if body != nil {
b, err := json.Marshal(body)
if err != nil {
return fmt.Errorf("nerimity: encoding request body: %w", err)
}
reader = bytes.NewReader(b)
}
req, err := http.NewRequestWithContext(ctx, method, url, reader)
if err != nil {
return fmt.Errorf("nerimity: building request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
if authToken != "" {
req.Header.Set("Authorization", authToken)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("nerimity: could not connect to server: %w", err)
}
defer resp.Body.Close()
raw, _ := io.ReadAll(resp.Body)
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return &APIError{Status: resp.StatusCode, Body: string(raw)}
}
if out != nil && len(raw) > 0 {
if err := json.Unmarshal(raw, out); err != nil {
return fmt.Errorf("nerimity: decoding response: %w", err)
}
}
return nil
}
func (c *Client) messagesURL(channelID string) string {
return c.apiBase + "/channels/" + channelID + "/messages"
}
func (c *Client) messageURL(channelID, messageID string) string {
return c.messagesURL(channelID) + "/" + messageID
}
type postMessageBody struct {
Content string `json:"content"`
NerimityCdnFileID string `json:"nerimityCdnFileId,omitempty"`
HTMLEmbed string `json:"htmlEmbed,omitempty"`
Buttons []ButtonOption `json:"buttons,omitempty"`
Silent bool `json:"silent,omitempty"`
MentionReplies bool `json:"mentionReplies,omitempty"`
ReplyToMessageIDs []string `json:"replyToMessageIds,omitempty"`
}
func (c *Client) postMessage(ctx context.Context, channelID, content string, opts MessageOptions) (*Message, error) {
body := postMessageBody{
Content: content,
NerimityCdnFileID: opts.NerimityCdnFileID,
HTMLEmbed: opts.HTMLEmbed,
Buttons: opts.Buttons,
Silent: opts.Silent,
MentionReplies: opts.MentionReplies,
ReplyToMessageIDs: opts.ReplyToMessageIDs,
}
var raw rawMessage
if err := c.doJSON(ctx, http.MethodPost, c.messagesURL(channelID), body, &raw, c.token); err != nil {
return nil, err
}
return newMessage(c, raw), nil
}
type editMessageBody struct {
Content string `json:"content"`
HTMLEmbed string `json:"htmlEmbed,omitempty"`
Buttons []ButtonOption `json:"buttons,omitempty"`
}
func (c *Client) editMessage(ctx context.Context, channelID, messageID, content string, opts EditOptions) (*Message, error) {
body := editMessageBody{Content: content, HTMLEmbed: opts.HTMLEmbed, Buttons: opts.Buttons}
var raw rawMessage
if err := c.doJSON(ctx, http.MethodPatch, c.messageURL(channelID, messageID), body, &raw, c.token); err != nil {
return nil, err
}
return newMessage(c, raw), nil
}
func (c *Client) deleteMessage(ctx context.Context, channelID, messageID string) error {
return c.doJSON(ctx, http.MethodDelete, c.messageURL(channelID, messageID), nil, nil, c.token)
}
func (c *Client) fetchMessage(ctx context.Context, channelID, messageID string) (*Message, error) {
var raw rawMessage
if err := c.doJSON(ctx, http.MethodGet, c.messageURL(channelID, messageID), nil, &raw, c.token); err != nil {
return nil, err
}
return newMessage(c, raw), nil
}
func (c *Client) buttonCallback(ctx context.Context, channelID, messageID, buttonID, userID string, resp ButtonResponse) error {
url := c.messageURL(channelID, messageID) + "/buttons/" + buttonID + "/callback"
body := map[string]any{"userId": userID}
if resp.Content != "" {
body["content"] = resp.Content
}
if len(resp.Components) > 0 {
body["components"] = resp.Components
}
if resp.Title != "" {
body["title"] = resp.Title
}
if resp.ButtonLabel != "" {
body["buttonLabel"] = resp.ButtonLabel
}
return c.doJSON(ctx, http.MethodPost, url, body, nil, c.token)
}
func (c *Client) banMember(ctx context.Context, serverID, userID, reason string) error {
url := c.apiBase + "/servers/" + serverID + "/bans/" + userID
return c.doJSON(ctx, http.MethodPost, url, map[string]any{"reason": reason}, nil, c.token)
}
func (c *Client) unbanMember(ctx context.Context, serverID, userID string) error {
url := c.apiBase + "/servers/" + serverID + "/bans/" + userID
return c.doJSON(ctx, http.MethodDelete, url, nil, nil, c.token)
}
func (c *Client) kickMember(ctx context.Context, serverID, userID string) error {
url := c.apiBase + "/servers/" + serverID + "/members/" + userID + "/kick"
return c.doJSON(ctx, http.MethodDelete, url, nil, nil, c.token)
}