feat: members

This commit is contained in:
Yuzu 2022-06-23 18:21:33 -05:00
parent f247669902
commit bba3ded08c
7 changed files with 164 additions and 15 deletions

111
structures/Member.ts Normal file
View File

@ -0,0 +1,111 @@
import type { Model } from "./Base.ts";
import type { Snowflake } from "../util/Snowflake.ts";
import type { Session } from "../session/Session.ts";
import type { DiscordMember, MakeRequired } from "../vendor/external.ts";
import type { ImageFormat, ImageSize } from "../util/shared/images.ts";
import { iconBigintToHash, iconHashToBigInt } from "../util/hash.ts";
import { Routes } from "../util/mod.ts";
import { User } from "./User.ts";
/**
* @link https://discord.com/developers/docs/resources/guild#create-guild-ban
* */
export interface CreateGuildBan {
/** Number of days to delete messages for (0-7) */
deleteMessageDays?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
/** Reason for the ban */
reason?: string;
}
/**
* Represents a guild member
* TODO: add a `guild` property somehow
* @link https://discord.com/developers/docs/resources/guild#guild-member-object
* */
export class Member implements Model {
constructor(session: Session, data: MakeRequired<DiscordMember, "user">) {
this.session = session;
this.user = new User(session, data.user);
this.avatarHash = data.avatar ? iconHashToBigInt(data.avatar) : undefined;
this.nickname = data.nick ? data.nick : undefined;
this.joinedTimestamp = Number.parseInt(data.joined_at);
this.roles = data.roles;
this.deaf = !!data.deaf;
this.mute = !!data.mute;
this.pending = !!data.pending;
this.communicationDisabledUntilTimestamp = data.communication_disabled_until ? Number.parseInt(data.communication_disabled_until) : undefined;
}
readonly session: Session;
user: User;
avatarHash?: bigint;
nickname?: string;
joinedTimestamp: number;
roles: Snowflake[];
deaf: boolean;
mute: boolean;
pending: boolean;
communicationDisabledUntilTimestamp?: number;
/** shorthand to User.id */
get id(): Snowflake {
return this.user.id;
}
get nicknameOrUsername() {
return this.nickname ?? this.user.username;
}
get joinedAt() {
return new Date(this.joinedTimestamp);
}
/**
* Bans the member
* */
async ban(guildId: Snowflake, options: CreateGuildBan): Promise<Member> {
await this.session.rest.runMethod<undefined>(
this.session.rest,
"PUT",
Routes.GUILD_BAN(guildId, this.id),
options ? {
delete_message_days: options.deleteMessageDays,
reason: options.reason
} : {}
);
return this;
}
/**
* Kicks the member
* */
async kick(guildId: Snowflake, { reason }: { reason?: string }): Promise<Member> {
await this.session.rest.runMethod<undefined>(
this.session.rest,
"DELETE",
Routes.GUILD_MEMBER(guildId, this.id),
{ reason }
);
return this;
}
/** gets the user's avatar */
avatarUrl(options: { format?: ImageFormat; size?: ImageSize } = { size: 128 }) {
let url: string;
if (!this.avatarHash) {
url = Routes.USER_DEFAULT_AVATAR(Number(this.user.discriminator) % 5);
} else {
url = Routes.USER_AVATAR(this.id, iconBigintToHash(this.avatarHash));
}
return `${url}.${options.format ?? (url.includes("/a_") ? "gif" : "jpg")}?size=${options.size}`;
}
toString() {
return `<@!${this.user.id}>`;
}
}

View File

@ -3,6 +3,7 @@ import type { Snowflake } from "../util/Snowflake.ts";
import type { Session } from "../session/mod.ts"; import type { Session } from "../session/mod.ts";
import type { AllowedMentionsTypes, DiscordMessage } from "../vendor/external.ts"; import type { AllowedMentionsTypes, DiscordMessage } from "../vendor/external.ts";
import { User } from "./User.ts"; import { User } from "./User.ts";
import { Member } from "./Member.ts";
import { Attachment } from "./Attachment.ts"; import { Attachment } from "./Attachment.ts";
import { MessageFlags, Routes } from "../util/mod.ts"; import { MessageFlags, Routes } from "../util/mod.ts";
@ -52,6 +53,12 @@ export class Message implements Model {
this.content = data.content!; this.content = data.content!;
this.attachments = data.attachments.map((attachment) => new Attachment(session, attachment)); this.attachments = data.attachments.map((attachment) => new Attachment(session, attachment));
// user is always null on MessageCreate and its replaced with author
this.member = data.member ? new Member(session, {
...data.member,
user: data.author,
}) : undefined;
} }
readonly session: Session; readonly session: Session;
@ -66,6 +73,7 @@ export class Message implements Model {
content: string; content: string;
attachments: Attachment[]; attachments: Attachment[];
member?: Member;
get url() { get url() {
return `https://discord.com/channels/${this.guildId ?? "@me"}/${this.channelId}/${this.id}`; return `https://discord.com/channels/${this.guildId ?? "@me"}/${this.channelId}/${this.id}`;

View File

@ -2,19 +2,10 @@ import type { Model } from "./Base.ts";
import type { Snowflake } from "../util/Snowflake.ts"; import type { Snowflake } from "../util/Snowflake.ts";
import type { Session } from "../session/mod.ts"; import type { Session } from "../session/mod.ts";
import type { DiscordUser } from "../vendor/external.ts"; import type { DiscordUser } from "../vendor/external.ts";
import type { ImageFormat, ImageSize } from "../util/shared/images.ts";
import { iconBigintToHash, iconHashToBigInt } from "../util/hash.ts"; import { iconBigintToHash, iconHashToBigInt } from "../util/hash.ts";
import { Routes } from "../util/mod.ts"; import { Routes } from "../util/mod.ts";
/**
* @link https://discord.com/developers/docs/reference#image-formatting
*/
export type ImageFormat = "jpg" | "jpeg" | "png" | "webp" | "gif" | "json";
/**
* @link https://discord.com/developers/docs/reference#image-formatting
*/
export type ImageSize = 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096;
/** /**
* Represents a user * Represents a user
* @link https://discord.com/developers/docs/resources/user#user-object * @link https://discord.com/developers/docs/resources/user#user-object

View File

@ -12,7 +12,7 @@ session.on("ready", (_shardId, payload) => {
}); });
session.on("messageCreate", (message) => { session.on("messageCreate", (message) => {
if (message.content === "!ping") { if (message.content.startsWith("!ping")) {
message.reply({ content: "pong!" }); message.reply({ content: "pong!" });
} }
}); });

View File

@ -31,10 +31,10 @@ export function CHANNEL_MESSAGES(channelId: Snowflake, options?: GetMessagesOpti
let url = `/channels/${channelId}/messages?`; let url = `/channels/${channelId}/messages?`;
if (options) { if (options) {
if ("after" in options && options.after) url += `after=${options.after}`; if (options.after) url += `after=${options.after}`;
if ("before" in options && options.before) url += `&before=${options.before}`; if (options.before) url += `&before=${options.before}`;
if ("around" in options && options.around) url += `&around=${options.around}`; if (options.around) url += `&around=${options.around}`;
if ("limit" in options && options.limit) url += `&limit=${options.limit}`; if (options.limit) url += `&limit=${options.limit}`;
} }
return url; return url;
@ -44,3 +44,32 @@ export function CHANNEL_MESSAGES(channelId: Snowflake, options?: GetMessagesOpti
export function CHANNEL_MESSAGE(channelId: Snowflake, messageId: Snowflake) { export function CHANNEL_MESSAGE(channelId: Snowflake, messageId: Snowflake) {
return `/channels/${channelId}/messages/${messageId}`; return `/channels/${channelId}/messages/${messageId}`;
} }
/** used to kick members */
export function GUILD_MEMBER(guildId: Snowflake, userId: Snowflake) {
return `/guilds/${guildId}/members/${userId}`;
}
/** used to ban members */
export function GUILD_BAN(guildId: Snowflake, userId: Snowflake) {
return `/guilds/${guildId}/bans/${userId}`;
}
export interface GetBans {
limit?: number;
before?: Snowflake;
after?: Snowflake;
}
/** used to unban members */
export function GUILD_BANS(guildId: Snowflake, options?: GetBans) {
let url = `/guilds/${guildId}/bans?`;
if (options) {
if (options.limit) url += `limit=${options.limit}`;
if (options.after) url += `&after=${options.after}`;
if (options.before) url += `&before=${options.before}`;
}
return url;
}

View File

@ -2,4 +2,5 @@ export * from "./EventEmmiter.ts";
export * from "./Snowflake.ts"; export * from "./Snowflake.ts";
export * from "./hash.ts"; export * from "./hash.ts";
export * from "./shared/flags.ts"; export * from "./shared/flags.ts";
export * from "./shared/images.ts";
export * as Routes from "./Routes.ts"; export * as Routes from "./Routes.ts";

9
util/shared/images.ts Normal file
View File

@ -0,0 +1,9 @@
/**
* @link https://discord.com/developers/docs/reference#image-formatting
*/
export type ImageFormat = "jpg" | "jpeg" | "png" | "webp" | "gif" | "json";
/**
* @link https://discord.com/developers/docs/reference#image-formatting
*/
export type ImageSize = 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096;