mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
Docs: guilds.ts (#72)
* Documentation for channels.ts: BaseChannel and TextChannel * Update channels docs * Documentation: guilds.ts * Documentation: guilds.ts * Documentation: Guild finish * Remove some links
This commit is contained in:
parent
63faae768a
commit
5141ad2bb3
@ -208,6 +208,7 @@ export class TextChannel {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetchPins makes an asynchronous request and gets the current channel pins.
|
||||
* @returns A promise that resolves with an array of Message objects.
|
||||
|
@ -46,29 +46,54 @@ export abstract class BaseGuild implements Model {
|
||||
this.features = data.features;
|
||||
}
|
||||
|
||||
/** The session that instantiated the guild. */
|
||||
readonly session: Session;
|
||||
/** Guild id. */
|
||||
readonly id: Snowflake;
|
||||
|
||||
/** Guild name. */
|
||||
name: string;
|
||||
/**
|
||||
* Icon hash. Discord uses ids and hashes to render images in the client.
|
||||
* @link https://discord.com/developers/docs/reference#image-formatting
|
||||
* */
|
||||
iconHash?: bigint;
|
||||
/**
|
||||
* Enabled guild features (animated banner, news, auto moderation, etc).
|
||||
* @see {@link GuildFeatures}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features
|
||||
* */
|
||||
features: GuildFeatures[];
|
||||
|
||||
/** createdTimestamp gets the current guild timestamp. */
|
||||
get createdTimestamp(): number {
|
||||
return Snowflake.snowflakeToTimestamp(this.id);
|
||||
}
|
||||
|
||||
/** createdAt gets the creation Date object of the guild. */
|
||||
get createdAt(): Date {
|
||||
return new Date(this.createdTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the guild features includes partnered.
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features
|
||||
* */
|
||||
get partnered(): boolean {
|
||||
return this.features.includes(GuildFeatures.Partnered);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the guild is verified.
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-guild-features
|
||||
* */
|
||||
get verified(): boolean {
|
||||
return this.features.includes(GuildFeatures.Verified);
|
||||
}
|
||||
|
||||
/**
|
||||
* iconURL gets the current guild icon.
|
||||
* @link https://discord.com/developers/docs/reference#image-formatting
|
||||
* */
|
||||
iconURL(options: { size?: ImageSize; format?: ImageFormat } = { size: 128 }): string | void {
|
||||
if (this.iconHash) {
|
||||
return Util.formatImageURL(
|
||||
@ -79,12 +104,18 @@ export abstract class BaseGuild implements Model {
|
||||
}
|
||||
}
|
||||
|
||||
/** toString gets the guild name */
|
||||
toString(): string {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
/** AnonymousGuild */
|
||||
/**
|
||||
* Class for anonymous guilds.
|
||||
* @see {@link BaseGuild}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-resource
|
||||
*/
|
||||
export class AnonymousGuild extends BaseGuild implements Model {
|
||||
constructor(session: Session, data: Partial<DiscordGuild>); // TODO: Improve this type (name and id are required)
|
||||
constructor(session: Session, data: DiscordGuild) {
|
||||
@ -100,15 +131,41 @@ export class AnonymousGuild extends BaseGuild implements Model {
|
||||
this.premiumSubscriptionCount = data.premium_subscription_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* The guild's splash hash.
|
||||
* @link https://discord.com/developers/docs/reference#image-formatting
|
||||
*/
|
||||
splashHash?: bigint;
|
||||
/**
|
||||
* The guild's banner hash.
|
||||
* @link https://discord.com/developers/docs/reference#image-formatting
|
||||
*/
|
||||
bannerHash?: bigint;
|
||||
|
||||
/**
|
||||
* The guild's verification level.
|
||||
* @see {@link VerificationLevels}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-verification-level
|
||||
*/
|
||||
verificationLevel: VerificationLevels;
|
||||
/** The guild's vanity url code. */
|
||||
vanityUrlCode?: string;
|
||||
/**
|
||||
* The guild's nsfw level.
|
||||
* @see {@link GuildNsfwLevel}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-guild-nsfw-level
|
||||
*/
|
||||
nsfwLevel: GuildNsfwLevel;
|
||||
/** The guild's description. */
|
||||
description?: string;
|
||||
/** The number of boosts this guild currently has. */
|
||||
premiumSubscriptionCount?: number;
|
||||
|
||||
/**
|
||||
* splashURL gets the current guild splash as a string.
|
||||
* @link https://discord.com/developers/docs/reference#image-formatting
|
||||
* @param options - Image options for the splash url.
|
||||
* @returns Splash url or void.
|
||||
*/
|
||||
splashURL(options: { size?: ImageSize; format?: ImageFormat } = { size: 128 }): string | void {
|
||||
if (this.splashHash) {
|
||||
return Util.formatImageURL(
|
||||
@ -119,6 +176,12 @@ export class AnonymousGuild extends BaseGuild implements Model {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bannerURL gets the current guild banner as a string.
|
||||
* @link https://discord.com/developers/docs/reference#image-formatting
|
||||
* @param options - Image options for the banner url.
|
||||
* @returns Banner url or void
|
||||
*/
|
||||
bannerURL(options: { size?: ImageSize; format?: ImageFormat } = { size: 128 }): string | void {
|
||||
if (this.bannerHash) {
|
||||
return Util.formatImageURL(
|
||||
@ -305,7 +368,8 @@ export interface GuildEditOptions extends Partial<GuildCreateOptions> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a guild
|
||||
* Represents a guild.
|
||||
* @see {@link BaseGuild}.
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object
|
||||
*/
|
||||
export class Guild extends BaseGuild implements Model {
|
||||
@ -339,18 +403,69 @@ export class Guild extends BaseGuild implements Model {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The guild's splash hash.
|
||||
* @link https://discord.com/developers/docs/reference#image-formatting
|
||||
*/
|
||||
splashHash?: bigint;
|
||||
/**
|
||||
* Only present for guilds with the "DISCOVERABLE" feature
|
||||
* @link https://discord.com/developers/docs/reference#image-formatting
|
||||
*/
|
||||
discoverySplashHash?: bigint;
|
||||
/** ID of the guild owner. */
|
||||
ownerId: Snowflake;
|
||||
/** True if the server widget is enabled */
|
||||
widgetEnabled: boolean;
|
||||
/** The channel id that the widget will generate an invite to, or undefined if set to no invite. */
|
||||
widgetChannelId?: Snowflake;
|
||||
/**
|
||||
* Verification level required for the guild.
|
||||
* @see {@link VerificationLevels}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-verification-level
|
||||
*/
|
||||
vefificationLevel: VerificationLevels;
|
||||
/**
|
||||
* The default message notification level.
|
||||
* @see {@link DefaultMessageNotificationLevels}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-default-message-notification-level
|
||||
*/
|
||||
defaultMessageNotificationLevel: DefaultMessageNotificationLevels;
|
||||
/**
|
||||
* The explicit content filter level.
|
||||
* @see {@link ExplicitContentFilterLevels}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-explicit-content-filter-level
|
||||
*/
|
||||
explicitContentFilterLevel: ExplicitContentFilterLevels;
|
||||
/**
|
||||
* Premium tier (Server Boost level).
|
||||
* @see {@link PremiumTiers}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-object-premium-tier
|
||||
*/
|
||||
premiumTier: PremiumTiers;
|
||||
/**
|
||||
* A map with the guild's members.
|
||||
* @see {@link Member}
|
||||
* @link https://discord.com/developers/docs/resources/guild#guild-member-object
|
||||
*/
|
||||
members: Map<Snowflake, Member>;
|
||||
/**
|
||||
* A map with the guild's roles.
|
||||
* @see {@link Role}
|
||||
* @link https://discord.com/developers/docs/topics/permissions#role-object
|
||||
*/
|
||||
roles: Map<Snowflake, Role>;
|
||||
/**
|
||||
* A map with the guild's emojis.
|
||||
* @see {@link GuildEmoji}
|
||||
* @link https://discord.com/developers/docs/resources/emoji#emoji-object-emoji-structure
|
||||
*/
|
||||
emojis: Map<Snowflake, GuildEmoji>;
|
||||
/**
|
||||
* A map with the guild's channels.
|
||||
* @see {@link GuildChannel}
|
||||
* @link https://discord.com/developers/docs/resources/channel#channel-object
|
||||
*/
|
||||
channels: Map<Snowflake, GuildChannel>;
|
||||
|
||||
/**
|
||||
@ -386,7 +501,8 @@ export class Guild extends BaseGuild implements Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* 'null' would reset the nickname
|
||||
* editBotNickname edits the bot's nickname in the guild.
|
||||
* 'null' would reset the nickname.
|
||||
*/
|
||||
async editBotNickname(options: { nick: string | null; reason?: string }): Promise<(string | undefined)> {
|
||||
const result = await this.session.rest.runMethod<{ nick?: string } | undefined>(
|
||||
@ -399,6 +515,13 @@ export class Guild extends BaseGuild implements Model {
|
||||
return result?.nick;
|
||||
}
|
||||
|
||||
/**
|
||||
* createEmoji creates an emoji in the guild.
|
||||
* @see {@link CreateGuildEmoji}
|
||||
* @see {@link GuildEmoji}
|
||||
* @param options The options to create a emoji.
|
||||
* @returns A promise that resolves to the guild's new emoji.
|
||||
*/
|
||||
async createEmoji(options: CreateGuildEmoji): Promise<GuildEmoji> {
|
||||
if (options.image && !options.image.startsWith('data:image/')) {
|
||||
options.image = await urlToBase64(options.image);
|
||||
@ -414,6 +537,11 @@ export class Guild extends BaseGuild implements Model {
|
||||
return new GuildEmoji(this.session, emoji, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* deleteEmoji deletes an emoji from the guild.
|
||||
* @param id - The id of the emoji to delete.
|
||||
* @param reason - The reason for deleting the emoji.
|
||||
*/
|
||||
async deleteEmoji(id: Snowflake, { reason }: { reason?: string } = {}): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
this.session.rest,
|
||||
@ -423,6 +551,14 @@ export class Guild extends BaseGuild implements Model {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* editEmoji edits an emoji in the guild.
|
||||
* @see {@link ModifyGuildEmoji}
|
||||
* @see {@link GuildEmoji}
|
||||
* @param id - The id of the emoji to edit.
|
||||
* @param options - Options to modify the emoji.
|
||||
* @returns A promise that resolves to the edited emoji.
|
||||
*/
|
||||
async editEmoji(id: Snowflake, options: ModifyGuildEmoji): Promise<GuildEmoji> {
|
||||
const emoji = await this.session.rest.runMethod<DiscordEmoji>(
|
||||
this.session.rest,
|
||||
@ -434,6 +570,12 @@ export class Guild extends BaseGuild implements Model {
|
||||
return new GuildEmoji(this.session, emoji, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* createRole creates a role in the guild.
|
||||
* @see {@link CreateRole}
|
||||
* @see {@link Role}
|
||||
* @param options - Options to create a new role.
|
||||
*/
|
||||
async createRole(options: CreateRole): Promise<Role> {
|
||||
let icon: string | undefined;
|
||||
|
||||
@ -462,10 +604,21 @@ export class Guild extends BaseGuild implements Model {
|
||||
return new Role(this.session, role, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* deleteRole deletes a role from the guild.
|
||||
* @param roleId - The id of the role to delete.
|
||||
* */
|
||||
async deleteRole(roleId: Snowflake): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(this.session.rest, 'DELETE', Routes.GUILD_ROLE(this.id, roleId));
|
||||
}
|
||||
|
||||
/**
|
||||
* editRole edits a role in the guild.
|
||||
* @see {@link ModifyGuildRole}
|
||||
* @see {@link Role}
|
||||
* @param roleId - The id of the role to edit.
|
||||
* @param options - Options to modify the role.
|
||||
*/
|
||||
async editRole(roleId: Snowflake, options: ModifyGuildRole): Promise<Role> {
|
||||
const role = await this.session.rest.runMethod<DiscordRole>(
|
||||
this.session.rest,
|
||||
@ -482,6 +635,12 @@ export class Guild extends BaseGuild implements Model {
|
||||
return new Role(this.session, role, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* addRole adds a role to a user in the guild.
|
||||
* @param memberId - The id of the member to add a role to.
|
||||
* @param roleId - The id of the role to add.
|
||||
* @param reason - The reason for adding the role to the member.
|
||||
*/
|
||||
async addRole(memberId: Snowflake, roleId: Snowflake, { reason }: { reason?: string } = {}): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
this.session.rest,
|
||||
@ -491,6 +650,12 @@ export class Guild extends BaseGuild implements Model {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* removeRole removes a role from a user in the guild.
|
||||
* @param memberId - The id of the member to remove a role from.
|
||||
* @param roleId - The id of the role to remove.
|
||||
* @param reason - The reason for removing the role from the member.
|
||||
*/
|
||||
async removeRole(memberId: Snowflake, roleId: Snowflake, { reason }: { reason?: string } = {}): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
this.session.rest,
|
||||
@ -501,7 +666,10 @@ export class Guild extends BaseGuild implements Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the roles moved
|
||||
* Returns the roles moved.
|
||||
* @see {@link ModifyRolePositions}
|
||||
* @see {@link Role}
|
||||
* @param options - Options to modify the roles.
|
||||
*/
|
||||
async moveRoles(options: ModifyRolePositions[]): Promise<Role[]> {
|
||||
const roles = await this.session.rest.runMethod<DiscordRole[]>(
|
||||
@ -514,6 +682,10 @@ export class Guild extends BaseGuild implements Model {
|
||||
return roles.map((role) => new Role(this.session, role, this.id));
|
||||
}
|
||||
|
||||
/**
|
||||
* deleteInvite deletes an invite from the guild.
|
||||
* @param inviteCode - The invite code to get the invite for.
|
||||
*/
|
||||
async deleteInvite(inviteCode: string): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
this.session.rest,
|
||||
@ -523,6 +695,14 @@ export class Guild extends BaseGuild implements Model {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* fetchInvite gets an invite from the guild.
|
||||
* @see {@link Routes.GetInvite}
|
||||
* @see {@link Invite}
|
||||
* @param inviteCode - The invite code to get the invite for.
|
||||
* @param options - Options to get the invite.
|
||||
* @returns Promise resolving to the invite.
|
||||
*/
|
||||
async fetchInvite(inviteCode: string, options: Routes.GetInvite): Promise<Invite> {
|
||||
const inviteMetadata = await this.session.rest.runMethod<DiscordInviteMetadata>(
|
||||
this.session.rest,
|
||||
@ -533,6 +713,11 @@ export class Guild extends BaseGuild implements Model {
|
||||
return new Invite(this.session, inviteMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* fetchInvites gets all invites from the guild.
|
||||
* @see {@link Invite}
|
||||
* @returns A promise that resolves to the guild's invites.
|
||||
*/
|
||||
async fetchInvites(): Promise<Invite[]> {
|
||||
const invites = await this.session.rest.runMethod<DiscordInviteMetadata[]>(
|
||||
this.session.rest,
|
||||
@ -544,7 +729,10 @@ export class Guild extends BaseGuild implements Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* Bans the member
|
||||
* banMember bans a member from the guild.
|
||||
* @see {@link CreateGuildBan}
|
||||
* @param memberId - The id of the member to ban.
|
||||
* @param options - Options to ban the member.
|
||||
*/
|
||||
async banMember(memberId: Snowflake, options: CreateGuildBan): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
@ -561,7 +749,9 @@ export class Guild extends BaseGuild implements Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks the member
|
||||
* kickMember kicks a member from the guild.
|
||||
* @param memberId - The id of the member to kick.
|
||||
* @param reason - The reason for kicking the member.
|
||||
*/
|
||||
async kickMember(memberId: Snowflake, { reason }: { reason?: string }): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
@ -572,9 +762,10 @@ export class Guild extends BaseGuild implements Model {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unbans the member
|
||||
* */
|
||||
/**
|
||||
* unbanMember unbans a member from the guild.
|
||||
* @param memberId - The id of the member to get.
|
||||
*/
|
||||
async unbanMember(memberId: Snowflake): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
this.session.rest,
|
||||
@ -583,6 +774,14 @@ export class Guild extends BaseGuild implements Model {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* editMember edits a member in the guild.
|
||||
* @see {@link ModifyGuildMember}
|
||||
* @see {@link Member}
|
||||
* @param memberId - The id of the member to get.
|
||||
* @param options - Options to edit the member.
|
||||
* @returns Promise resolving to the edited member.
|
||||
*/
|
||||
async editMember(memberId: Snowflake, options: ModifyGuildMember): Promise<Member> {
|
||||
const member = await this.session.rest.runMethod<DiscordMemberWithUser>(
|
||||
this.session.rest,
|
||||
@ -603,6 +802,12 @@ export class Guild extends BaseGuild implements Model {
|
||||
return new Member(this.session, member, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* pruneMembers prunes members from the guild.
|
||||
* @see {@link BeginGuildPrune}
|
||||
* @param options - Options to prune the members.
|
||||
* @returns A promise that resolves to the number of members pruned.
|
||||
*/
|
||||
async pruneMembers(options: BeginGuildPrune): Promise<number> {
|
||||
const result = await this.session.rest.runMethod<{ pruned: number }>(
|
||||
this.session.rest,
|
||||
@ -618,6 +823,10 @@ export class Guild extends BaseGuild implements Model {
|
||||
return result.pruned;
|
||||
}
|
||||
|
||||
/**
|
||||
* getPruneCount gets 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> {
|
||||
const result = await this.session.rest.runMethod<{ pruned: number }>(
|
||||
this.session.rest,
|
||||
@ -628,6 +837,11 @@ export class Guild extends BaseGuild implements Model {
|
||||
return result.pruned;
|
||||
}
|
||||
|
||||
/**
|
||||
* getActiveThreads gets the active threads in the guild.
|
||||
* @see {@link ReturnThreadsArchive}
|
||||
* @returns Promise resolving a ReturnThreadsArchive without hasMore property.
|
||||
*/
|
||||
async getActiveThreads(): Promise<Omit<ReturnThreadsArchive, 'hasMore'>> {
|
||||
const { threads, members } = await this.session.rest.runMethod<DiscordListActiveThreads>(
|
||||
this.session.rest,
|
||||
@ -646,7 +860,7 @@ export class Guild extends BaseGuild implements Model {
|
||||
}
|
||||
|
||||
/** *
|
||||
* Deletes a guild
|
||||
* Deletes the guild.
|
||||
*/
|
||||
async delete(): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
@ -657,7 +871,7 @@ export class Guild extends BaseGuild implements Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves the guild
|
||||
* Leaves the guild.
|
||||
*/
|
||||
async leave(): Promise<void> {
|
||||
await this.session.rest.runMethod<undefined>(
|
||||
@ -671,6 +885,12 @@ export class Guild extends BaseGuild implements Model {
|
||||
* Creates a guild and returns its data, the bot joins the guild
|
||||
* This was modified from discord.js to make it compatible
|
||||
* precondition: Bot should be in less than 10 servers
|
||||
* @see {@link Session}
|
||||
* @see {@link GuildCreateOptions}
|
||||
* @see {@link Guild}
|
||||
* @param session - The session the guild should be created in.
|
||||
* @param options - Options to create the guild.
|
||||
* @returns A promise that resolves to the created guild.
|
||||
*/
|
||||
static async create(session: Session, options: GuildCreateOptions): Promise<Guild> {
|
||||
const guild = await session.rest.runMethod<DiscordGuild>(session.rest, 'POST', Routes.GUILDS(), {
|
||||
@ -712,28 +932,35 @@ export class Guild extends BaseGuild implements Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* ESets a new guild splash.
|
||||
* setSplash sets a new splash for the guild. Same as Guild.edit({..., splash: 'splashURL'})
|
||||
* @see {@link Guild}
|
||||
*/
|
||||
setSplash(splashURL: string): Promise<Guild> {
|
||||
return this.edit({ splashURL });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new guild banner.
|
||||
* setBanner sets a new banner for the guild. Same as Guild.edit({..., banner: 'bannerURL'})
|
||||
* @see {@link Guild}
|
||||
*/
|
||||
setBanner(bannerURL: string): Promise<Guild> {
|
||||
return this.edit({ bannerURL });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new guild discovery splash image.
|
||||
* Sets a new guild discovery splash image. Same as Guild.edit({..., discoverySplashURL: 'discoverySplashURL'})
|
||||
* @see {@link Guild}
|
||||
*/
|
||||
setDiscoverySplash(discoverySplashURL: string): Promise<Guild> {
|
||||
return this.edit({ discoverySplashURL });
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits a guild and returns its data
|
||||
* Edits a guild and returns its data.
|
||||
* @see {@link Guild}
|
||||
* @see {@link GuildEditOptions}
|
||||
* @param options - Options to edit the guild.
|
||||
* @returns A promise that resolves to the edited guild.
|
||||
*/
|
||||
async edit(options: GuildEditOptions): Promise<Guild> {
|
||||
const guild = await this.session.rest.runMethod<DiscordGuild>(this.session.rest, 'PATCH', Routes.GUILDS(), {
|
||||
|
Loading…
x
Reference in New Issue
Block a user