From a6c09bc9099832c88a83939bee776fc7d21f1f06 Mon Sep 17 00:00:00 2001 From: dolfies Date: Fri, 3 May 2024 18:21:02 -0400 Subject: [PATCH] feat(ValidUser): also display badges & banner (#2235) Co-authored-by: V --- src/plugins/validUser/index.tsx | 72 +++++++++++++++++++++++++++++++-- src/webpack/common/utils.ts | 3 +- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/plugins/validUser/index.tsx b/src/plugins/validUser/index.tsx index 2fce693e..7a21ac86 100644 --- a/src/plugins/validUser/index.tsx +++ b/src/plugins/validUser/index.tsx @@ -21,12 +21,37 @@ import { Devs } from "@utils/constants"; import { sleep } from "@utils/misc"; import { Queue } from "@utils/Queue"; import definePlugin from "@utils/types"; -import { UserStore, UserUtils, useState } from "@webpack/common"; +import { Constants, FluxDispatcher, RestAPI, UserProfileStore, UserStore, useState } from "@webpack/common"; import type { ComponentType, ReactNode } from "react"; +// LYING to the type checker here +const UserFlags = Constants.UserFlags as Record; +const badges: Record = { + "active_developer": { id: "active_developer", description: "Active Developer", icon: "6bdc42827a38498929a4920da12695d9", link: "https://support-dev.discord.com/hc/en-us/articles/10113997751447" }, + "bug_hunter_level_1": { id: "bug_hunter_level_1", description: "Discord Bug Hunter", icon: "2717692c7dca7289b35297368a940dd0", link: "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" }, + "bug_hunter_level_2": { id: "bug_hunter_level_2", description: "Discord Bug Hunter", icon: "848f79194d4be5ff5f81505cbd0ce1e6", link: "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" }, + "certified_moderator": { id: "certified_moderator", description: "Moderator Programs Alumni", icon: "fee1624003e2fee35cb398e125dc479b", link: "https://discord.com/safety" }, + "discord_employee": { id: "staff", description: "Discord Staff", icon: "5e74e9b61934fc1f67c65515d1f7e60d", link: "https://discord.com/company" }, + "hypesquad": { id: "hypesquad", description: "HypeSquad Events", icon: "bf01d1073931f921909045f3a39fd264", link: "https://discord.com/hypesquad" }, + "hypesquad_online_house_1": { id: "hypesquad_house_1", description: "HypeSquad Bravery", icon: "8a88d63823d8a71cd5e390baa45efa02", link: "https://discord.com/settings/hypesquad-online" }, + "hypesquad_online_house_2": { id: "hypesquad_house_2", description: "HypeSquad Brilliance", icon: "011940fd013da3f7fb926e4a1cd2e618", link: "https://discord.com/settings/hypesquad-online" }, + "hypesquad_online_house_3": { id: "hypesquad_house_3", description: "HypeSquad Balance", icon: "3aa41de486fa12454c3761e8e223442e", link: "https://discord.com/settings/hypesquad-online" }, + "partner": { id: "partner", description: "Partnered Server Owner", icon: "3f9748e53446a137a052f3454e2de41e", link: "https://discord.com/partners" }, + "premium": { id: "premium", description: "Subscriber", icon: "2ba85e8026a8614b640c2837bcdfe21b", link: "https://discord.com/settings/premium" }, + "premium_early_supporter": { id: "early_supporter", description: "Early Supporter", icon: "7060786766c9c840eb3019e725d2b358", link: "https://discord.com/settings/premium" }, + "verified_developer": { id: "verified_developer", description: "Early Verified Bot Developer", icon: "6df5892e0f35b051f8b61eace34f4967" }, +}; + const fetching = new Set(); const queue = new Queue(5); +interface ProfileBadge { + id: string; + description: string; + icon: string; + link?: string; +} + interface MentionProps { data: { userId?: string; @@ -43,6 +68,45 @@ interface MentionProps { UserMention: ComponentType; } +async function getUser(id: string) { + let userObj = UserStore.getUser(id); + if (userObj) + return userObj; + + const user: any = await RestAPI.get({ url: `/users/${id}` }).then(response => { + FluxDispatcher.dispatch({ + type: "USER_UPDATE", + user: response.body, + }); + + return response.body; + }); + + // Populate the profile + await FluxDispatcher.dispatch( + { + type: "USER_PROFILE_FETCH_FAILURE", + userId: id, + } + ); + + userObj = UserStore.getUser(id); + const fakeBadges: ProfileBadge[] = Object.entries(UserFlags) + .filter(([_, flag]) => !isNaN(flag) && userObj.hasFlag(flag)) + .map(([key]) => badges[key.toLowerCase()]); + if (user.premium_type || !user.bot && (user.banner || user.avatar?.startsWith?.("a_"))) + fakeBadges.push(badges.premium); + + // Fill in what we can deduce + const profile = UserProfileStore.getUserProfile(id); + profile.accentColor = user.accent_color; + profile.badges = fakeBadges; + profile.banner = user.banner; + profile.premiumType = user.premium_type; + + return userObj; +} + function MentionWrapper({ data, UserMention, RoleMention, parse, props }: MentionProps) { const [userId, setUserId] = useState(data.userId); @@ -85,14 +149,14 @@ function MentionWrapper({ data, UserMention, RoleMention, parse, props }: Mentio fetching.add(id); queue.unshift(() => - UserUtils.getUser(id) + getUser(id) .then(() => { setUserId(id); fetching.delete(id); }) .catch(e => { if (e?.status === 429) { - queue.unshift(() => sleep(1000).then(fetch)); + queue.unshift(() => sleep(e?.body?.retry_after ?? 1000).then(fetch)); fetching.delete(id); } }) @@ -112,7 +176,7 @@ function MentionWrapper({ data, UserMention, RoleMention, parse, props }: Mentio export default definePlugin({ name: "ValidUser", description: "Fix mentions for unknown users showing up as '@unknown-user' (hover over a mention to fix it)", - authors: [Devs.Ven], + authors: [Devs.Ven, Devs.Dolfies], tags: ["MentionCacheFix"], patches: [ diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index f5d30cd7..6d74e9b2 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -23,7 +23,6 @@ import { _resolveReady, filters, findByCodeLazy, findByProps, findByPropsLazy, f import type * as t from "./types/utils"; export let FluxDispatcher: t.FluxDispatcher; - waitFor(["dispatch", "subscribe"], m => { FluxDispatcher = m; // Non import call to avoid circular dependency @@ -40,6 +39,8 @@ export let ComponentDispatch; waitFor(["ComponentDispatch", "ComponentDispatcher"], m => ComponentDispatch = m.ComponentDispatch); +export const Constants = findByPropsLazy("Endpoints"); + export const RestAPI: t.RestAPI = proxyLazyWebpack(() => { const mod = findByProps("getAPIBaseURL"); return mod.HTTP ?? mod;