feat(Guils): widgets, vanityURL, preview (#76)

closes #64
This commit is contained in:
Marcos Susaña 2022-07-20 15:57:10 -04:00 committed by GitHub
parent c50e8d72c8
commit 491889849a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 264 additions and 46 deletions

View File

@ -450,6 +450,24 @@ export function GUILD_WIDGET(guildId: Snowflake, options: GetWidget = { get: 'se
} }
/** @link https://discord.com/developers/docs/resources/guild#get-guild-voice-regions */ /** @link https://discord.com/developers/docs/resources/guild#get-guild-voice-regions */
export function GUILD_VOICE_REGIONS(guildId: string): string { export function GUILD_VOICE_REGIONS(guildId: Snowflake): string {
return `/guilds/${guildId}/regions`; return `/guilds/${guildId}/regions`;
} }
/**
* @link https://discord.com/developers/docs/resources/guild#get-guild-vanity-url
* @param guildId The guild
* @returns Get vanity URL
*/
export function GUILD_VANITY(guildId: Snowflake): string {
return `/guilds/${guildId}/vanity-url`;
}
/**
* @link https://discord.com/developers/docs/resources/guild#get-guild-preview
* @param guildId The guild
* @returns Get guild preview url
*/
export function GUILD_PREVIEW(guildId: Snowflake): string {
return `/guilds/${guildId}/preview`;
}

View File

@ -0,0 +1,41 @@
import { DiscordGuildWidget } from "../../api-types/discord.ts";
import { Session } from "../Session.ts";
import { Snowflake } from "../Snowflake.ts";
import { Model } from "./Base.ts";
import { PartialChannel } from './channels.ts';
export interface WidgetMember {
id?: string;
username: string;
avatar?: string | null;
status: string;
avatarURL: string;
}
export class Widget implements Model {
constructor(session: Session, data: DiscordGuildWidget) {
this.session = session;
this.id = data.id;
this.name = data.name;
this.instantInvite = data.instant_invite;
this.channels = data.channels;
this.members = data.members.map(x => {
return {
id: x.id,
username: x.username,
avatar: x.avatar,
status: x.status,
avatarURL: x.avatar_url
}
});
this.presenceCount = data.presence_count;
}
session: Session;
id: Snowflake;
name: string;
instantInvite?: string;
channels: PartialChannel[];
members: WidgetMember[];
presenceCount: number;
}

View File

@ -868,6 +868,12 @@ export type ChannelWithMessages =
export type ChannelWithMessagesInGuild = Exclude<ChannelWithMessages, DMChannel>; export type ChannelWithMessagesInGuild = Exclude<ChannelWithMessages, DMChannel>;
export type PartialChannel = {
id: string;
name: string;
position: number;
};
export class ChannelFactory { export class ChannelFactory {
static fromGuildChannel(session: Session, channel: DiscordChannel): ChannelInGuild { static fromGuildChannel(session: Session, channel: DiscordChannel): ChannelInGuild {
switch (channel.type) { switch (channel.type) {

View File

@ -3,8 +3,12 @@ import type { Session } from '../Session.ts';
import type { import type {
ChannelTypes, ChannelTypes,
DefaultMessageNotificationLevels, DefaultMessageNotificationLevels,
DiscordBan,
DiscordEmoji, DiscordEmoji,
DiscordGuild, DiscordGuild,
DiscordGuildWidget,
DiscordGuildWidgetSettings,
DiscordInvite,
DiscordInviteMetadata, DiscordInviteMetadata,
DiscordListActiveThreads, DiscordListActiveThreads,
DiscordMemberWithUser, DiscordMemberWithUser,
@ -17,6 +21,7 @@ import type {
SystemChannelFlags, SystemChannelFlags,
VerificationLevels, VerificationLevels,
VideoQualityModes, VideoQualityModes,
DiscordGuildPreview
} from '../../discordeno/mod.ts'; } from '../../discordeno/mod.ts';
import type { ImageFormat, ImageSize } from '../Util.ts'; import type { ImageFormat, ImageSize } from '../Util.ts';
import { GuildFeatures, PremiumTiers } from '../../discordeno/mod.ts'; import { GuildFeatures, PremiumTiers } from '../../discordeno/mod.ts';
@ -31,6 +36,9 @@ import Role from './Role.ts';
import GuildEmoji from './GuildEmoji.ts'; import GuildEmoji from './GuildEmoji.ts';
import { urlToBase64 } from '../util/urlToBase64.ts'; import { urlToBase64 } from '../util/urlToBase64.ts';
import Invite from './Invite.ts'; import Invite from './Invite.ts';
import User from './User.ts';
import { Widget } from './Widget.ts';
import Sticker from './Sticker.ts';
/** BaseGuild */ /** BaseGuild */
/** /**
@ -56,13 +64,13 @@ export abstract class BaseGuild implements Model {
/** /**
* Icon hash. Discord uses ids and hashes to render images in the client. * Icon hash. Discord uses ids and hashes to render images in the client.
* @link https://discord.com/developers/docs/reference#image-formatting * @link https://discord.com/developers/docs/reference#image-formatting
* */ */
iconHash?: bigint; iconHash?: bigint;
/** /**
* Enabled guild features (animated banner, news, auto moderation, etc). * Enabled guild features (animated banner, news, auto moderation, etc).
* @see {@link GuildFeatures} * @see {@link GuildFeatures}
* @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features * @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features
* */ */
features: GuildFeatures[]; features: GuildFeatures[];
/** createdTimestamp gets the current guild timestamp. */ /** createdTimestamp gets the current guild timestamp. */
@ -78,7 +86,7 @@ export abstract class BaseGuild implements Model {
/** /**
* If the guild features includes partnered. * If the guild features includes partnered.
* @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features * @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features
* */ */
get partnered(): boolean { get partnered(): boolean {
return this.features.includes(GuildFeatures.Partnered); return this.features.includes(GuildFeatures.Partnered);
} }
@ -86,7 +94,7 @@ export abstract class BaseGuild implements Model {
/** /**
* If the guild is verified. * If the guild is verified.
* @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features * @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features
* */ */
get verified(): boolean { get verified(): boolean {
return this.features.includes(GuildFeatures.Verified); return this.features.includes(GuildFeatures.Verified);
} }
@ -94,7 +102,7 @@ export abstract class BaseGuild implements Model {
/** /**
* iconURL gets the current guild icon. * iconURL gets the current guild icon.
* @link https://discord.com/developers/docs/reference#image-formatting * @link https://discord.com/developers/docs/reference#image-formatting
* */ */
iconURL(options: { size?: ImageSize; format?: ImageFormat } = { size: 128 }): string | void { iconURL(options: { size?: ImageSize; format?: ImageFormat } = { size: 128 }): string | void {
if (this.iconHash) { if (this.iconHash) {
return Util.formatImageURL( return Util.formatImageURL(
@ -207,6 +215,47 @@ export class InviteGuild extends AnonymousGuild implements Model {
welcomeScreen?: WelcomeScreen; welcomeScreen?: WelcomeScreen;
} }
/**
* Represent Discord Guild Preview Object
* @link https://discord.com/developers/docs/resources/guild#guild-preview-object
*/
export class GuildPreview implements Model {
constructor(session: Session, data: DiscordGuildPreview) {
this.session = session;
this.id = data.id;
this.name = data.name;
this.description = data.description ?? undefined;
this.iconHash = data.icon ? Util.iconHashToBigInt(data.icon) : undefined;
this.splashHash = data.splash ? Util.iconHashToBigInt(data.splash) : undefined;
this.discoverySplashHash = data.discovery_splash ? Util.iconHashToBigInt(data.discovery_splash) : undefined;
this.emojis = data.emojis.map(x => new GuildEmoji(this.session, x, this.id));
this.features = data.features;
this.approximateMemberCount = data.approximate_member_count;
this.approximatePresenceCount = data.approximate_presence_count;
this.stickers = data.stickers.map(x => new Sticker(this.session, x));
}
session: Session;
/** guild id */
id: Snowflake;
/** guild name (2-100 characters) */
name: string;
iconHash?: bigint;
splashHash?: bigint;
discoverySplashHash?: bigint;
/** custom guild emojis */
emojis: GuildEmoji[];
/** enabled guild features */
features: GuildFeatures[];
/** approximate number of members in this guild */
approximateMemberCount: number;
/** approximate number of online members in this guild */
approximatePresenceCount: number;
/** the description for the guild */
description?: string;
/** custom guild stickers */
stickers: Sticker[];
}
/** Guild */ /** Guild */
export interface CreateRole { export interface CreateRole {
name?: string; name?: string;
@ -245,6 +294,27 @@ export interface CreateGuildBan {
reason?: string; reason?: string;
} }
/**
* @link https://discord.com/developers/docs/resources/guild#ban-object
*/
export interface GuildBan {
reason?: string;
user: User;
}
/**
* @link https://discord.com/developers/docs/resources/guild#guild-widget-settings-object-guild-widget-settings-structure
*/
export interface GuildWidgetSettings {
enabled: boolean;
channelId?: Snowflake;
}
export interface PartialVanityURL {
code: string;
uses: number;
}
/** /**
* @link https://discord.com/developers/docs/resources/guild#modify-guild-member * @link https://discord.com/developers/docs/resources/guild#modify-guild-member
*/ */
@ -386,7 +456,6 @@ export class Guild extends BaseGuild implements Model {
this.defaultMessageNotificationLevel = data.default_message_notifications; this.defaultMessageNotificationLevel = data.default_message_notifications;
this.explicitContentFilterLevel = data.explicit_content_filter; this.explicitContentFilterLevel = data.explicit_content_filter;
this.premiumTier = data.premium_tier; this.premiumTier = data.premium_tier;
this.members = new Map( this.members = new Map(
data.members?.map((member) => [data.id, new Member(session, { ...member, user: member.user! }, data.id)]), data.members?.map((member) => [data.id, new Member(session, { ...member, user: member.user! }, data.id)]),
); );
@ -502,7 +571,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* editBotNickname edits the bot's nickname in the guild. * edits the bot's nickname in the guild.
* 'null' would reset the nickname. * 'null' would reset the nickname.
*/ */
async editBotNickname(options: { nick: string | null; reason?: string }): Promise<(string | undefined)> { async editBotNickname(options: { nick: string | null; reason?: string }): Promise<(string | undefined)> {
@ -517,7 +586,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* createEmoji creates an emoji in the guild. * creates an emoji in the guild.
* @see {@link CreateGuildEmoji} * @see {@link CreateGuildEmoji}
* @see {@link GuildEmoji} * @see {@link GuildEmoji}
* @param options The options to create a emoji. * @param options The options to create a emoji.
@ -539,7 +608,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* deleteEmoji deletes an emoji from the guild. * deletes an emoji from the guild.
* @param id - The id of the emoji to delete. * @param id - The id of the emoji to delete.
* @param reason - The reason for deleting the emoji. * @param reason - The reason for deleting the emoji.
*/ */
@ -553,7 +622,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* editEmoji edits an emoji in the guild. * edits an emoji in the guild.
* @see {@link ModifyGuildEmoji} * @see {@link ModifyGuildEmoji}
* @see {@link GuildEmoji} * @see {@link GuildEmoji}
* @param id - The id of the emoji to edit. * @param id - The id of the emoji to edit.
@ -572,7 +641,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* createRole creates a role in the guild. * creates a role in the guild.
* @see {@link CreateRole} * @see {@link CreateRole}
* @see {@link Role} * @see {@link Role}
* @param options - Options to create a new role. * @param options - Options to create a new role.
@ -606,15 +675,15 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* deleteRole deletes a role from the guild. * deletes a role from the guild.
* @param roleId - The id of the role to delete. * @param roleId - The id of the role to delete.
* */ */
async deleteRole(roleId: Snowflake): Promise<void> { async deleteRole(roleId: Snowflake): Promise<void> {
await this.session.rest.runMethod<undefined>(this.session.rest, 'DELETE', Routes.GUILD_ROLE(this.id, roleId)); await this.session.rest.runMethod<undefined>(this.session.rest, 'DELETE', Routes.GUILD_ROLE(this.id, roleId));
} }
/** /**
* editRole edits a role in the guild. * edits a role in the guild.
* @see {@link ModifyGuildRole} * @see {@link ModifyGuildRole}
* @see {@link Role} * @see {@link Role}
* @param roleId - The id of the role to edit. * @param roleId - The id of the role to edit.
@ -637,7 +706,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* addRole adds a role to a user in the guild. * adds a role to a user in the guild.
* @param memberId - The id of the member to add a role to. * @param memberId - The id of the member to add a role to.
* @param roleId - The id of the role to add. * @param roleId - The id of the role to add.
* @param reason - The reason for adding the role to the member. * @param reason - The reason for adding the role to the member.
@ -652,7 +721,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* removeRole removes a role from a user in the guild. * removes a role from a user in the guild.
* @param memberId - The id of the member to remove a role from. * @param memberId - The id of the member to remove a role from.
* @param roleId - The id of the role to remove. * @param roleId - The id of the role to remove.
* @param reason - The reason for removing the role from the member. * @param reason - The reason for removing the role from the member.
@ -667,7 +736,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* Returns the roles moved. * the roles moved.
* @see {@link ModifyRolePositions} * @see {@link ModifyRolePositions}
* @see {@link Role} * @see {@link Role}
* @param options - Options to modify the roles. * @param options - Options to modify the roles.
@ -684,7 +753,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* deleteInvite deletes an invite from the guild. * deletes an invite from the guild.
* @param inviteCode - The invite code to get the invite for. * @param inviteCode - The invite code to get the invite for.
*/ */
async deleteInvite(inviteCode: string): Promise<void> { async deleteInvite(inviteCode: string): Promise<void> {
@ -697,7 +766,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* fetchInvite gets an invite from the guild. * gets an invite from the guild.
* @see {@link Routes.GetInvite} * @see {@link Routes.GetInvite}
* @see {@link Invite} * @see {@link Invite}
* @param inviteCode - The invite code to get the invite for. * @param inviteCode - The invite code to get the invite for.
@ -715,7 +784,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* fetchInvites gets all invites from the guild. * gets all invites from the guild.
* @see {@link Invite} * @see {@link Invite}
* @returns A promise that resolves to the guild's invites. * @returns A promise that resolves to the guild's invites.
*/ */
@ -730,7 +799,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* banMember bans a member from the guild. * bans a member from the guild.
* @see {@link CreateGuildBan} * @see {@link CreateGuildBan}
* @param memberId - The id of the member to ban. * @param memberId - The id of the member to ban.
* @param options - Options to ban the member. * @param options - Options to ban the member.
@ -750,7 +819,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* kickMember kicks a member from the guild. * kicks a member from the guild.
* @param memberId - The id of the member to kick. * @param memberId - The id of the member to kick.
* @param reason - The reason for kicking the member. * @param reason - The reason for kicking the member.
*/ */
@ -764,7 +833,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* unbanMember unbans a member from the guild. * unbans a member from the guild.
* @param memberId - The id of the member to get. * @param memberId - The id of the member to get.
*/ */
async unbanMember(memberId: Snowflake): Promise<void> { async unbanMember(memberId: Snowflake): Promise<void> {
@ -776,7 +845,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* editMember edits a member in the guild. * edits a member in the guild.
* @see {@link ModifyGuildMember} * @see {@link ModifyGuildMember}
* @see {@link Member} * @see {@link Member}
* @param memberId - The id of the member to get. * @param memberId - The id of the member to get.
@ -804,7 +873,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* pruneMembers prunes members from the guild. * prunes members from the guild.
* @see {@link BeginGuildPrune} * @see {@link BeginGuildPrune}
* @param options - Options to prune the members. * @param options - Options to prune the members.
* @returns A promise that resolves to the number of members pruned. * @returns A promise that resolves to the number of members pruned.
@ -825,7 +894,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* getPruneCount gets the number of members that would be pruned. * gets the number of members that would be pruned.
* @returns A promise that resolves to the number of members that would be pruned. * @returns A promise that resolves to the number of members that would be pruned.
*/ */
async getPruneCount(): Promise<number> { async getPruneCount(): Promise<number> {
@ -839,7 +908,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* getActiveThreads gets the active threads in the guild. * gets the active threads in the guild.
* @see {@link ReturnThreadsArchive} * @see {@link ReturnThreadsArchive}
* @returns Promise resolving a ReturnThreadsArchive without hasMore property. * @returns Promise resolving a ReturnThreadsArchive without hasMore property.
*/ */
@ -933,7 +1002,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* setSplash sets a new splash for the guild. Same as Guild.edit({..., splash: 'splashURL'}) * sets a new splash for the guild. Same as Guild.edit({..., splash: 'splashURL'})
* @see {@link Guild} * @see {@link Guild}
*/ */
setSplash(splashURL: string): Promise<Guild> { setSplash(splashURL: string): Promise<Guild> {
@ -941,7 +1010,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* setBanner sets a new banner for the guild. Same as Guild.edit({..., banner: 'bannerURL'}) * sets a new banner for the guild. Same as Guild.edit({..., banner: 'bannerURL'})
* @see {@link Guild} * @see {@link Guild}
*/ */
setBanner(bannerURL: string): Promise<Guild> { setBanner(bannerURL: string): Promise<Guild> {
@ -979,7 +1048,8 @@ export class Guild extends BaseGuild implements Model {
splash: 'splashURL' in options splash: 'splashURL' in options
? options.splashURL && urlToBase64(options.splashURL) ? options.splashURL && urlToBase64(options.splashURL)
: options.iconHash && Util.iconBigintToHash(options.iconHash), : options.iconHash && Util.iconBigintToHash(options.iconHash),
banner: 'bannerURL' in options ? options.bannerURL && urlToBase64(options.bannerURL) banner: 'bannerURL' in options
? options.bannerURL && urlToBase64(options.bannerURL)
: options.bannerHash && Util.iconBigintToHash(options.bannerHash), : options.bannerHash && Util.iconBigintToHash(options.bannerHash),
discovery_splash: 'discoverySplashURL' in options discovery_splash: 'discoverySplashURL' in options
? options.discoverySplashURL && urlToBase64(options.discoverySplashURL) ? options.discoverySplashURL && urlToBase64(options.discoverySplashURL)
@ -997,7 +1067,7 @@ export class Guild extends BaseGuild implements Model {
} }
/** /**
* fetchVoiceRegions gets the voice regions available for the guild. * gets the voice regions available for the guild.
* @see {@link DiscordVoiceRegion} * @see {@link DiscordVoiceRegion}
* @returns Promise that resolves to an array of voice regions. * @returns Promise that resolves to an array of voice regions.
*/ */
@ -1006,8 +1076,91 @@ export class Guild extends BaseGuild implements Model {
this.session.rest, this.session.rest,
'GET', 'GET',
Routes.GUILD_VOICE_REGIONS(this.id), Routes.GUILD_VOICE_REGIONS(this.id),
) );
} }
/**
* Fetches user ban in the guild
* @param userId The user id
* @returns Resolves Discord Ban
*/
async fetchBan(userId: Snowflake): Promise<GuildBan> {
const ban = await this.session.rest.runMethod<DiscordBan>(
this.session.rest,
'GET',
Routes.GUILD_BAN(this.id, userId),
);
return { reason: ban.reason ?? undefined, user: new User(this.session, ban.user) };
}
/**
* Fetches bans in the guild
* @param options
* @returns Resolve with list of bans
*/
async fetchBans(options?: Routes.GetBans): Promise<GuildBan[]> {
const bans = await this.session.rest.runMethod<DiscordBan[]>(
this.session.rest,
'GET',
Routes.GUILD_BANS(this.id, options),
);
return bans.map((x) => {
return { reason: x.reason ?? undefined, user: new User(this.session, x.user) };
});
}
/**
* Fetches settings for {@link Widget} in the guild
* @returns Resolves with the settings
*/
async fetchWidgetSettings(): Promise<GuildWidgetSettings> {
const widget = await this.session.rest.runMethod<DiscordGuildWidgetSettings>(
this.session.rest,
'GET',
Routes.GUILD_WIDGET(this.id),
);
return {
enabled: !!widget.enabled,
channelId: widget.channel_id ?? undefined,
};
}
/**
* Fetches widget in the guild
* @returns Resolves with the Widget
*/
async fetchWidget(): Promise<Widget> {
const widget = await this.session.rest.runMethod<DiscordGuildWidget>(
this.session.rest,
'GET',
Routes.GUILD_WIDGET(this.id, { get: 'json' }),
);
return new Widget(this.session, widget);
}
/**
* Fetches vanity url invite
* @see {@link Invite}
* @returns Resolves a Invite
*/
async fetchVanityURL(): Promise<Partial<Invite>> {
const vanity = await this.session.rest.runMethod<DiscordInvite>(
this.session.rest,
'GET',
Routes.GUILD_VANITY(this.id),
);
return new Invite(this.session, vanity);
}
/**
* Fetches preview of the guild
* @returns Resolves a Guild Preview object
*/
async fetchGuildPreview(): Promise<GuildPreview> {
const preview = await this.session.rest.runMethod<DiscordGuildPreview>(this.session.rest, 'GET', Routes.GUILD_PREVIEW(this.id));
return new GuildPreview(this.session, preview);
}
} }
export default Guild; export default Guild;