diff --git a/components/Form/Label.tsx b/components/Form/Label.tsx index 3e230be..2c24a2e 100644 --- a/components/Form/Label.tsx +++ b/components/Form/Label.tsx @@ -21,7 +21,7 @@ const Label: React.FC = ({ * )} - {labelDesc} + {labelDesc} )}
diff --git a/components/Form/Selects.tsx b/components/Form/Selects.tsx index b4118aa..90b99ff 100644 --- a/components/Form/Selects.tsx +++ b/components/Form/Selects.tsx @@ -109,7 +109,10 @@ const Select: React.FC = ({ onChange={handleChange} onBlur={handleTouch} noOptionsMessage={() => '검색 결과가 없습니다.'} - value={values.map((el) => ({ label: el, value: el }))} + value={values.map((el) => ({ + label: Object.values(options).find(({ value }) => value === el)?.label || el, + value: el, + }))} components={{ MultiValue, MultiValueRemove, diff --git a/pages/addbot.tsx b/pages/addbot.tsx index da86d1c..6935bd5 100644 --- a/pages/addbot.tsx +++ b/pages/addbot.tsx @@ -10,7 +10,7 @@ import HCaptcha from '@hcaptcha/react-hcaptcha' import { get } from '@utils/Query' import { cleanObject, parseCookie, redirectTo } from '@utils/Tools' import { AddBotSubmit, AddBotSubmitSchema } from '@utils/Yup' -import { botCategories, botCategoryDescription, library } from '@utils/Constants' +import { botCategories, botCategoryDescription, botEnforcements, library } from '@utils/Constants' import { getToken } from '@utils/Csrf' import Fetch from '@utils/Fetch' import { ResponseProps, SubmittedBot, Theme, User } from '@types' @@ -57,6 +57,7 @@ const AddBot: NextPage = ({ logged, user, csrfToken, theme }) => { - 어떤 - 기능 - 있나요?`, + enforcements: [], _csrf: csrfToken, _captcha: 'captcha', } @@ -356,6 +357,34 @@ const AddBot: NextPage = ({ logged, user, csrfToken, theme }) => { + +

* = 필수 항목

diff --git a/pages/api/v2/bots/[id]/index.ts b/pages/api/v2/bots/[id]/index.ts index 0804870..c292036 100644 --- a/pages/api/v2/bots/[id]/index.ts +++ b/pages/api/v2/bots/[id]/index.ts @@ -289,6 +289,7 @@ const Bots = RequestHandler() category: JSON.stringify(bot.category), vanity: bot.vanity, banner: bot.banner, + enforcements: JSON.stringify(bot.enforcements), bg: bot.bg, }, { @@ -302,6 +303,7 @@ const Bots = RequestHandler() category: JSON.stringify(validated.category), vanity: validated.vanity, banner: validated.banner, + enforcements: JSON.stringify(validated.enforcements), bg: validated.bg, } ) diff --git a/pages/bots/[id]/edit.tsx b/pages/bots/[id]/edit.tsx index 55bbc2e..0c94bfb 100644 --- a/pages/bots/[id]/edit.tsx +++ b/pages/bots/[id]/edit.tsx @@ -9,9 +9,16 @@ import { ParsedUrlQuery } from 'querystring' import { getJosaPicker } from 'josa' import { get } from '@utils/Query' -import { checkBotFlag, checkUserFlag, cleanObject, makeBotURL, parseCookie, redirectTo } from '@utils/Tools' +import { + checkBotFlag, + checkUserFlag, + cleanObject, + makeBotURL, + parseCookie, + redirectTo, +} from '@utils/Tools' import { ManageBot, getManageBotSchema } from '@utils/Yup' -import { botCategories, botCategoryDescription, library } from '@utils/Constants' +import { botCategories, botCategoryDescription, botEnforcements, library } from '@utils/Constants' import { Bot, Theme, User } from '@types' import { getToken } from '@utils/Csrf' import Fetch from '@utils/Fetch' @@ -71,6 +78,7 @@ const ManageBotPage: NextPage = ({ bot, user, csrfToken, theme } ) return const isPerkAvailable = checkBotFlag(bot.flags, 'trusted') || checkBotFlag(bot.flags, 'partnered') + console.log(bot.enforcements) return ( @@ -82,6 +90,7 @@ const ManageBotPage: NextPage = ({ bot, user, csrfToken, theme } prefix: bot.prefix, library: bot.lib, category: bot.category, + enforcements: bot.enforcements, intro: bot.intro, desc: bot.desc, website: bot.web, @@ -98,8 +107,12 @@ const ManageBotPage: NextPage = ({ bot, user, csrfToken, theme } > {({ errors, touched, values, setFieldTouched, setFieldValue }) => (
-
- +
+

{bot.name}#{bot.tag} @@ -165,7 +178,11 @@ const ManageBotPage: NextPage = ({ bot, user, csrfToken, theme } error={errors.category && touched.category ? (errors.category as string) : null} > ({ label: el, value: el, description: botCategoryDescription[el] }))} + options={botCategories.map((el) => ({ + label: el, + value: el, + description: botCategoryDescription[el], + }))} handleChange={(value) => { setFieldValue( 'category', @@ -273,24 +290,26 @@ const ManageBotPage: NextPage = ({ bot, user, csrfToken, theme } - { - isPerkAvailable && ( - <> + {isPerkAvailable && ( + <> -

신뢰된 봇 특전 설정

- 신뢰된 봇의 혜택을 만나보세요. (커스텀 URL과 배너/배경 이미지는 이용약관 및 가이드라인을 준수해야하며 위반 시 신뢰된 봇 자격이 박탈될 수 있습니다.) +

+ 신뢰된 봇 특전 설정 +

+ + 신뢰된 봇의 혜택을 만나보세요. (커스텀 URL과 배너/배경 이미지는 이용약관 및 + 가이드라인을 준수해야하며 위반 시 신뢰된 봇 자격이 박탈될 수 있습니다.) + - - ) - } + + )} + +

* = 필수 항목 @@ -320,7 +366,6 @@ const ManageBotPage: NextPage = ({ bot, user, csrfToken, theme } 저장 - )} diff --git a/types/index.ts b/types/index.ts index a8d7295..fc6171b 100644 --- a/types/index.ts +++ b/types/index.ts @@ -1,3 +1,4 @@ +import { botEnforcements } from '@utils/Constants' import type { GuildFeature } from 'discord.js' import type { IncomingMessage } from 'http' import type { NextPageContext } from 'next' @@ -25,11 +26,14 @@ export interface Bot { url: string | null discord: string | null vanity: string | null + enforcements: BotEnforcementKeys[] bg: string banner: string owners: User[] | string[] } +export type BotEnforcementKeys = 'JOIN_ENFORCED' | 'JOIN_PARTIALLY_ENFORCED' + export interface RawGuild { id: string name: string diff --git a/utils/Constants.ts b/utils/Constants.ts index 2460d14..017d669 100644 --- a/utils/Constants.ts +++ b/utils/Constants.ts @@ -120,6 +120,11 @@ export const botCategoryDescription = { 마인크래프트: '게임 "마인크래프트"에 관련된 기능을 다룹니다.', } +export const botEnforcements = { + '서버 참여가 강제되는 명령어가 있습니다': 'JOIN_PARTIALLY_ENFORCED', + '서버 참여 없이는 봇을 사용할 수 없습니다': 'JOIN_ENFORCED', +} + export const botCategoryIcon = { 관리: 'fas fa-cogs', 뮤직: 'fas fa-music', diff --git a/utils/Query.ts b/utils/Query.ts index 07a49cc..9bf6ab3 100644 --- a/utils/Query.ts +++ b/utils/Query.ts @@ -62,6 +62,7 @@ async function getBot(id: string, topLevel = true): Promise { 'bots.status', 'bots.trusted', 'bots.partnered', + 'bots.enforcements', 'bots.discord', 'bots.state', 'bots.vanity', @@ -102,7 +103,7 @@ async function getBot(id: string, topLevel = true): Promise { res.owners = JSON.parse(res.owners) res.banner = res.banner ? camoUrl(res.banner) : null res.bg = res.bg ? camoUrl(res.bg) : null - + res.enforcements = JSON.parse(res.enforcements ?? '"[]"') if (discordBot.flags.bitfield & UserFlags.BotHTTPInteractions) { res.status = 'online' } else if (botMember) { @@ -448,6 +449,7 @@ async function getBotSubmit(id: string, date: number): Promise { 'id', 'date', 'category', + 'enforcements', 'lib', 'prefix', 'intro', @@ -463,6 +465,7 @@ async function getBotSubmit(id: string, date: number): Promise { .where({ id, date }) if (res.length === 0) return null res[0].category = JSON.parse(res[0].category) + res[0].enforcements = JSON.parse(res[0].enforcements || '"[]"') res[0].owner = await get.user.load(res[0].owner) return res[0] } @@ -474,6 +477,7 @@ async function getBotSubmits(id: string): Promise { 'id', 'date', 'category', + 'enforcements', 'lib', 'prefix', 'intro', @@ -492,6 +496,7 @@ async function getBotSubmits(id: string): Promise { res = await Promise.all( res.map(async (el) => { el.category = JSON.parse(el.category) + el.enforcements = JSON.parse(el.enforcements) el.owner = owner return el }) @@ -636,6 +641,7 @@ async function submitBot( git: data.git, url: data.url, category: JSON.stringify(data.category), + enforcements: JSON.stringify(data.enforcements), discord: data.discord, state: 0, }) @@ -745,6 +751,7 @@ async function updateBot(id: string, data: ManageBot): Promise { intro: data.intro, desc: data.desc, vanity: data.vanity, + enforcements: JSON.stringify(data.enforcements), banner: data.banner, bg: data.bg, }) @@ -1134,6 +1141,7 @@ async function approveBotSubmission(id: string, date: number) { 'id', 'date', 'category', + 'enforcements', 'lib', 'prefix', 'intro', @@ -1160,6 +1168,7 @@ async function approveBotSubmission(id: string, date: number) { web: data.web, git: data.git, category: data.category, + enforcements: data.enforcements, discord: data.discord, token: sign({ id }), }) diff --git a/utils/Yup.ts b/utils/Yup.ts index 91d984c..2d314bf 100644 --- a/utils/Yup.ts +++ b/utils/Yup.ts @@ -3,6 +3,7 @@ import YupKorean from 'yup-locales-ko' import { ListType } from '@types' import { botCategories, + botEnforcements, library, reportCats, reservedVanityBypass, @@ -174,6 +175,7 @@ export const AddBotSubmitSchema: Yup.SchemaOf = Yup.object({ .min(100, '봇 설명은 최소 100자여야합니다.') .max(1500, '봇 설명은 최대 1500자여야합니다.') .required('봇 설명은 필수 항목입니다.'), + enforcements: Yup.array(Yup.string().oneOf(Object.values(botEnforcements))), _csrf: Yup.string().required(), _captcha: Yup.string().required(), }) @@ -190,6 +192,7 @@ export interface AddBotSubmit { category: string | string[] intro: string desc: string + enforcements: string[] _csrf: string _captcha: string } @@ -303,6 +306,7 @@ export function getManageBotSchema(perkAvailable = false) { .min(100, '봇 설명은 최소 100자여야합니다.') .max(1500, '봇 설명은 최대 1500자여야합니다.') .required('봇 설명은 필수 항목입니다.'), + enforcements: Yup.array(Yup.string().oneOf(Object.values(botEnforcements))), _csrf: Yup.string().required(), } @@ -349,6 +353,7 @@ export interface ManageBot { desc: string vanity: string banner: string + enforcements: string[] bg: string _csrf: string }