Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(GuildMember): add flags #9087

Merged
merged 2 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/discord.js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ exports.Colors = require('./util/Colors');
exports.DataResolver = require('./util/DataResolver');
exports.Events = require('./util/Events');
exports.Formatters = require('./util/Formatters');
exports.GuildMemberFlagsBitField = require('./util/GuildMemberFlagsBitField').GuildMemberFlagsBitField;
exports.IntentsBitField = require('./util/IntentsBitField');
exports.LimitedCollection = require('./util/LimitedCollection');
exports.MessageFlagsBitField = require('./util/MessageFlagsBitField');
Expand Down
6 changes: 6 additions & 0 deletions packages/discord.js/src/managers/GuildMemberManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel');
const { GuildMember } = require('../structures/GuildMember');
const { Role } = require('../structures/Role');
const Events = require('../util/Events');
const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField');
const Partials = require('../util/Partials');

/**
Expand Down Expand Up @@ -279,6 +280,7 @@ 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 {GuildMemberFlagsResolvable} [flags] The flags to set for the member
* @property {string} [reason] Reason for editing this user
*/

Expand Down Expand Up @@ -314,6 +316,10 @@ class GuildMemberManager extends CachedManager {
: options.communicationDisabledUntil;
}

if (typeof options.flags !== 'undefined') {
options.flags = GuildMemberFlagsBitField.resolve(options.flags);
}

let endpoint;
if (id === this.client.user.id) {
const keys = Object.keys(options);
Expand Down
22 changes: 22 additions & 0 deletions packages/discord.js/src/structures/GuildMember.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const VoiceState = require('./VoiceState');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { DiscordjsError, ErrorCodes } = require('../errors');
const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager');
const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField');
const PermissionsBitField = require('../util/PermissionsBitField');

/**
Expand Down Expand Up @@ -93,6 +94,16 @@ class GuildMember extends Base {
this.communicationDisabledUntilTimestamp =
data.communication_disabled_until && Date.parse(data.communication_disabled_until);
}

if ('flags' in data) {
/**
* The flags of this member
* @type {Readonly<GuildMemberFlagsBitField>}
*/
this.flags = new GuildMemberFlagsBitField(data.flags).freeze();
} else {
this.flags ??= new GuildMemberFlagsBitField().freeze();
}
}

_clone() {
Expand Down Expand Up @@ -314,6 +325,16 @@ class GuildMember extends Base {
return this.guild.members.edit(this, options);
}

/**
* Sets the flags for this member.
* @param {GuildMemberFlagsResolvable} flags The flags to set
* @param {string} [reason] Reason for setting the flags
* @returns {Promise<GuildMember>}
*/
setFlags(flags, reason) {
return this.edit({ flags, reason });
}

/**
* Sets the nickname for this member.
* @param {?string} nick The nickname for the guild member, or `null` if you want to reset their nickname
Expand Down Expand Up @@ -423,6 +444,7 @@ class GuildMember extends Base {
this.avatar === member.avatar &&
this.pending === member.pending &&
this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp &&
this.flags.bitfield === member.flags.bitfield &&
(this._roles === member._roles ||
(this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i])))
);
Expand Down
5 changes: 5 additions & 0 deletions packages/discord.js/src/util/APITypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildMFALevel}
*/

/**
* @external GuildMemberFlags
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildMemberFlags}
*/

/**
* @external GuildNSFWLevel
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildNSFWLevel}
Expand Down
41 changes: 41 additions & 0 deletions packages/discord.js/src/util/GuildMemberFlagsBitField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

const { GuildMemberFlags } = require('discord-api-types/v10');
const BitField = require('./BitField');

/**
* Data structure that makes it easy to interact with a {@link GuildMember#flags} bitfield.
* @extends {BitField}
*/
class GuildMemberFlagsBitField extends BitField {
/**
* Numeric guild guild member flags.
* @type {GuildMemberFlags}
* @memberof GuildMemberFlagsBitField
*/
static Flags = GuildMemberFlags;
}

/**
* @name GuildMemberFlagsBitField
* @kind constructor
* @memberof GuildMemberFlagsBitField
* @param {BitFieldResolvable} [bits=0] Bit(s) to read from
*/

/**
* Bitfield of the packed bits
* @type {number}
* @name GuildMemberFlagsBitField#bitfield
*/

/**
* Data that can be resolved to give a guild member flag bitfield. This can be:
* * A string (see {@link GuildMemberFlagsBitField.Flags})
* * A guild member flag
* * An instance of GuildMemberFlagsBitField
* * An Array of GuildMemberFlagsResolvable
* @typedef {string|number|GuildMemberFlagsBitField|GuildMemberFlagsResolvable[]} GuildMemberFlagsResolvable
*/

exports.GuildMemberFlagsBitField = GuildMemberFlagsBitField;
13 changes: 13 additions & 0 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ import {
ApplicationRoleConnectionMetadataType,
APIApplicationRoleConnectionMetadata,
ImageFormat,
GuildMemberFlags,
} from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
Expand Down Expand Up @@ -1474,6 +1475,15 @@ export class GuildEmoji extends BaseGuildEmoji {
public setName(name: string, reason?: string): Promise<GuildEmoji>;
}

export type GuildMemberFlagsString = keyof typeof GuildMemberFlags;

export type GuildMemberFlagsResolvable = BitFieldResolvable<GuildMemberFlagsString, number>;

export class GuildMemberFlagsBitField extends BitField<GuildMemberFlagsString> {
public static Flags: GuildMemberFlags;
public static resolve(bit?: BitFieldResolvable<GuildMemberFlagsString, GuildMemberFlags>): number;
}

export class GuildMember extends PartialTextBasedChannel(Base) {
private constructor(client: Client<true>, data: RawGuildMemberData, guild: Guild);
public avatar: string | null;
Expand All @@ -1487,6 +1497,7 @@ export class GuildMember extends PartialTextBasedChannel(Base) {
public pending: boolean;
public get communicationDisabledUntil(): Date | null;
public communicationDisabledUntilTimestamp: number | null;
public flags: Readonly<GuildMemberFlagsBitField>;
public get joinedAt(): Date | null;
public joinedTimestamp: number | null;
public get kickable(): boolean;
Expand Down Expand Up @@ -1516,6 +1527,7 @@ export class GuildMember extends PartialTextBasedChannel(Base) {
};
public kick(reason?: string): Promise<GuildMember>;
public permissionsIn(channel: GuildChannelResolvable): Readonly<PermissionsBitField>;
public setFlags(flags: GuildMemberFlagsResolvable, reason?: string): Promise<GuildMember>;
public setNickname(nickname: string | null, reason?: string): Promise<GuildMember>;
public toJSON(): unknown;
public toString(): UserMention;
Expand Down Expand Up @@ -5482,6 +5494,7 @@ export interface GuildMemberEditOptions {
deaf?: boolean;
channel?: GuildVoiceChannelResolvable | null;
communicationDisabledUntil?: DateResolvable | null;
flags?: GuildMemberFlagsResolvable;
reason?: string;
}

Expand Down
3 changes: 3 additions & 0 deletions packages/discord.js/typings/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ import {
AutoModerationRuleManager,
PrivateThreadChannel,
PublicThreadChannel,
GuildMemberFlagsBitField,
} from '.';
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
Expand Down Expand Up @@ -2143,3 +2144,5 @@ client.on('guildAuditLogEntryCreate', (auditLogEntry, guild) => {
expectType<GuildAuditLogsEntry>(auditLogEntry);
expectType<Guild>(guild);
});

expectType<Readonly<GuildMemberFlagsBitField>>(guildMember.flags);