'use strict'; const CachedManager = require('./CachedManager'); const { default: Collection } = require('@discordjs/collection'); const { Error, TypeError } = require('../errors/DJSError'); const { remove } = require('lodash'); const { localeObject, DMScanLevel, stickerAnimationMode } = require('../util/Constants') /** * Manages API methods for users and stores their cache. * @extends {CachedManager} */ class ClientUserSettingManager extends CachedManager { constructor(client, iterable) { super(client); // Raw data this.rawSetting = {}; // Language this.locale = null; // Setting => ACTIVITY SETTINGS => Activity Status => Display current activity as a status message this.activityDisplay = null; // this.disableDMfromServer = new Collection(); // Allow direct messages from server members this.DMfromServerMode = null; // this.displayImage = null; // this.linkedImageDisplay = null; // Setting => APP SETTINGS => Accessibility => Automatically play GIFs when Discord is focused. this.autoplayGIF = null; // Show embeds and preview website links pasted into chat this.previewLink = null; // Setting => APP SETTINGS => Accessibility => Play Animated Emojis this.animatedEmojis = null; // Setting => APP SETTINGS => Accessibility => Text-to-speech => Allow playback this.allowTTS = null; // Setting => APP SETTINGS => Appearance => Message Display => Compact Mode [OK] this.compactMode = null; // Setting => APP SETTINGS => Text & Images => Emoji => Convert Emoticons this.convertEmoticons = null; // SAFE DIRECT MESSAGING this.DMScanLevel = null; // Setting => APP SETTINGS => Appearance => Theme [OK] this.theme = ''; // this.developerMode = null; // this.afkTimeout = null; // this.stickerAnimationMode = null; // WHO CAN ADD YOU AS A FRIEND ? this.addFriendFrom = { all: null, mutual_friends: null, mutual_guilds: null, }; // Setting => APP SETTINGS => Text & Images => Emoji => Show emoji reactions this.showEmojiReactions = null; // Custom Stauts [It's not working now] this.customStatus = null; // Guild folder and position this.guildMetadata = new Collection(); // Todo: add new method from Discum } /** * * @param {Object} data Raw Data to patch * @extends https://github.com/Merubokkusu/Discord-S.C.U.M/blob/master/discum/user/user.py * @private */ _patch(data) { this.rawSetting = Object.assign(this.rawSetting, data); if ('locale' in data) { this.locale = localeObject[data.locale]; } if ('show_current_game' in data) { this.activityDisplay = data.show_current_game; } if ('default_guilds_restricted' in data) { this.DMfromServerMode = data.default_guilds_restricted; } if ('inline_attachment_media' in data) { this.displayImage = data.inline_attachment_media; } if ('inline_embed_media' in data) { this.linkedImageDisplay = data.inline_embed_media; } if ('gif_auto_play' in data) { this.autoplayGIF = data.gif_auto_play; } if ('render_embeds' in data) { this.previewLink = data.render_embeds; } if ('animate_emoji' in data) { this.animatedEmojis = data.animate_emoji; } if ('enable_tts_command' in data) { this.allowTTS = data.enable_tts_command; } if ('message_display_compact' in data) { this.compactMode = data.message_display_compact; } if ('convert_emoticons' in data) { this.convertEmoticons = data.convert_emoticons; } if ('explicit_content_filter' in data) { this.DMScanLevel = DMScanLevel[data.explicit_content_filter]; } if ('theme' in data) { this.theme = data.theme; } if ('developer_mode' in data) { this.developerMode = data.developer_mode; } if ('afk_timeout' in data) { this.afkTimeout = data.afk_timeout * 1000; // second => milisecond } if ('animate_stickers' in data) { this.stickerAnimationMode = stickerAnimationMode[data.animate_stickers]; } if ('render_reactions' in data) { this.showEmojiReactions = data.render_reactions; } if ('custom_status' in data) { this.customStatus = data.custom_status || {}; // Thanks PinkDuwc._#3443 reported this issue this.customStatus.status = data.status; } if ('friend_source_flags' in data) { this.addFriendFrom = { all: data.friend_source_flags.all || false, mutual_friends: data.friend_source_flags.all ? true : data.friend_source_flags.mutual_friends, mutual_guilds: data.friend_source_flags.all ? true : data.friend_source_flags.mutual_guilds, }; } if ('guild_folders' in data) { const data_ = data.guild_positions.map((guildId, i) => { // Find folder const folderIndex = data.guild_folders.findIndex((obj) => obj.guild_ids.includes(guildId), ); const metadata = { guildId: guildId, guildIndex: i, folderId: data.guild_folders[folderIndex]?.id, folderIndex, folderName: data.guild_folders[folderIndex]?.name, folderColor: data.guild_folders[folderIndex]?.color, folderGuilds: data.guild_folders[folderIndex]?.guild_ids, }; return [guildId, metadata]; }); this.guildMetadata = new Collection(data_); } if ('restricted_guilds' in data) { data.restricted_guilds.map((guildId) => { const guild = this.client.guilds.cache.get(guildId); if (!guild) return; guild.disableDM = true; this.disableDMfromServer.set(guildId, true); }); } } async fetch() { if (this.client.bot) throw new Error('INVALID_BOT_METHOD'); try { const data = await this.client.api.users('@me').settings.get(); this._patch(data); return this; } catch (e) { throw e; } } /** * Edit data * @param {Object} data Data to edit * @private */ async edit(data) { if (this.client.bot) throw new Error('INVALID_BOT_METHOD'); try { const res = await this.client.api.users('@me').settings.patch({ data }); this._patch(res); return this; } catch (e) { throw e; } } /** * Set compact mode * @param {Boolean | null} value Compact mode enable or disable * @returns {Boolean} */ async setDisplayCompactMode(value) { if (this.client.bot) throw new Error('INVALID_BOT_METHOD'); if ( typeof value !== 'boolean' && typeof value !== 'null' && typeof value !== 'undefined' ) throw new TypeError( 'INVALID_TYPE', 'value', 'boolean | null | undefined', true, ); if (!value) value = !this.compactMode; if (value !== this.compactMode) { await this.edit({ message_display_compact: value }); } return this.compactMode; } /** * Discord Theme * @param {null |dark |light} value Theme to set * @returns {theme} */ async setTheme(value) { if (this.client.bot) throw new Error('INVALID_BOT_METHOD'); const validValues = ['dark', 'light']; if ( typeof value !== 'string' && typeof value !== 'null' && typeof value !== 'undefined' ) throw new TypeError( 'INVALID_TYPE', 'value', 'string | null | undefined', true, ); if (!validValues.includes(value)) { value == validValues[0] ? (value = validValues[1]) : (value = validValues[0]); } if (value !== this.theme) { await this.edit({ theme: value }); } return this.theme; } /** * * Locale Setting, must be one of: * * `DANISH` * * `GERMAN` * * `ENGLISH_UK` * * `ENGLISH_US` * * `SPANISH` * * `FRENCH` * * `CROATIAN` * * `ITALIAN` * * `LITHUANIAN` * * `HUNGARIAN` * * `DUTCH` * * `NORWEGIAN` * * `POLISH` * * `BRAZILIAN_PORTUGUESE` * * `ROMANIA_ROMANIAN` * * `FINNISH` * * `SWEDISH` * * `VIETNAMESE` * * `TURKISH` * * `CZECH` * * `GREEK` * * `BULGARIAN` * * `RUSSIAN` * * `UKRAINIAN` * * `HINDI` * * `THAI` * * `CHINA_CHINESE` * * `JAPANESE` * * `TAIWAN_CHINESE` * * `KOREAN` * @param {string} value * @returns {locale} */ async setLocale(value) { if (this.client.bot) throw new Error('INVALID_BOT_METHOD'); if (typeof value !== 'string') throw new TypeError('INVALID_TYPE', 'value', 'string', true); if (!localeObject[value]) throw new Error('INVALID_LOCALE'); if (localeObject[value] !== this.locale) { await this.edit({ locale: localeObject[value] }); } return this.locale; } // TODO: Guild positions & folders // Change Index in Array [Hidden] /** * * @param {Array} array Array * @param {Number} from Index1 * @param {Number} to Index2 * @returns {Array} * @private */ _move(array, from, to) { array.splice(to, 0, array.splice(from, 1)[0]); return array; } // TODO: Move Guild // folder to folder // folder to home // home to home // home to folder /** * Change Guild Position (from * to Folder or Home) * @param {GuildIDResolve} guildId guild.id * @param {Number} newPosition Guild Position * * **WARNING**: Type = `FOLDER`, newPosition is the guild's index in the Folder. * @param {number} type Move to folder or home * * `FOLDER`: 1 * * `HOME`: 2 * @param {FolderID} folderId If you want to move to folder * @private */ async guildChangePosition(guildId, newPosition, type, folderId) { // get Guild default position // Escape const oldGuildFolderPosition = this.rawSetting.guild_folders.findIndex( (value) => value.guild_ids.includes(guildId), ); const newGuildFolderPosition = this.rawSetting.guild_folders.findIndex( (value) => value.guild_ids.includes(this.rawSetting.guild_positions[newPosition]), ); if (type == 2 || `${type}`.toUpperCase() == 'HOME') { // Delete GuildID from Folder and create new Folder // Check it is folder const folder = this.rawSetting.guild_folders[oldGuildFolderPosition]; if (folder.id) { this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids = this.rawSetting.guild_folders[ oldGuildFolderPosition ].guild_ids.filter((v) => v !== guildId); } this.rawSetting.guild_folders = this._move( this.rawSetting.guild_folders, oldGuildFolderPosition, newGuildFolderPosition, ); this.rawSetting.guild_folders[newGuildFolderPosition].id = null; } else if (type == 1 || `${type}`.toUpperCase() == 'FOLDER') { // Delete GuildID from oldFolder this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids = this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids.filter( (v) => v !== guildId, ); // Index new Folder const folderIndex = this.rawSetting.guild_folders.findIndex( (value) => value.id == folderId, ); const folder = this.rawSetting.guild_folders[folderIndex]; folder.guild_ids.push(guildId); folder.guild_ids = [...new Set(folder.guild_ids)]; folder.guild_ids = this._move( folder.guild_ids, folder.guild_ids.findIndex((v) => v == guildId), newPosition, ); } this.edit({ guild_folders: this.rawSetting.guild_folders }); } } module.exports = ClientUserSettingManager;