337 lines
10 KiB
JavaScript
337 lines
10 KiB
JavaScript
/*
|
|
* BetterDiscord User Struct
|
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
|
* All rights reserved.
|
|
* https://betterdiscord.net
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import { DiscordApi, DiscordApiModules as Modules } from 'modules';
|
|
import { List, InsufficientPermissions } from 'structs';
|
|
import { Utils } from 'common';
|
|
import { Guild } from './guild';
|
|
import { Channel } from './channel';
|
|
|
|
const users = new WeakMap();
|
|
|
|
/**
|
|
* Class representing a Discord user
|
|
*/
|
|
export class User {
|
|
|
|
constructor(data) {
|
|
if (users.has(data)) return users.get(data);
|
|
users.set(data, this);
|
|
|
|
this.discordObject = data;
|
|
}
|
|
|
|
static from(data) {
|
|
return new User(data);
|
|
}
|
|
|
|
static fromId(id) {
|
|
const user = Modules.UserStore.getUser(id);
|
|
if (user) return User.from(user);
|
|
}
|
|
|
|
static get GuildMember() { return GuildMember }
|
|
|
|
get id() { return this.discordObject.id }
|
|
get username() { return this.discordObject.username }
|
|
get usernameLowerCase() { return this.discordObject.usernameLowerCase }
|
|
get discriminator() { return this.discordObject.discriminator }
|
|
get avatar() { return this.discordObject.avatar }
|
|
get email() { return undefined }
|
|
get phone() { return undefined }
|
|
get flags() { return this.discordObject.flags }
|
|
get isBot() { return this.discordObject.bot }
|
|
get premium() { return this.discordObject.premium }
|
|
get verified() { return this.discordObject.verified }
|
|
get mfaEnabled() { return this.discordObject.mfaEnabled }
|
|
get mobile() { return this.discordObject.mobile }
|
|
|
|
get tag() { return this.discordObject.tag }
|
|
get avatarUrl() { return this.discordObject.avatarURL }
|
|
get createdAt() { return this.discordObject.createdAt }
|
|
|
|
get isClamied() { return this.discordObject.isClaimed() }
|
|
get isLocalBot() { return this.discordObject.isLocalBot() }
|
|
get isPhoneVerified() { return this.discordObject.isPhoneVerified() }
|
|
|
|
get guilds() {
|
|
return DiscordApi.guilds.filter(g => g.members.find(m => m.user === this));
|
|
}
|
|
|
|
get status() {
|
|
return Modules.UserStatusStore.getStatus(this.id);
|
|
}
|
|
|
|
get activity() {
|
|
// type can be either 0 (normal/rich presence game), 1 (streaming) or 2 (listening to Spotify)
|
|
// (3 appears as watching but is undocumented)
|
|
return Modules.UserStatusStore.getActivity(this.id);
|
|
}
|
|
|
|
get note() {
|
|
const note = Modules.UserNoteStore.getNote(this.id);
|
|
return note ? note : null;
|
|
}
|
|
|
|
/**
|
|
* Updates the note for this user.
|
|
* @param {String} note The new note
|
|
* @return {Promise}
|
|
*/
|
|
updateNote(note) {
|
|
return Modules.APIModule.put({
|
|
url: `${Modules.DiscordConstants.Endpoints.NOTES}/${this.id}`,
|
|
body: { note }
|
|
});
|
|
}
|
|
|
|
get privateChannel() {
|
|
return DiscordApi.channels.find(c => c.type === 'DM' && c.recipientId === this.id);
|
|
}
|
|
|
|
async ensurePrivateChannel() {
|
|
if (DiscordApi.currentUser === this)
|
|
throw new Error('Cannot create a direct message channel to the current user.');
|
|
return Channel.fromId(await Modules.PrivateChannelActions.ensurePrivateChannel(DiscordApi.currentUser.id, this.id));
|
|
}
|
|
|
|
async sendMessage(content, parse = true) {
|
|
const channel = await this.ensurePrivateChannel();
|
|
return channel.sendMessage(content, parse);
|
|
}
|
|
|
|
get isFriend() {
|
|
return Modules.RelationshipStore.isFriend(this.id);
|
|
}
|
|
|
|
get isBlocked() {
|
|
return Modules.RelationshipStore.isBlocked(this.id);
|
|
}
|
|
|
|
addFriend() {
|
|
Modules.RelationshipManager.addRelationship(this.id, {location: 'Context Menu'});
|
|
}
|
|
|
|
removeFriend() {
|
|
Modules.RelationshipManager.removeRelationship(this.id, {location: 'Context Menu'});
|
|
}
|
|
|
|
block() {
|
|
Modules.RelationshipManager.addRelationship(this.id, {location: 'Context Menu'}, Modules.DiscordConstants.RelationshipTypes.BLOCKED);
|
|
}
|
|
|
|
unblock() {
|
|
Modules.RelationshipManager.removeRelationship(this.id, {location: 'Context Menu'});
|
|
}
|
|
|
|
/**
|
|
* Opens the profile modal for this user.
|
|
* @param {String} section The section to open (see DiscordConstants.UserProfileSections)
|
|
*/
|
|
openUserProfileModal(section = 'USER_INFO') {
|
|
Modules.UserProfileModal.open(this.id);
|
|
Modules.UserProfileModal.setSection(section);
|
|
}
|
|
|
|
}
|
|
|
|
const guild_members = new WeakMap();
|
|
|
|
/**
|
|
* Class representing a Discord Guild Member
|
|
*/
|
|
export class GuildMember {
|
|
constructor(data, guild_id) {
|
|
if (guild_members.has(data)) return guild_members.get(data);
|
|
guild_members.set(data, this);
|
|
|
|
this.discordObject = data;
|
|
this.guildId = guild_id;
|
|
}
|
|
|
|
get userId() { return this.discordObject.userId }
|
|
get nickname() { return this.discordObject.nick }
|
|
get colourString() { return this.discordObject.colorString }
|
|
get hoistRoleId() { return this.discordObject.hoistRoleId }
|
|
get roleIds() { return this.discordObject.roles }
|
|
|
|
get user() {
|
|
return User.fromId(this.userId);
|
|
}
|
|
|
|
get name() {
|
|
return this.nickname || this.user.username;
|
|
}
|
|
|
|
get guild() {
|
|
return Guild.fromId(this.guildId);
|
|
}
|
|
|
|
get roles() {
|
|
return List.from(this.roleIds, id => this.guild.roles.find(r => r.id === id))
|
|
.sort((r1, r2) => r1.position === r2.position ? 0 : r1.position > r2.position ? 1 : -1);
|
|
}
|
|
|
|
get hoistRole() {
|
|
return this.guild.roles.find(r => r.id === this.hoistRoleId);
|
|
}
|
|
|
|
checkPermissions(perms) {
|
|
return Modules.PermissionUtils.can(perms, DiscordApi.currentUser.discordObject, this.guild.discordObject);
|
|
}
|
|
|
|
assertPermissions(name, perms) {
|
|
if (!this.checkPermissions(perms)) throw new InsufficientPermissions(name);
|
|
}
|
|
|
|
/**
|
|
* Opens the modal to change this user's nickname.
|
|
*/
|
|
openChangeNicknameModal() {
|
|
if (DiscordApi.currentUser === this.user)
|
|
this.assertPermissions('CHANGE_NICKNAME', Modules.DiscordPermissions.CHANGE_NICKNAME);
|
|
else this.assertPermissions('MANAGE_NICKNAMES', Modules.DiscordPermissions.MANAGE_NICKNAMES);
|
|
|
|
Modules.ChangeNicknameModal.open(this.guildId, this.userId);
|
|
}
|
|
|
|
/**
|
|
* Changes the user's nickname on this guild.
|
|
* @param {String} nickname The user's new nickname
|
|
* @return {Promise}
|
|
*/
|
|
changeNickname(nick) {
|
|
if (DiscordApi.currentUser === this.user)
|
|
this.assertPermissions('CHANGE_NICKNAME', Modules.DiscordPermissions.CHANGE_NICKNAME);
|
|
else this.assertPermissions('MANAGE_NICKNAMES', Modules.DiscordPermissions.MANAGE_NICKNAMES);
|
|
|
|
return Modules.APIModule.patch({
|
|
url: `${Modules.DiscordConstants.Endpoints.GUILD_MEMBERS(this.guild_id)}/${DiscordApi.currentUser === this.user ? '@me/nick' : this.userId}`,
|
|
body: { nick }
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Kicks this user from the guild.
|
|
* @param {String} reason A reason to attach to the audit log entry
|
|
* @return {Promise}
|
|
*/
|
|
kick(reason = '') {
|
|
this.assertPermissions('KICK_MEMBERS', Modules.DiscordPermissions.KICK_MEMBERS);
|
|
return Modules.GuildActions.kickUser(this.guildId, this.userId, reason);
|
|
}
|
|
|
|
/**
|
|
* Bans this user from the guild.
|
|
* @param {Number} daysToDelete The number of days of the user's recent message history to delete
|
|
* @param {String} reason A reason to attach to the audit log entry
|
|
* @return {Promise}
|
|
*/
|
|
ban(daysToDelete = 1, reason = '') {
|
|
this.assertPermissions('BAN_MEMBERS', Modules.DiscordPermissions.BAN_MEMBERS);
|
|
return Modules.GuildActions.banUser(this.guildId, this.userId, daysToDelete, reason);
|
|
}
|
|
|
|
/**
|
|
* Removes the ban for this user.
|
|
* @return {Promise}
|
|
*/
|
|
unban() {
|
|
this.assertPermissions('BAN_MEMBERS', Modules.DiscordPermissions.BAN_MEMBERS);
|
|
return Modules.GuildActions.unbanUser(this.guildId, this.userId);
|
|
}
|
|
|
|
/**
|
|
* Moves this user to another voice channel.
|
|
* @param {GuildVoiceChannel} channel The channel to move this user to
|
|
*/
|
|
move(channel) {
|
|
this.assertPermissions('MOVE_MEMBERS', Modules.DiscordPermissions.MOVE_MEMBERS);
|
|
Modules.GuildActions.setChannel(this.guildId, this.userId, channel.id);
|
|
}
|
|
|
|
/**
|
|
* Mutes this user for everyone in the guild.
|
|
*/
|
|
mute(active = true) {
|
|
this.assertPermissions('MUTE_MEMBERS', Modules.DiscordPermissions.MUTE_MEMBERS);
|
|
Modules.GuildActions.setServerMute(this.guildId, this.userId, active);
|
|
}
|
|
|
|
/**
|
|
* Unmutes this user.
|
|
*/
|
|
unmute() {
|
|
this.mute(false);
|
|
}
|
|
|
|
/**
|
|
* Deafens this user.
|
|
*/
|
|
deafen(active = true) {
|
|
this.assertPermissions('DEAFEN_MEMBERS', Modules.DiscordPermissions.DEAFEN_MEMBERS);
|
|
Modules.GuildActions.setServerDeaf(this.guildId, this.userId, active);
|
|
}
|
|
|
|
/**
|
|
* Undeafens this user.
|
|
*/
|
|
undeafen() {
|
|
this.deafen(false);
|
|
}
|
|
|
|
/**
|
|
* Gives this user a role.
|
|
* @param {Role} role The role to add
|
|
* @return {Promise}
|
|
*/
|
|
addRole(...roles) {
|
|
const newRoles = this.roleIds.concat([]);
|
|
let changed = false;
|
|
for (const role of roles) {
|
|
if (newRoles.includes(role.id || role)) continue;
|
|
newRoles.push(role.id || role);
|
|
changed = true;
|
|
}
|
|
if (!changed) return;
|
|
return this.updateRoles(newRoles);
|
|
}
|
|
|
|
/**
|
|
* Removes a role from this user.
|
|
* @param {Role} role The role to remove
|
|
* @return {Promise}
|
|
*/
|
|
removeRole(...roles) {
|
|
const newRoles = this.roleIds.concat([]);
|
|
let changed = false;
|
|
for (const role of roles) {
|
|
if (!newRoles.includes(role.id || role)) continue;
|
|
Utils.removeFromArray(newRoles, role.id || role);
|
|
changed = true;
|
|
}
|
|
if (!changed) return;
|
|
return this.updateRoles(newRoles);
|
|
}
|
|
|
|
/**
|
|
* Updates this user's roles.
|
|
* @param {Array} roles An array of Role objects or role IDs
|
|
* @return {Promise}
|
|
*/
|
|
updateRoles(roles) {
|
|
roles = roles.map(r => r.id || r);
|
|
return Modules.APIModule.patch({
|
|
url: `${Modules.DiscordConstants.Endpoints.GUILD_MEMBERS(this.guildId)}/${this.userId}`,
|
|
body: { roles }
|
|
});
|
|
}
|
|
}
|