forked from acm-uic/calsync
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiscord.ts
185 lines (171 loc) · 4.92 KB
/
discord.ts
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import {
BaseChannel,
CreateEventParams,
CreateEventResponse,
DeleteEventParams,
DeleteEventResponse,
DiscordEvent,
GetDiscordEventsParams,
PatchEventParams,
PatchEventResponse,
} from "./interfaces.ts";
/** Discord API base URL. */
const DISCORD_API_BASE_URL = "https://discord.com/api/v10";
type DiscordFetchParams = {
endpoint: string;
method?: string;
// deno-lint-ignore no-explicit-any
body?: any;
headers?: Record<string, string>;
};
/**
* Discord Events API Client.
* Required Bot Permissions: MANAGE_EVENTS
*/
export class DiscordClient {
#guildId: string;
#botToken: string;
constructor({ guildId, botToken }: { guildId: string; botToken: string }) {
this.#guildId = guildId;
this.#botToken = botToken;
}
async #fetch({ endpoint, method, body, headers }: DiscordFetchParams): Promise<Response> {
const res = await fetch(`${DISCORD_API_BASE_URL}${endpoint}`, {
method,
body: JSON.stringify(body),
headers: {
Authorization: `Bot ${this.#botToken}`,
"Content-Type": "application/json",
...headers,
},
});
if (res.status === 429) {
const retryAfter = res.headers.get("x-ratelimit-reset-after");
if (retryAfter) {
await new Promise((resolve) => setTimeout(resolve, parseFloat(retryAfter) * 1000 + 1000));
return this.#fetch({ endpoint, method, body, headers });
} else {
throw new Error("Discord Response Error");
}
}
return res;
}
/**
* Get events on a Discord server.
*
* @throws Will throw error if HTTP request was not successful.
* @param params Used to generate query params for Discord API request.
* @returns Array of events if successful
*/
public async getEvents<O extends GetDiscordEventsParams>(
params: O,
): Promise<
O extends { withUserCount: "false" } ? Omit<DiscordEvent, "user_count">[] : DiscordEvent[]
> {
try {
const res = await this.#fetch({
endpoint: `/guilds/${this.#guildId}/scheduled-events?${(new URLSearchParams(params)).toString()}`,
});
const parsed = await res.json() as O extends { withUserCount: "false" } ? Omit<DiscordEvent, "user_count">[]
: DiscordEvent[];
return parsed;
} catch (e) {
console.error(
`Error getting events from discord`,
);
throw e;
}
}
/**
* Create event in the discord server.
* @throws Will throw error if HTTP request was not successful.
* @param params Event information
* @returns Event data if successful
*/
public async createEvent(
params: CreateEventParams,
): Promise<CreateEventResponse> {
const { eventData } = params;
try {
const res = await this.#fetch({
endpoint: `/guilds/${this.#guildId}/scheduled-events`,
body: eventData,
method: "POST",
});
const parsed = await res.json() as CreateEventResponse;
return parsed;
} catch (e) {
console.error(
`Error creating event in discord.`,
);
throw e;
}
}
/**
* Delete event in the discord server.
* @throws Will throw error if HTTP request was not successful.
* @param params Event ID to delete
* @returns Blank response if successful. Status 204.
*/
public async deleteEvent(
params: DeleteEventParams,
): Promise<DeleteEventResponse> {
const { id } = params;
try {
await this.#fetch({
endpoint: `/guilds/${this.#guildId}/scheduled-events/${id}`,
method: "DELETE",
});
return {};
} catch (e) {
console.error(
`Error deleting event in discord.`,
);
throw e;
}
}
/**
* Patch event in the discord server.
* @throws Will throw error if HTTP request was not successful.
* @param params Event ID to patch and updated event information
* @returns Event data if successful
*/
public async patchEvent(
params: PatchEventParams,
): Promise<PatchEventResponse> {
const { id, eventData } = params;
try {
const res = await this.#fetch({
endpoint: `/guilds/${this.#guildId}/scheduled-events/${id}`,
method: "PATCH",
body: eventData,
});
const parsed = await res.json() as PatchEventResponse;
return parsed;
} catch (e) {
console.error(
`Error patching event in discord.`,
);
throw e;
}
}
/**
* Get channels on a Discord server.
* @throws Will throw error if HTTP request was not successful.
* @returns Array of pruned channels (id, type) if successful
*/
public async getChannels(): Promise<BaseChannel[]> {
try {
const res = await this.#fetch({ endpoint: `/guilds/${this.#guildId}/channels` });
const parsed = await res.json() as BaseChannel[];
return parsed.map(
({ id, type, name }): BaseChannel => ({ id, type, name }),
);
} catch (e) {
console.error(
`Error getting channels from discord.`,
);
throw e;
}
}
}