From 224c28f29dda85aba6172f95554505c8cfb61607 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Talbot?=
<108630700+fetchfern@users.noreply.github.com>
Date: Mon, 27 Jul 2026 15:20:38 -0400
Subject: [PATCH] feat: more details linked account info for support/moderation
(#6897)
* feat: show discord + steam ID + github profile in "Show details" user modal
* pnpm intl:extract
---
apps/frontend/src/locales/en-US/index.json | 15 +++
apps/frontend/src/pages/user/[user].vue | 106 +++++++++++++++++-
apps/labrinth/src/models/v2/user.rs | 1 -
apps/labrinth/src/models/v3/users.rs | 9 +-
apps/labrinth/src/routes/v3/users.rs | 10 +-
.../api-client/src/modules/labrinth/types.ts | 2 +
6 files changed, 139 insertions(+), 4 deletions(-)
diff --git a/apps/frontend/src/locales/en-US/index.json b/apps/frontend/src/locales/en-US/index.json
index 9f6ce185b..49b279eb2 100644
--- a/apps/frontend/src/locales/en-US/index.json
+++ b/apps/frontend/src/locales/en-US/index.json
@@ -3374,6 +3374,15 @@
"profile.collection.projects-count": {
"message": "{count, plural, one {# project} other {# projects}}"
},
+ "profile.details.error.github-popup-blocked": {
+ "message": "Allow pop-ups for Modrinth, then try again."
+ },
+ "profile.details.error.github-profile-message": {
+ "message": "The GitHub profile could not be retrieved. Please try again."
+ },
+ "profile.details.error.github-profile-title": {
+ "message": "Unable to open GitHub profile"
+ },
"profile.details.label.auth-providers": {
"message": "Auth providers"
},
@@ -3389,9 +3398,15 @@
"profile.details.label.has-totp": {
"message": "Has TOTP"
},
+ "profile.details.label.loading-github-profile": {
+ "message": "Loading..."
+ },
"profile.details.label.payment-methods": {
"message": "Payment methods"
},
+ "profile.details.label.view-github-profile": {
+ "message": "View profile"
+ },
"profile.details.tooltip.email-not-verified": {
"message": "Email not verified"
},
diff --git a/apps/frontend/src/pages/user/[user].vue b/apps/frontend/src/pages/user/[user].vue
index 4ebf1e763..0a86596ec 100644
--- a/apps/frontend/src/pages/user/[user].vue
+++ b/apps/frontend/src/pages/user/[user].vue
@@ -71,7 +71,37 @@
{{
formatMessage(messages.authProvidersLabel)
}}
- {{ user.auth_providers.join(', ') }}
+
+
+ {{ authProviderNames[provider] ?? provider }}
+
+ ({{ user.discord_id }})
+
+
+ (
+
+ )
+
+
+ ({{ user.steam_id }})
+
+
+
@@ -437,6 +467,26 @@ const messages = defineMessages({
id: 'profile.details.label.auth-providers',
defaultMessage: 'Auth providers',
},
+ viewGithubProfileLabel: {
+ id: 'profile.details.label.view-github-profile',
+ defaultMessage: 'View profile',
+ },
+ loadingGithubProfileLabel: {
+ id: 'profile.details.label.loading-github-profile',
+ defaultMessage: 'Loading...',
+ },
+ githubProfileErrorTitle: {
+ id: 'profile.details.error.github-profile-title',
+ defaultMessage: 'Unable to open GitHub profile',
+ },
+ githubProfileErrorMessage: {
+ id: 'profile.details.error.github-profile-message',
+ defaultMessage: 'The GitHub profile could not be retrieved. Please try again.',
+ },
+ githubPopupBlockedMessage: {
+ id: 'profile.details.error.github-popup-blocked',
+ defaultMessage: 'Allow pop-ups for Modrinth, then try again.',
+ },
paymentMethodsLabel: {
id: 'profile.details.label.payment-methods',
defaultMessage: 'Payment methods',
@@ -518,6 +568,16 @@ const messages = defineMessages({
const client = injectModrinthClient()
const userId = useRouteId('user')
+const authProviderNames = {
+ github: 'GitHub',
+ discord: 'Discord',
+ microsoft: 'Microsoft',
+ gitlab: 'GitLab',
+ google: 'Google',
+ steam: 'Steam',
+ paypal: 'PayPal',
+}
+const isLoadingGithubProfile = ref(false)
const {
data: user,
@@ -664,6 +724,50 @@ async function copyPermalink() {
await navigator.clipboard.writeText(`${config.public.siteUrl}/user/${user.value.id}`)
}
+async function openGithubProfile() {
+ const githubId = user.value?.github_id
+ if (!githubId || isLoadingGithubProfile.value) return
+
+ const profileWindow = window.open('about:blank', '_blank')
+ if (!profileWindow) {
+ addNotification({
+ type: 'error',
+ title: formatMessage(messages.githubProfileErrorTitle),
+ message: formatMessage(messages.githubPopupBlockedMessage),
+ })
+ return
+ }
+
+ profileWindow.opener = null
+ isLoadingGithubProfile.value = true
+
+ try {
+ const githubUser = await client.request(`/${githubId}`, {
+ api: 'https://api.github.com',
+ version: 'user',
+ method: 'GET',
+ headers: { 'Content-Type': '' },
+ skipAuth: true,
+ })
+
+ if (!githubUser?.login) {
+ throw new Error('GitHub user response did not include a login')
+ }
+
+ profileWindow.location.replace(`https://github.com/${encodeURIComponent(githubUser.login)}`)
+ } catch (error) {
+ profileWindow.close()
+ console.error('Failed to retrieve GitHub profile:', error)
+ addNotification({
+ type: 'error',
+ title: formatMessage(messages.githubProfileErrorTitle),
+ message: formatMessage(messages.githubProfileErrorMessage),
+ })
+ } finally {
+ isLoadingGithubProfile.value = false
+ }
+}
+
function reportProfileFromHeader() {
if (!user.value) return
if (auth.value.user) {
diff --git a/apps/labrinth/src/models/v2/user.rs b/apps/labrinth/src/models/v2/user.rs
index d8fae78f3..35622abf8 100644
--- a/apps/labrinth/src/models/v2/user.rs
+++ b/apps/labrinth/src/models/v2/user.rs
@@ -24,7 +24,6 @@ pub struct LegacyUser {
pub has_totp: Option,
pub payout_data: Option, // this was changed in v3, but not ones we want to keep out of v2
- // DEPRECATED. Always returns None
pub github_id: Option,
}
diff --git a/apps/labrinth/src/models/v3/users.rs b/apps/labrinth/src/models/v3/users.rs
index 456faa87e..fe5de4c18 100644
--- a/apps/labrinth/src/models/v3/users.rs
+++ b/apps/labrinth/src/models/v3/users.rs
@@ -70,8 +70,11 @@ pub struct User {
#[serde(skip_serializing_if = "Option::is_none")]
pub moderation_notes: Option