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(Guild): add api methods for membership screening #5144

Closed
wants to merge 13 commits into from
86 changes: 86 additions & 0 deletions src/structures/Guild.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ class Guild extends Base {
* * VERIFIED
* * VIP_REGIONS
* * WELCOME_SCREEN_ENABLED
* * MEMBER_VERIFICATION_GATE_ENABLED
* * PREVIEW_ENABLED
ckohen marked this conversation as resolved.
Show resolved Hide resolved
* @typedef {string} Features
*/

Expand Down Expand Up @@ -484,6 +486,15 @@ class Guild extends Base {
return new Date(this.joinedTimestamp);
}

/**
* Whether Membership Screening is enabled on this guild
* @type {boolean}
* @readonly
*/
get membershipScreeningEnabled() {
return this.features.includes('MEMBER_VERIFICATION_GATE_ENABLED');
}

ckohen marked this conversation as resolved.
Show resolved Hide resolved
/**
* If this guild is partnered
* @type {boolean}
Expand Down Expand Up @@ -959,6 +970,49 @@ class Guild extends Base {
.then(data => GuildAuditLogs.build(this, data));
}

/**
* Data for a field in Membership Screening
* @typedef {Object} GuildMembershipScreeningField
* @property {MembershipScreeningType} fieldType The type of the field
* @property {string} label The title of the field
* @property {string[]} [values] The list of values in the field
* @property {boolean} required Whether the user has to fill out this field
*/

/**
* Data for the Guild Membership Screening object
* @typedef {Object} GuildMembershipScreening
* @property {boolean} enabled Whether membership screening is enabled
* @property {string} description The server description shown in the membership screening form
* @property {GuildMembershipScreeningField[]} formFields The steps in the membership screening form
*/

/**
* Fetches the guild Membership Screening data.
* @returns {Promise<GuildMembershipScreening>}
* @example
* // Fetches the guild membership screening options
* guild.fetchMembershipScreening()
* .then(memberScreen => console.log(`Membership Screening is ${memberScreen.enabled ? 'enabled' : 'disabled'}`))
* .catch(console.error);
*/
ckohen marked this conversation as resolved.
Show resolved Hide resolved
async fetchMembershipScreening() {
if (!this.features.includes('COMMUNITY')) {
throw new Error('COMMUNITY');
}
ckohen marked this conversation as resolved.
Show resolved Hide resolved
const data = await this.client.api.guilds(this.id, 'member-verification').get();
return {
enabled: this.membershipScreeningEnabled,
description: data.description,
formFields: data.form_fields.map(field => ({
fieldType: field.field_type,
label: field.label,
values: field.values,
required: field.required,
})),
};
}

/**
* Adds a user to the guild using OAuth2. Requires the `CREATE_INSTANT_INVITE` permission.
* @param {UserResolvable} user User to add to the guild
Expand Down Expand Up @@ -1422,6 +1476,38 @@ class Guild extends Base {
.then(() => this);
}

/**
* Edits the guild's membership screening form.
* @param {Partial<GuildMembershipScreening>} memberScreen The membership screening data for the guild
ckohen marked this conversation as resolved.
Show resolved Hide resolved
* @returns {Promise<GuildMembershipScreening>}
*/
async setMembershipScreening(memberScreen) {
if (!this.features.includes('COMMUNITY')) {
throw new Error('COMMUNITY');
}
const fields = memberScreen.formFields?.map(field => ({
field_type: field.field_type,
label: field.label,
values: field.values,
required: field.required,
}));
const data = {};
if (typeof memberScreen.enabled !== 'undefined') data.enabled = memberScreen.enabled;
if (typeof memberScreen.description !== 'undefined') data.description = memberScreen.description;
if (typeof memberScreen.formFields !== 'undefined') data.form_fields = JSON.stringify(fields);
ckohen marked this conversation as resolved.
Show resolved Hide resolved
const res = await this.client.api.guilds(this.id, 'member-verification').patch({ data });
return {
enabled: memberScreen.enabled,
description: res.description,
formFields: res.form_fields.map(field => ({
fieldType: field.field_type,
label: field.label,
values: field.values,
required: field.required,
})),
};
}

/**
* Leaves the guild.
* @returns {Promise<Guild>}
Expand Down
7 changes: 7 additions & 0 deletions src/util/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,13 @@ exports.ExplicitContentFilterLevels = ['DISABLED', 'MEMBERS_WITHOUT_ROLES', 'ALL
*/
exports.VerificationLevels = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_HIGH'];

/**
* The type of membership screening. Here are the available types:
* * TERMS
* @typedef {string} MembershipScreeningType
*/
exports.MembershipScreeningType = ['TERMS'];
ckohen marked this conversation as resolved.
Show resolved Hide resolved

/**
* An error encountered while performing an API request. Here are the potential errors:
* * UNKNOWN_ACCOUNT
Expand Down
23 changes: 22 additions & 1 deletion typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ declare module 'discord.js' {
ExplicitContentFilterLevels: ExplicitContentFilterLevel[];
DefaultMessageNotifications: DefaultMessageNotifications[];
VerificationLevels: VerificationLevel[];
MembershipScreeningType: MembershipScreeningType[];
MembershipStates: 'INVITED' | 'ACCEPTED';
};

Expand Down Expand Up @@ -602,6 +603,7 @@ declare module 'discord.js' {
public readonly me: GuildMember | null;
public memberCount: number;
public members: GuildMemberManager;
public readonly membershipScreeningEnabled: boolean;
public mfaLevel: number;
public name: string;
public readonly nameAcronym: string;
Expand Down Expand Up @@ -647,6 +649,7 @@ declare module 'discord.js' {
public fetchEmbed(): Promise<GuildWidget>;
public fetchIntegrations(options?: FetchIntegrationsOptions): Promise<Collection<string, Integration>>;
public fetchInvites(): Promise<Collection<string, Invite>>;
public fetchMembershipScreening(): Promise<GuildMembershipScreening>;
public fetchPreview(): Promise<GuildPreview>;
public fetchTemplates(): Promise<Collection<GuildTemplate['code'], GuildTemplate>>;
public fetchVanityCode(): Promise<string>;
Expand All @@ -671,6 +674,7 @@ declare module 'discord.js' {
reason?: string,
): Promise<Guild>;
public setIcon(icon: Base64Resolvable | null, reason?: string): Promise<Guild>;
public setMembershipScreening(memberScreen: Partial<GuildMembershipScreening>): Promise<GuildMembershipScreening>;
public setName(name: string, reason?: string): Promise<Guild>;
public setOwner(owner: GuildMemberResolvable, reason?: string): Promise<Guild>;
public setPreferredLocale(preferredLocale: string, reason?: string): Promise<Guild>;
Expand Down Expand Up @@ -2652,7 +2656,9 @@ declare module 'discord.js' {
| 'VANITY_URL'
| 'VERIFIED'
| 'VIP_REGIONS'
| 'WELCOME_SCREEN_ENABLED';
| 'WELCOME_SCREEN_ENABLED'
| 'MEMBER_VERIFICATION_GATE_ENABLED'
| 'PREVIEW_ENABLED';

interface GuildMemberEditData {
nick?: string | null;
Expand All @@ -2664,6 +2670,19 @@ declare module 'discord.js' {

type GuildMemberResolvable = GuildMember | UserResolvable;

interface GuildMembershipScreening {
description: string;
enabled: boolean;
formFields: GuildMembershipScreeningField[];
}

interface GuildMembershipScreeningField {
fieldType: MembershipScreeningType;
label: string;
required: boolean;
values?: string;
}

type GuildResolvable = Guild | GuildChannel | GuildMember | GuildEmoji | Invite | Role | Snowflake;

interface GuildPruneMembersOptions {
Expand Down Expand Up @@ -2745,6 +2764,8 @@ declare module 'discord.js' {

type GuildTemplateResolvable = string;

type MembershipScreeningType = 'TERMS';

type MembershipStates = 'INVITED' | 'ACCEPTED';

type MessageAdditions = MessageEmbed | MessageAttachment | (MessageEmbed | MessageAttachment)[];
Expand Down