feat: get display name on query (#565)

* feat: get display name on query

* chore: use global_name instead of display_name

* feat: show username on Owner

* chore: remove unused import

* feat: user page

* chore: remove logging

* feat: navbar

* feat: Seo

* feat: logging

* feat: addbot

* feat: security credit

* feat: report

* feat: transfer owner

* feat: seo

* feat: report

* chore: do not get channel from guild

* chore: remove displayname

* chore: remove unused import
This commit is contained in:
SKINMAKER 2023-06-10 22:29:51 +09:00 committed by GitHub
parent e6fc5199bf
commit 5d41ada703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 56 additions and 36 deletions

View File

@ -32,7 +32,7 @@ const Navbar: React.FC<NavbarProps> = ({ token }) => {
if(data.code !== 200) return
setUserCache(JSON.parse(localStorage.userCache = JSON.stringify({
id: data.data.id,
username: data.data.username,
username: data.data.globalName,
tag: data.data.tag,
version: 2
})))

View File

@ -1,7 +1,7 @@
import Link from 'next/link'
import DiscordAvatar from '@components/DiscordAvatar'
const Owner: React.FC<OwnerProps> = ({ id, username, tag, crown=false }) => {
const Owner: React.FC<OwnerProps> = ({ id, globalName, username, tag, crown=false }) => {
return (
<Link href={`/users/${id}`}>
<a className='dark:hover:bg-discord-dark-hover flex mb-1 px-4 py-4 text-black dark:text-gray-400 text-base dark:bg-discord-black bg-little-white hover:bg-little-white-hover rounded cursor-pointer'>
@ -9,9 +9,8 @@ const Owner: React.FC<OwnerProps> = ({ id, username, tag, crown=false }) => {
<DiscordAvatar userID={id} className='z-negative absolute inset-0 w-full h-full' />
</div>
<div className='flex-1 w-0 leading-snug'>
<h4 className='whitespace-nowrap truncate'>{ crown && <i className='fas fa-crown text-yellow-300 text-xs' /> }{username}</h4>
<span className='text-gray-600 text-sm'>#{tag}</span>
<h4 className='whitespace-nowrap truncate'>{ crown && <i className='fas fa-crown text-yellow-300 text-xs' /> }{globalName}</h4>
<span className='text-gray-600 text-sm'>{tag !== '0' ? '#' + tag : '@' + username}</span>
</div>
</a>
</Link>
@ -22,7 +21,8 @@ export default Owner
interface OwnerProps {
id: string
tag: string
username: string
tag: string
globalName: string
crown?: boolean
}

View File

@ -82,7 +82,7 @@ const AddBot:NextPage<AddBotProps> = ({ logged, user, csrfToken, theme }) => {
}} />
<h1 className='text-3xl font-bold'> </h1>
<div className='mt-1 mb-5'>
, <span className='font-semibold'>{user.username}#{user.tag}</span>! <a role='button' tabIndex={0} onKeyDown={toLogin} onClick={toLogin} className='text-discord-blurple cursor-pointer outline-none'> ?</a>
, <span className='font-semibold'>{user.tag === '0' ? `@${user.username}` : `${user.globalName}#${user.tag}`}</span>! <a role='button' tabIndex={0} onKeyDown={toLogin} onClick={toLogin} className='text-discord-blurple cursor-pointer outline-none'> ?</a>
</div>
{
data ? data.code == 200 && data.data ? <Message type='success'>

View File

@ -95,7 +95,7 @@ const Bots = RequestHandler()
embeds: [
new EmbedBuilder()
.setAuthor({
name: `${userinfo.username}#${userinfo.tag}`,
name: userinfo.tag === '0' ? `${userinfo.globalName} (@${userinfo.username})` : `${userinfo.username}#${userinfo.tag}`,
iconURL: KoreanbotsEndPoints.URL.root + KoreanbotsEndPoints.CDN.avatar(userinfo.id, { format: 'png', size: 256 }),
url: KoreanbotsEndPoints.URL.user(userinfo.id)
})

View File

@ -37,7 +37,7 @@ const UserReport = RequestHandler().post(limiter)
})
if(!validated) return
await getReportChannel().send({ content: `Reported by <@${user}> (${user})\nReported **${userInfo.username}**#${userInfo.tag} <@${userInfo.id}> (${userInfo.id})\nCategory ${req.body.category}\nDesc\n\`\`\`${req.body.description}\`\`\``, allowedMentions: { parse: ['users'] }})
await getReportChannel().send({ content: `Reported by <@${user}> (${user})\nReported **${userInfo.tag === '0' ? userInfo.globalName + ' @' + userInfo.username : userInfo.globalName + '#' + userInfo.tag} <@${userInfo.id}> (${userInfo.id})\nCategory ${req.body.category}\nDesc\n\`\`\`${req.body.description}\`\`\``, allowedMentions: { parse: ['users'] }})
return ResponseWrapper(res, { code: 200, message: '성공적으로 처리되었습니다.' })
})

View File

@ -205,7 +205,7 @@ const ManageBotPage:NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme })
<div className='flex flex-wrap'>
{
(values.owners as User[]).map((el, n) => <Tag className='flex items-center' text={<>
<DiscordAvatar userID={el.id} size={128} className='w-6 h-6 mr-1 rounded-full' /> {el.username}#{el.tag}
<DiscordAvatar userID={el.id} size={128} className='w-6 h-6 mr-1 rounded-full' /> {el.tag === '0' ? `${el.globalName} (@${el.username})` : `${el.username}#${el.tag}`}
{
n !== 0 && <button className='ml-0.5 hover:text-red-500' onClick={() => {
setFieldValue('owners', (() => {

View File

@ -210,6 +210,7 @@ const Bots: NextPage<BotsProps> = ({ data, desc, date, user, theme, csrfToken })
key={el.id}
id={el.id}
tag={el.tag}
globalName={el.globalName}
username={el.username}
/>
))}

View File

@ -131,6 +131,7 @@ const PendingBot: NextPage<PendingBotProps> = ({ data }) => {
key={el.id}
id={el.id}
tag={el.tag}
globalName={el.globalName}
username={el.username}
/>
))}

View File

@ -46,7 +46,7 @@ const Security: NextPage<SecurityProps> = ({ bugReports }) => {
bugReports.filter(el=>el).map(u =>
<div key={u.id} className='flex items-center mr-2.5'>
<DiscordAvatar userID={u.id} size={128} className='rounded-full w-6 h-6 mr-1' />
<span className='text-base font-semibold dark:text-gray-300'>{u.username}#{u.tag}</span>
<span className='text-base font-semibold dark:text-gray-300'>{u.globalName} {`(@${u.username})`}</span>
</div>
)
}

View File

@ -229,6 +229,7 @@ const Servers: NextPage<ServersProps> = ({ data, desc, date, user, theme }) => {
key={data.owner.id}
id={data.owner.id}
tag={data.owner.tag}
globalName={data.owner.globalName}
username={data.owner.username}
/>
}
@ -241,6 +242,7 @@ const Servers: NextPage<ServersProps> = ({ data, desc, date, user, theme }) => {
key={el.id}
id={el.id}
tag={el.tag}
globalName={el.globalName}
username={el.username}
crown={el.id === data.owner?.id}
/>

View File

@ -32,8 +32,8 @@ const Users: NextPage<UserProps> = ({ user, data }) => {
return (
<Container paddingTop className='py-10'>
<NextSeo
title={data.username}
description={data.bots.length === 0 ? `${data.username}님의 프로필입니다.` : josa(
title={data.globalName}
description={data.bots.length === 0 ? `${data.globalName}님의 프로필입니다.` : josa(
`${(data.bots as Bot[])
.slice(0, 5)
.map(el => el.name)
@ -58,10 +58,15 @@ const Users: NextPage<UserProps> = ({ user, data }) => {
</div>
<div className='flex-grow px-5 py-10 w-full text-center lg:w-5/12 lg:text-left'>
<div>
<div className='lg:flex mt-3 mb-1 '>
<h1 className='text-4xl font-bold'>{data.username}</h1>
<span className='ml-0.5 text-gray-400 text-3xl font-semibold mt-1'>#{data.tag}</span>
</div>
{
(data.tag !== '0') ? <div className='lg:flex mt-3 mb-1 '>
<h1 className='text-4xl font-bold'>{data.globalName}</h1>
<span className='ml-0.5 text-gray-400 text-3xl font-semibold mt-1'>#{data.tag}</span>
</div> : <div className='lg:flex mt-3 mb-1 flex-col'>
<h1 className='text-4xl font-bold'>{data.globalName}</h1>
<span className='text-gray-400 text-2xl font-semibold mt-1'>@{data.username}</span>
</div>
}
<div className='badges flex mb-2 justify-center lg:justify-start'>
{checkUserFlag(data.flags, 'staff') && (
<Tooltip text='한국 디스코드 리스트 스탭입니다.' direction='left'>

View File

@ -39,9 +39,9 @@ const ReportUser: NextPage<ReportUserProps> = ({ data, user, csrfToken }) => {
</div>
</>
return <Container paddingTop className='py-10'>
<NextSeo title={`${data.username} 신고하기`} />
<NextSeo title={`${data.globalName} 신고하기`} />
<Link href={makeUserURL(data)}>
<a className='text-blue-500 hover:opacity-80'><i className='fas fa-arrow-left mt-3 mb-3' /> <strong>{data.username}</strong>{getJosaPicker('로')(data.username)} </a>
<a className='text-blue-500 hover:opacity-80'><i className='fas fa-arrow-left mt-3 mb-3' /> <strong>{data.globalName}</strong>{getJosaPicker('로')(data.globalName)} </a>
</Link>
{
reportRes?.code === 200 ? <Message type='success'>

View File

@ -77,6 +77,7 @@ export interface User {
avatar: string
tag: string
username: string
globalName: string
flags: number
github: string
bots: Bot[] | string[]

View File

@ -24,11 +24,11 @@ ServerListDiscordBot.login(process.env.DISCORD_SERVERLIST_TOKEN)
export const getMainGuild = () => DiscordBot.guilds.cache.get(process.env.GUILD_ID)
export const getReviewGuild = () => DiscordBot.guilds.cache.get(process.env.REVIEW_GUILD_ID)
export const getReportChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(process.env.REPORT_CHANNEL_ID) as Discord.TextChannel
export const getLoggingChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(process.env.LOGGING_CHANNEL_ID) as Discord.TextChannel
export const getStatsLoggingChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(process.env.STATS_LOGGING_CHANNEL_ID) as Discord.TextChannel
export const getBotReviewLogChannel = (): Discord.TextChannel => getReviewGuild().channels.cache.get(process.env.REVIEW_LOG_CHANNEL_ID) as Discord.TextChannel
export const getOpenBotReviewLogChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(process.env.OPEN_REVIEW_LOG_CHANNEL_ID) as Discord.TextChannel
export const getReportChannel = (): Discord.TextChannel => DiscordBot.channels.cache.get(process.env.REPORT_CHANNEL_ID) as Discord.TextChannel
export const getLoggingChannel = (): Discord.TextChannel => DiscordBot.channels.cache.get(process.env.LOGGING_CHANNEL_ID) as Discord.TextChannel
export const getStatsLoggingChannel = (): Discord.TextChannel => DiscordBot.channels.cache.get(process.env.STATS_LOGGING_CHANNEL_ID) as Discord.TextChannel
export const getBotReviewLogChannel = (): Discord.TextChannel => DiscordBot.channels.cache.get(process.env.REVIEW_LOG_CHANNEL_ID) as Discord.TextChannel
export const getOpenBotReviewLogChannel = (): Discord.TextChannel => DiscordBot.channels.cache.get(process.env.OPEN_REVIEW_LOG_CHANNEL_ID) as Discord.TextChannel
export const discordLog = async (type: string, issuerID: string, embed?: Discord.EmbedBuilder, attachment?: { content: string, format: string}, content?: string): Promise<void> => {
getLoggingChannel().send({

View File

@ -1,7 +1,7 @@
import fetch from 'node-fetch'
import { TLRU } from 'tlru'
import DataLoader from 'dataloader'
import { ActivityType, GuildFeature, GuildMember, User as DiscordUser, UserFlags } from 'discord.js'
import { ActivityType, GuildFeature, GuildMember, User as DiscordUser, APIUser as APIDiscordUser, UserFlags } from 'discord.js'
import { Bot, Server, User, ListType, List, TokenRegister, BotFlags, DiscordUserFlags, SubmittedBot, DiscordTokenInfo, ServerData, ServerFlags, RawGuild, Nullable, Webhook, BotSpec, ServerSpec } from '@types'
import { botCategories, DiscordEnpoints, imageSafeHost, serverCategories, SpecialEndPoints, VOTE_COOLDOWN } from './Constants'
@ -46,19 +46,21 @@ async function getBot(id: string, topLevel=true):Promise<Bot> {
.orWhere({ vanity: id, trusted: true })
.orWhere({ vanity: id, partnered: true })
if (res[0]) {
const discordBot = await DiscordBot.users.fetch(res[0].id).then(r=> r).catch(() => null) as DiscordUser
const discordBot = await get.discord._rawUser.load(res[0].id)
if(!discordBot) return null
const botMember = await getMainGuild()?.members?.fetch(res[0].id).catch(e=> e) as GuildMember
res[0].flags = res[0].flags | (discordBot.flags?.bitfield & DiscordUserFlags.VERIFIED_BOT ? BotFlags.verified : 0) | (res[0].trusted ? BotFlags.trusted : 0) | (res[0].partnered ? BotFlags.partnered : 0)
const name = discordBot.global_name ?? discordBot.username
res[0].flags = res[0].flags | (discordBot.flags & DiscordUserFlags.VERIFIED_BOT ? BotFlags.verified : 0) | (res[0].trusted ? BotFlags.trusted : 0) | (res[0].partnered ? BotFlags.partnered : 0)
res[0].tag = discordBot.discriminator
res[0].avatar = discordBot.avatar
res[0].name = discordBot.username
res[0].name = name
res[0].category = JSON.parse(res[0].category)
res[0].owners = JSON.parse(res[0].owners)
if(botMember) {
if(discordBot.flags.has(UserFlags.BotHTTPInteractions)) {
res[0].status = 'online'
} else if(!botMember.presence) {
if(discordBot.flags & UserFlags.BotHTTPInteractions) {
res[0].status = 'online'
} else if(botMember) {
if(!botMember.presence) {
res[0].status = 'offline'
} else {
res[0].status = botMember.presence.activities.some(r => r.type === ActivityType.Streaming) ? 'streaming' : botMember.presence.status
@ -75,7 +77,7 @@ async function getBot(id: string, topLevel=true):Promise<Bot> {
res[0].owners = res[0].owners.filter((el: User | null) => el).map((row: User) => ({ ...row }))
}
await knex('bots').update({ name: discordBot.username }).where({ id })
await knex('bots').update({ name }).where({ id })
}
@ -153,9 +155,10 @@ async function getUser(id: string, topLevel = true):Promise<User> {
.where('owners', 'like', `%${id}%`)
.orderBy('date', 'asc')
const discordUser = await get.discord.user.load(id)
const discordUser = await get.discord._rawUser.load(id)
res[0].tag = discordUser?.discriminator || '0000'
res[0].username = discordUser?.username || 'Unknown User'
res[0].globalName = discordUser?.global_name || discordUser?.username || 'Unknown User'
if (topLevel) {
res[0].bots = (await Promise.all(ownedBots.map(async b => await get._rawBot.load(b.id)))).filter((el: Bot | null) => el)
res[0].servers = (await Promise.all(ownedServer.map(async b => await get._rawServer.load(b.id)))).filter((el: Server | null) => el)
@ -607,7 +610,10 @@ async function getImage(url: string) {
return await res.buffer()
}
async function getDiscordUser(id: string):Promise<DiscordUser> {
async function getDiscordUser(id: string, raw = false):Promise<APIDiscordUser & { global_name: string } | DiscordUser> {
if(raw) {
return await DiscordBot.rest.get(`/users/${id}`).catch(() => null) as APIDiscordUser & { global_name: string }
}
return await DiscordBot.users.fetch(id, {cache: true}).then(u => u).catch(()=>null)
}
@ -752,7 +758,11 @@ export const get = {
discord: {
user: new DataLoader(
async (ids: string[]) =>
(await Promise.all(ids.map(async (id: string) => await getDiscordUser(id))))
(await Promise.all(ids.map(async (id: string) => await getDiscordUser(id, false) as DiscordUser)))
, { cacheMap: new TLRU({ maxStoreSize: 5000, maxAgeMs: 43200000 }) }),
_rawUser: new DataLoader(
async (ids: string[]) =>
(await Promise.all(ids.map(async (id: string) => await getDiscordUser(id, true) as APIDiscordUser & { global_name: string })))
, { cacheMap: new TLRU({ maxStoreSize: 5000, maxAgeMs: 43200000 }) }),
},
bot: new DataLoader(