diff --git a/src/errors/Messages.js b/src/errors/Messages.js index e0808b8..c4c8b54 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -197,6 +197,10 @@ const Messages = { INVALID_REMOTE_AUTH_URL: 'Invalid remote auth URL (https://discord.com/ra/{hash})', INVALID_URL: url => `Invalid URL: ${url}.\nMake sure you are using a valid URL (https://discord.com/oauth2/authorize?...)`, + + NITRO_REQUIRED: 'This feature is only available for Nitro users.', + NITRO_BOOST_REQUIRED: feature => `This feature (${feature}) is only available for Nitro Boost users.`, + ONLY_ME: 'This feature is only available for self.', }; for (const [name, message] of Object.entries(Messages)) register(name, message); diff --git a/src/managers/GuildMemberManager.js b/src/managers/GuildMemberManager.js index eaf2f04..7b329cd 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/managers/GuildMemberManager.js @@ -9,6 +9,7 @@ const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel'); const { GuildMember } = require('../structures/GuildMember'); const { Role } = require('../structures/Role'); const { Events, Opcodes } = require('../util/Constants'); +const DataResolver = require('../util/DataResolver'); const SnowflakeUtil = require('../util/SnowflakeUtil'); /** @@ -236,6 +237,9 @@ class GuildMemberManager extends CachedManager { * (if they are connected to voice), or `null` if you want to disconnect them from voice * @property {DateResolvable|null} [communicationDisabledUntil] The date or timestamp * for the member's communication to be disabled until. Provide `null` to enable communication again. + * @property {?(BufferResolvable|Base64Resolvable)} [avatar] The new guild avatar + * @property {?(BufferResolvable|Base64Resolvable)} [banner] The new guild banner + * @property {?string} [bio] The new guild about me */ /** @@ -268,11 +272,22 @@ class GuildMemberManager extends CachedManager { _data.communication_disabled_until = _data.communicationDisabledUntil && new Date(_data.communicationDisabledUntil).toISOString(); + // Avatar, banner, bio + if (typeof _data.avatar !== 'undefined') { + _data.avatar = await DataResolver.resolveImage(_data.avatar); + } + if (typeof _data.banner !== 'undefined') { + _data.banner = await DataResolver.resolveImage(_data.banner); + } + let endpoint = this.client.api.guilds(this.guild.id); if (id === this.client.user.id) { const keys = Object.keys(data); - if (keys.length === 1 && keys[0] === 'nick') endpoint = endpoint.members('@me'); - else endpoint = endpoint.members(id); + if (keys.length === 1 && ['nick', 'avatar', 'banner', 'bio'].includes(keys[0])) { + endpoint = endpoint.members('@me'); + } else { + endpoint = endpoint.members(id); + } } else { endpoint = endpoint.members(id); } diff --git a/src/structures/ClientUser.js b/src/structures/ClientUser.js index 949f404..61a2f0e 100644 --- a/src/structures/ClientUser.js +++ b/src/structures/ClientUser.js @@ -104,6 +104,8 @@ class ClientUser extends User { * @typedef {Object} ClientUserEditData * @property {string} [username] The new username * @property {?(BufferResolvable|Base64Resolvable)} [avatar] The new avatar + * @property {?(BufferResolvable|Base64Resolvable)} [banner] The new banner + * @property {?string} [bio] The new bio */ /** @@ -209,7 +211,7 @@ class ClientUser extends User { /** * Set Accent color * @param {ColorResolvable} color Color to set - * @returns {Promise} + * @returns {Promise} */ setAccentColor(color = null) { return this.edit({ accent_color: color ? Util.resolveColor(color) : null }); @@ -219,7 +221,7 @@ class ClientUser extends User { * Set discriminator * @param {User.discriminator} discriminator It is #1234 * @param {string} password The password of the account - * @returns {Promise} + * @returns {Promise} */ setDiscriminator(discriminator, password) { if (this.nitroType == 'NONE') throw new Error('You must be a Nitro User to change your discriminator.'); @@ -234,8 +236,8 @@ class ClientUser extends User { /** * Set About me - * @param {string} bio Bio to set - * @returns {Promise} + * @param {string | null} bio Bio to set + * @returns {Promise} */ setAboutMe(bio = null) { return this.edit({ @@ -247,7 +249,7 @@ class ClientUser extends User { * Change the email * @param {Email} email Email to change * @param {string} password Password of the account - * @returns {Promise} + * @returns {Promise} */ setEmail(email, password) { if (!password && !this.client.password) { @@ -263,7 +265,7 @@ class ClientUser extends User { * Set new password * @param {string} oldPassword Old password * @param {string} newPassword New password to set - * @returns {Promise} + * @returns {Promise} */ setPassword(oldPassword, newPassword) { if (!oldPassword && !this.client.password) { @@ -279,7 +281,7 @@ class ClientUser extends User { /** * Disable account * @param {string} password Password of the account - * @returns {Promise} + * @returns {Promise} */ async disableAccount(password) { if (!password && !this.client.password) { @@ -324,7 +326,7 @@ class ClientUser extends User { /** * Delete account. Warning: Cannot be changed once used! * @param {string} password Password of the account - * @returns {Promise} + * @returns {Promise} */ async deleteAccount(password) { if (!password && !this.client.password) { diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 16da298..57cd041 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -347,6 +347,51 @@ class GuildMember extends Base { return this.edit({ nick }, reason); } + /** + * Sets the guild avatar of the logged in client. + * @param {?(BufferResolvable|Base64Resolvable)} avatar The new avatar + * @returns {Promise} + */ + setAvatar(avatar) { + if (this.user.id !== this.client.user.id) { + throw new Error('ONLY_ME'); + } + if (this.client.user.nitroType !== 'NITRO_BOOST') { + throw new Error('NITRO_BOOST_REQUIRED', 'avatar'); + } + return this.edit({ avatar }); + } + + /** + * Sets the guild banner of the logged in client. + * @param {?(BufferResolvable|Base64Resolvable)} banner The new banner + * @returns {Promise} + */ + setBanner(banner) { + if (this.user.id !== this.client.user.id) { + throw new Error('ONLY_ME'); + } + if (this.client.user.nitroType !== 'NITRO_BOOST') { + throw new Error('NITRO_BOOST_REQUIRED', 'banner'); + } + return this.edit({ banner }); + } + + /** + * Set Guild About me + * @param {string | null} bio Bio to set + * @returns {Promise} + */ + setAboutMe(bio = null) { + if (this.user.id !== this.client.user.id) { + throw new Error('ONLY_ME'); + } + if (this.client.user.nitroType !== 'NITRO_BOOST') { + throw new Error('NITRO_BOOST_REQUIRED', 'bio'); + } + return this.edit({ bio }); + } + /** * Creates a DM channel between the client and this member. * @param {boolean} [force=false] Whether to skip the cache check and request the API diff --git a/src/structures/Invite.js b/src/structures/Invite.js index 4fe61d3..210cae5 100644 --- a/src/structures/Invite.js +++ b/src/structures/Invite.js @@ -342,7 +342,6 @@ class Invite extends Base { captcha_key: captcha, } : {}, - // Goodjob discord :) Bypass Phone Verification (not captcha .-.) headers: { 'X-Context-Properties': Buffer.from(JSON.stringify(dataHeader), 'utf8').toString('base64'), }, diff --git a/typings/index.d.ts b/typings/index.d.ts index add5d49..045d45b 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -900,7 +900,7 @@ export class ClientUser extends User { public setHypeSquad(type: HypeSquadType): Promise; public setAccentColor(color: ColorResolvable): Promise; public setDiscriminator(discriminator: string, password: string): Promise; - public setAboutMe(bio: string): Promise; + public setAboutMe(bio: string | null): Promise; public setEmail(email: string, password: string): Promise; public setPassword(oldPassword: string, newPassword: string): Promise; public disableAccount(password: string): Promise; @@ -1451,6 +1451,9 @@ export class GuildMember extends PartialTextBasedChannel(Base) { public kick(reason?: string): Promise; public permissionsIn(channel: GuildChannelResolvable): Readonly; public setNickname(nickname: string | null, reason?: string): Promise; + public setAvatar(avatar: BufferResolvable | Base64Resolvable | null): Promise; + public setBanner(banner: BufferResolvable | Base64Resolvable | null): Promise; + public setAboutMe(bio: string | null): Promise; public toJSON(): unknown; public toString(): MemberMention; public valueOf(): string; @@ -4938,6 +4941,8 @@ export interface ClientPresenceStatusData { export interface ClientUserEditData { username?: string; avatar?: BufferResolvable | Base64Resolvable | null; + banner?: BufferResolvable | Base64Resolvable | null; + bio?: string | null; } export interface CloseEvent { @@ -5582,6 +5587,9 @@ export interface GuildMemberEditData { deaf?: boolean; channel?: GuildVoiceChannelResolvable | null; communicationDisabledUntil?: DateResolvable | null; + avatar?: BufferResolvable | Base64Resolvable | null; + banner?: BufferResolvable | Base64Resolvable | null; + bio?: string | null; } export type GuildMemberResolvable = GuildMember | UserResolvable;