mirror of
https://github.com/koreanbots/core.git
synced 2025-12-15 06:10:22 +00:00
feat: 강제사항 명시 (#687)
* feat: add enforcements field * feat: add alert page * chore: specify enforcement description * fix: do not send vanity log when no changes are made * chore: add license related enforcements * fix: typo * refactor: make botEnforcements more maintainable * refactor: do not filter keys to display enforcements * fix: typo
This commit is contained in:
parent
843e4137cb
commit
218e7909b3
@ -21,7 +21,7 @@ const Label: React.FC<LabelProps> = ({
|
|||||||
<span className='align-text-top text-base font-semibold text-red-500'> *</span>
|
<span className='align-text-top text-base font-semibold text-red-500'> *</span>
|
||||||
)}
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
{labelDesc}
|
<span className='whitespace-pre-line'>{labelDesc}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={short ? 'col-span-1' : 'col-span-3'}>
|
<div className={short ? 'col-span-1' : 'col-span-3'}>
|
||||||
|
|||||||
@ -109,7 +109,10 @@ const Select: React.FC<SelectProps> = ({
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={handleTouch}
|
onBlur={handleTouch}
|
||||||
noOptionsMessage={() => '검색 결과가 없습니다.'}
|
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={{
|
components={{
|
||||||
MultiValue,
|
MultiValue,
|
||||||
MultiValueRemove,
|
MultiValueRemove,
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import HCaptcha from '@hcaptcha/react-hcaptcha'
|
|||||||
import { get } from '@utils/Query'
|
import { get } from '@utils/Query'
|
||||||
import { cleanObject, parseCookie, redirectTo } from '@utils/Tools'
|
import { cleanObject, parseCookie, redirectTo } from '@utils/Tools'
|
||||||
import { AddBotSubmit, AddBotSubmitSchema } from '@utils/Yup'
|
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 { getToken } from '@utils/Csrf'
|
||||||
import Fetch from '@utils/Fetch'
|
import Fetch from '@utils/Fetch'
|
||||||
import { ResponseProps, SubmittedBot, Theme, User } from '@types'
|
import { ResponseProps, SubmittedBot, Theme, User } from '@types'
|
||||||
@ -57,6 +57,7 @@ const AddBot: NextPage<AddBotProps> = ({ logged, user, csrfToken, theme }) => {
|
|||||||
- 어떤
|
- 어떤
|
||||||
- 기능
|
- 기능
|
||||||
- 있나요?`,
|
- 있나요?`,
|
||||||
|
enforcements: [],
|
||||||
_csrf: csrfToken,
|
_csrf: csrfToken,
|
||||||
_captcha: 'captcha',
|
_captcha: 'captcha',
|
||||||
}
|
}
|
||||||
@ -356,6 +357,34 @@ const AddBot: NextPage<AddBotProps> = ({ logged, user, csrfToken, theme }) => {
|
|||||||
</Segment>
|
</Segment>
|
||||||
</Label>
|
</Label>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
<Label
|
||||||
|
For='enforcements'
|
||||||
|
label='필수 고지 내용'
|
||||||
|
labelDesc='내용에 해당하는 경우 필수로 선택해야 합니다.'
|
||||||
|
required
|
||||||
|
error={
|
||||||
|
errors.enforcements && touched.enforcements ? (errors.enforcements as string) : null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Selects
|
||||||
|
options={Object.entries(botEnforcements).map(([k, v]) => ({
|
||||||
|
label: v.label,
|
||||||
|
value: k,
|
||||||
|
}))}
|
||||||
|
handleChange={(value) => {
|
||||||
|
setFieldValue(
|
||||||
|
'enforcements',
|
||||||
|
value.map((v) => v.value)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
handleTouch={() => setFieldTouched('enforcements', true)}
|
||||||
|
values={values.enforcements ?? ([] as string[])}
|
||||||
|
setValues={(value) => {
|
||||||
|
setFieldValue('enforcements', value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Label>
|
||||||
|
<Divider />
|
||||||
<p className='mb-5 mt-2 text-base'>
|
<p className='mb-5 mt-2 text-base'>
|
||||||
<span className='font-semibold text-red-500'> *</span> = 필수 항목
|
<span className='font-semibold text-red-500'> *</span> = 필수 항목
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -246,28 +246,29 @@ const Bots = RequestHandler()
|
|||||||
errors: ['다른 커스텀 URL로 다시 시도해주세요.'],
|
errors: ['다른 커스텀 URL로 다시 시도해주세요.'],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (validated.vanity !== bot.vanity) {
|
||||||
await webhookClients.internal.noticeLog.send({
|
await webhookClients.internal.noticeLog.send({
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
title: '한디리 커스텀 URL 변경',
|
title: '한디리 커스텀 URL 변경',
|
||||||
description: `봇: ${bot.name} - <@${bot.id}> ([${bot.id}](${KoreanbotsEndPoints.URL.bot(
|
description: `봇: ${bot.name} - <@${bot.id}> ([${
|
||||||
bot.id
|
bot.id
|
||||||
)}))`,
|
}](${KoreanbotsEndPoints.URL.bot(bot.id)}))`,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: '이전',
|
name: '이전',
|
||||||
value: bot.vanity || '없음',
|
value: bot.vanity || '없음',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '이후',
|
name: '이후',
|
||||||
value: validated.vanity || '없음',
|
value: validated.vanity || '없음',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
color: Colors.Blue,
|
color: Colors.Blue,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const result = await update.bot(req.query.id, validated)
|
const result = await update.bot(req.query.id, validated)
|
||||||
if (result === 0) return ResponseWrapper(res, { code: 400 })
|
if (result === 0) return ResponseWrapper(res, { code: 400 })
|
||||||
@ -289,6 +290,7 @@ const Bots = RequestHandler()
|
|||||||
category: JSON.stringify(bot.category),
|
category: JSON.stringify(bot.category),
|
||||||
vanity: bot.vanity,
|
vanity: bot.vanity,
|
||||||
banner: bot.banner,
|
banner: bot.banner,
|
||||||
|
enforcements: JSON.stringify(bot.enforcements),
|
||||||
bg: bot.bg,
|
bg: bot.bg,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -302,6 +304,7 @@ const Bots = RequestHandler()
|
|||||||
category: JSON.stringify(validated.category),
|
category: JSON.stringify(validated.category),
|
||||||
vanity: validated.vanity,
|
vanity: validated.vanity,
|
||||||
banner: validated.banner,
|
banner: validated.banner,
|
||||||
|
enforcements: JSON.stringify(validated.enforcements),
|
||||||
bg: validated.bg,
|
bg: validated.bg,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@ -9,9 +9,16 @@ import { ParsedUrlQuery } from 'querystring'
|
|||||||
import { getJosaPicker } from 'josa'
|
import { getJosaPicker } from 'josa'
|
||||||
|
|
||||||
import { get } from '@utils/Query'
|
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 { 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 { Bot, Theme, User } from '@types'
|
||||||
import { getToken } from '@utils/Csrf'
|
import { getToken } from '@utils/Csrf'
|
||||||
import Fetch from '@utils/Fetch'
|
import Fetch from '@utils/Fetch'
|
||||||
@ -82,6 +89,7 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
|
|||||||
prefix: bot.prefix,
|
prefix: bot.prefix,
|
||||||
library: bot.lib,
|
library: bot.lib,
|
||||||
category: bot.category,
|
category: bot.category,
|
||||||
|
enforcements: bot.enforcements,
|
||||||
intro: bot.intro,
|
intro: bot.intro,
|
||||||
desc: bot.desc,
|
desc: bot.desc,
|
||||||
website: bot.web,
|
website: bot.web,
|
||||||
@ -98,8 +106,12 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
|
|||||||
>
|
>
|
||||||
{({ errors, touched, values, setFieldTouched, setFieldValue }) => (
|
{({ errors, touched, values, setFieldTouched, setFieldValue }) => (
|
||||||
<Form>
|
<Form>
|
||||||
<div className='text-center md:flex md:text-left'>
|
<div className='text-ceznter md:flex md:text-left'>
|
||||||
<DiscordAvatar userID={bot.id} className='mx-auto rounded-full md:mx-1' hash={bot.avatar}/>
|
<DiscordAvatar
|
||||||
|
userID={bot.id}
|
||||||
|
className='mx-auto rounded-full md:mx-1'
|
||||||
|
hash={bot.avatar}
|
||||||
|
/>
|
||||||
<div className='px-8 py-6 md:w-2/3'>
|
<div className='px-8 py-6 md:w-2/3'>
|
||||||
<h1 className='text-3xl font-bold'>
|
<h1 className='text-3xl font-bold'>
|
||||||
{bot.name}#{bot.tag}
|
{bot.name}#{bot.tag}
|
||||||
@ -165,7 +177,11 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
|
|||||||
error={errors.category && touched.category ? (errors.category as string) : null}
|
error={errors.category && touched.category ? (errors.category as string) : null}
|
||||||
>
|
>
|
||||||
<Selects
|
<Selects
|
||||||
options={botCategories.map((el) => ({ label: el, value: el, description: botCategoryDescription[el] }))}
|
options={botCategories.map((el) => ({
|
||||||
|
label: el,
|
||||||
|
value: el,
|
||||||
|
description: botCategoryDescription[el],
|
||||||
|
}))}
|
||||||
handleChange={(value) => {
|
handleChange={(value) => {
|
||||||
setFieldValue(
|
setFieldValue(
|
||||||
'category',
|
'category',
|
||||||
@ -273,24 +289,26 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
|
|||||||
<Markdown text={values.desc} />
|
<Markdown text={values.desc} />
|
||||||
</Segment>
|
</Segment>
|
||||||
</Label>
|
</Label>
|
||||||
{
|
{isPerkAvailable && (
|
||||||
isPerkAvailable && (
|
<>
|
||||||
<>
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<h2 className='pt-2 text-2xl font-semibold text-koreanbots-green'>신뢰된 봇 특전 설정</h2>
|
<h2 className='pt-2 text-2xl font-semibold text-koreanbots-green'>
|
||||||
<span className='mt-1 text-sm text-gray-400'>신뢰된 봇의 혜택을 만나보세요. (커스텀 URL과 배너/배경 이미지는 이용약관 및 가이드라인을 준수해야하며 위반 시 신뢰된 봇 자격이 박탈될 수 있습니다.)</span>
|
신뢰된 봇 특전 설정
|
||||||
|
</h2>
|
||||||
|
<span className='mt-1 text-sm text-gray-400'>
|
||||||
|
신뢰된 봇의 혜택을 만나보세요. (커스텀 URL과 배너/배경 이미지는 이용약관 및
|
||||||
|
가이드라인을 준수해야하며 위반 시 신뢰된 봇 자격이 박탈될 수 있습니다.)
|
||||||
|
</span>
|
||||||
<Label
|
<Label
|
||||||
For='vanity'
|
For='vanity'
|
||||||
label='한디리 커스텀 URL'
|
label='한디리 커스텀 URL'
|
||||||
labelDesc='고유한 커스텀 URL을 설정해주세요.'
|
labelDesc='고유한 커스텀 URL을 설정해주세요.'
|
||||||
error={errors.vanity && touched.vanity ? errors.vanity : null}
|
error={errors.vanity && touched.vanity ? errors.vanity : null}
|
||||||
|
|
||||||
>
|
>
|
||||||
<div className='flex items-center'>
|
<div className='flex items-center'>
|
||||||
koreanbots.dev/bots/
|
koreanbots.dev/bots/
|
||||||
<Input name='vanity' placeholder='koreanbots' />
|
<Input name='vanity' placeholder='koreanbots' />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</Label>
|
</Label>
|
||||||
<Label
|
<Label
|
||||||
For='banner'
|
For='banner'
|
||||||
@ -308,9 +326,36 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
|
|||||||
>
|
>
|
||||||
<Input name='bg' placeholder='https://koreanbots.dev/logo.png' />
|
<Input name='bg' placeholder='https://koreanbots.dev/logo.png' />
|
||||||
</Label>
|
</Label>
|
||||||
</>
|
</>
|
||||||
)
|
)}
|
||||||
}
|
<Divider />
|
||||||
|
<Label
|
||||||
|
For='enforcements'
|
||||||
|
label='필수 고지 내용'
|
||||||
|
labelDesc='내용에 해당하는 경우 필수로 선택해야 합니다.'
|
||||||
|
required
|
||||||
|
error={
|
||||||
|
errors.enforcements && touched.enforcements ? (errors.enforcements as string) : null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Selects
|
||||||
|
options={Object.entries(botEnforcements).map(([k, v]) => ({
|
||||||
|
label: v.label,
|
||||||
|
value: k,
|
||||||
|
}))}
|
||||||
|
handleChange={(value) => {
|
||||||
|
setFieldValue(
|
||||||
|
'enforcements',
|
||||||
|
value.map((v) => v.value)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
handleTouch={() => setFieldTouched('enforcements', true)}
|
||||||
|
values={values.enforcements ?? ([] as string[])}
|
||||||
|
setValues={(value) => {
|
||||||
|
setFieldValue('enforcements', value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Label>
|
||||||
<Divider />
|
<Divider />
|
||||||
<p className='mb-5 mt-2 text-base'>
|
<p className='mb-5 mt-2 text-base'>
|
||||||
<span className='font-semibold text-red-500'> *</span> = 필수 항목
|
<span className='font-semibold text-red-500'> *</span> = 필수 항목
|
||||||
@ -320,7 +365,6 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
|
|||||||
<i className='far fa-save' /> 저장
|
<i className='far fa-save' /> 저장
|
||||||
</>
|
</>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { SnowflakeUtil } from 'discord.js'
|
|||||||
import { ParsedUrlQuery } from 'querystring'
|
import { ParsedUrlQuery } from 'querystring'
|
||||||
import { Bot, ResponseProps, Theme, User } from '@types'
|
import { Bot, ResponseProps, Theme, User } from '@types'
|
||||||
|
|
||||||
import { git, KoreanbotsEndPoints, reportCats, Status } from '@utils/Constants'
|
import { botEnforcements, git, KoreanbotsEndPoints, reportCats, Status } from '@utils/Constants'
|
||||||
import { get } from '@utils/Query'
|
import { get } from '@utils/Query'
|
||||||
import Day from '@utils/Day'
|
import Day from '@utils/Day'
|
||||||
import { ReportSchema } from '@utils/Yup'
|
import { ReportSchema } from '@utils/Yup'
|
||||||
@ -116,13 +116,27 @@ const Bots: NextPage<BotsProps> = ({ data, desc, date, user, theme, csrfToken })
|
|||||||
로 문의해주세요.
|
로 문의해주세요.
|
||||||
</p>
|
</p>
|
||||||
</Message>
|
</Message>
|
||||||
|
) : data.enforcements.length > 0 ? (
|
||||||
|
<Message type='warning'>
|
||||||
|
<h2 className='text-lg font-extrabold'>이 봇은 기능에 제한을 두고 있습니다.</h2>
|
||||||
|
<p>
|
||||||
|
{data.enforcements.map((i) => (
|
||||||
|
<li key={i}>{botEnforcements[i].description}</li>
|
||||||
|
))}
|
||||||
|
</p>
|
||||||
|
</Message>
|
||||||
) : (
|
) : (
|
||||||
''
|
''
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className='w-full lg:flex'>
|
<div className='w-full lg:flex'>
|
||||||
<div className='w-full text-center lg:w-2/12'>
|
<div className='w-full text-center lg:w-2/12'>
|
||||||
<DiscordAvatar userID={data.id} size={256} className='w-full rounded-full' hash={data.avatar}/>
|
<DiscordAvatar
|
||||||
|
userID={data.id}
|
||||||
|
size={256}
|
||||||
|
className='w-full rounded-full'
|
||||||
|
hash={data.avatar}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='w-full grow px-5 py-12 text-center lg:w-5/12 lg:text-left'>
|
<div className='w-full grow px-5 py-12 text-center lg:w-5/12 lg:text-left'>
|
||||||
<Tag
|
<Tag
|
||||||
@ -158,7 +172,7 @@ const Bots: NextPage<BotsProps> = ({ data, desc, date, user, theme, csrfToken })
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className='w-full lg:w-1/4'>
|
<div className='w-full lg:w-1/4'>
|
||||||
{(data.state === 'ok' && !checkBotFlag(data.flags, 'private')) && (
|
{data.state === 'ok' && !checkBotFlag(data.flags, 'private') && (
|
||||||
<LongButton newTab href={`/bots/${router.query.id}/invite`}>
|
<LongButton newTab href={`/bots/${router.query.id}/invite`}>
|
||||||
<h4 className='whitespace-nowrap'>
|
<h4 className='whitespace-nowrap'>
|
||||||
<i className='fas fa-user-plus text-discord-blurple' /> 초대하기
|
<i className='fas fa-user-plus text-discord-blurple' /> 초대하기
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
|
import { botEnforcements } from '@utils/Constants'
|
||||||
import type { GuildFeature } from 'discord.js'
|
import type { GuildFeature } from 'discord.js'
|
||||||
import type { IncomingMessage } from 'http'
|
import type { IncomingMessage } from 'http'
|
||||||
import type { NextPageContext } from 'next'
|
import type { NextPageContext } from 'next'
|
||||||
|
|
||||||
export type Nullable<T> = T | null
|
export type Nullable<T> = T | null
|
||||||
|
|
||||||
|
export type ValueOf<T> = T[keyof T]
|
||||||
|
|
||||||
export interface Bot {
|
export interface Bot {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
@ -25,11 +28,14 @@ export interface Bot {
|
|||||||
url: string | null
|
url: string | null
|
||||||
discord: string | null
|
discord: string | null
|
||||||
vanity: string | null
|
vanity: string | null
|
||||||
|
enforcements: BotEnforcementKeys[]
|
||||||
bg: string
|
bg: string
|
||||||
banner: string
|
banner: string
|
||||||
owners: User[] | string[]
|
owners: User[] | string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type BotEnforcementKeys = keyof typeof botEnforcements
|
||||||
|
|
||||||
export interface RawGuild {
|
export interface RawGuild {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
|
|||||||
@ -120,6 +120,25 @@ export const botCategoryDescription = {
|
|||||||
마인크래프트: '게임 "마인크래프트"에 관련된 기능을 다룹니다.',
|
마인크래프트: '게임 "마인크래프트"에 관련된 기능을 다룹니다.',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const botEnforcements = {
|
||||||
|
JOIN_PARTIALLY_ENFORCED: {
|
||||||
|
label: '서버 참여가 필요한 기능이 있습니다',
|
||||||
|
description: '봇의 일부 명령어는 봇의 디스코드 서버에 참여해야 사용할 수 있습니다.',
|
||||||
|
},
|
||||||
|
JOIN_ENFORCED: {
|
||||||
|
label: '서버 참여 없이는 봇의 핵심 기능을 사용할 수 없습니다',
|
||||||
|
description: '봇의 핵심 기능은 봇의 디스코드 서버에 참여해야 사용할 수 있습니다.',
|
||||||
|
},
|
||||||
|
LICENSE_PARTIALLY_ENFORCED: {
|
||||||
|
label: '유료 구매가 필요한 기능이 있습니다',
|
||||||
|
description: '봇의 일부 명령어는 유료 구매가 필요합니다.',
|
||||||
|
},
|
||||||
|
LICENSE_ENFORCED: {
|
||||||
|
label: '유료 구매 없이는 봇의 핵심 기능을 사용할 수 없습니다',
|
||||||
|
description: '유료 구매 없이는 봇의 핵심 기능을 사용할 수 없습니다.',
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
export const botCategoryIcon = {
|
export const botCategoryIcon = {
|
||||||
관리: 'fas fa-cogs',
|
관리: 'fas fa-cogs',
|
||||||
뮤직: 'fas fa-music',
|
뮤직: 'fas fa-music',
|
||||||
|
|||||||
@ -62,6 +62,7 @@ async function getBot(id: string, topLevel = true): Promise<Bot> {
|
|||||||
'bots.status',
|
'bots.status',
|
||||||
'bots.trusted',
|
'bots.trusted',
|
||||||
'bots.partnered',
|
'bots.partnered',
|
||||||
|
'bots.enforcements',
|
||||||
'bots.discord',
|
'bots.discord',
|
||||||
'bots.state',
|
'bots.state',
|
||||||
'bots.vanity',
|
'bots.vanity',
|
||||||
@ -102,7 +103,7 @@ async function getBot(id: string, topLevel = true): Promise<Bot> {
|
|||||||
res.owners = JSON.parse(res.owners)
|
res.owners = JSON.parse(res.owners)
|
||||||
res.banner = res.banner ? camoUrl(res.banner) : null
|
res.banner = res.banner ? camoUrl(res.banner) : null
|
||||||
res.bg = res.bg ? camoUrl(res.bg) : null
|
res.bg = res.bg ? camoUrl(res.bg) : null
|
||||||
|
res.enforcements = JSON.parse(res.enforcements ?? '[]')
|
||||||
if (discordBot.flags.bitfield & UserFlags.BotHTTPInteractions) {
|
if (discordBot.flags.bitfield & UserFlags.BotHTTPInteractions) {
|
||||||
res.status = 'online'
|
res.status = 'online'
|
||||||
} else if (botMember) {
|
} else if (botMember) {
|
||||||
@ -448,6 +449,7 @@ async function getBotSubmit(id: string, date: number): Promise<SubmittedBot> {
|
|||||||
'id',
|
'id',
|
||||||
'date',
|
'date',
|
||||||
'category',
|
'category',
|
||||||
|
'enforcements',
|
||||||
'lib',
|
'lib',
|
||||||
'prefix',
|
'prefix',
|
||||||
'intro',
|
'intro',
|
||||||
@ -463,6 +465,7 @@ async function getBotSubmit(id: string, date: number): Promise<SubmittedBot> {
|
|||||||
.where({ id, date })
|
.where({ id, date })
|
||||||
if (res.length === 0) return null
|
if (res.length === 0) return null
|
||||||
res[0].category = JSON.parse(res[0].category)
|
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)
|
res[0].owner = await get.user.load(res[0].owner)
|
||||||
return res[0]
|
return res[0]
|
||||||
}
|
}
|
||||||
@ -474,6 +477,7 @@ async function getBotSubmits(id: string): Promise<SubmittedBot[]> {
|
|||||||
'id',
|
'id',
|
||||||
'date',
|
'date',
|
||||||
'category',
|
'category',
|
||||||
|
'enforcements',
|
||||||
'lib',
|
'lib',
|
||||||
'prefix',
|
'prefix',
|
||||||
'intro',
|
'intro',
|
||||||
@ -492,6 +496,7 @@ async function getBotSubmits(id: string): Promise<SubmittedBot[]> {
|
|||||||
res = await Promise.all(
|
res = await Promise.all(
|
||||||
res.map(async (el) => {
|
res.map(async (el) => {
|
||||||
el.category = JSON.parse(el.category)
|
el.category = JSON.parse(el.category)
|
||||||
|
el.enforcements = JSON.parse(el.enforcements)
|
||||||
el.owner = owner
|
el.owner = owner
|
||||||
return el
|
return el
|
||||||
})
|
})
|
||||||
@ -636,6 +641,7 @@ async function submitBot(
|
|||||||
git: data.git,
|
git: data.git,
|
||||||
url: data.url,
|
url: data.url,
|
||||||
category: JSON.stringify(data.category),
|
category: JSON.stringify(data.category),
|
||||||
|
enforcements: JSON.stringify(data.enforcements),
|
||||||
discord: data.discord,
|
discord: data.discord,
|
||||||
state: 0,
|
state: 0,
|
||||||
})
|
})
|
||||||
@ -745,6 +751,7 @@ async function updateBot(id: string, data: ManageBot): Promise<number> {
|
|||||||
intro: data.intro,
|
intro: data.intro,
|
||||||
desc: data.desc,
|
desc: data.desc,
|
||||||
vanity: data.vanity,
|
vanity: data.vanity,
|
||||||
|
enforcements: JSON.stringify(data.enforcements),
|
||||||
banner: data.banner,
|
banner: data.banner,
|
||||||
bg: data.bg,
|
bg: data.bg,
|
||||||
})
|
})
|
||||||
@ -1134,6 +1141,7 @@ async function approveBotSubmission(id: string, date: number) {
|
|||||||
'id',
|
'id',
|
||||||
'date',
|
'date',
|
||||||
'category',
|
'category',
|
||||||
|
'enforcements',
|
||||||
'lib',
|
'lib',
|
||||||
'prefix',
|
'prefix',
|
||||||
'intro',
|
'intro',
|
||||||
@ -1160,6 +1168,7 @@ async function approveBotSubmission(id: string, date: number) {
|
|||||||
web: data.web,
|
web: data.web,
|
||||||
git: data.git,
|
git: data.git,
|
||||||
category: data.category,
|
category: data.category,
|
||||||
|
enforcements: data.enforcements,
|
||||||
discord: data.discord,
|
discord: data.discord,
|
||||||
token: sign({ id }),
|
token: sign({ id }),
|
||||||
})
|
})
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import YupKorean from 'yup-locales-ko'
|
|||||||
import { ListType } from '@types'
|
import { ListType } from '@types'
|
||||||
import {
|
import {
|
||||||
botCategories,
|
botCategories,
|
||||||
|
botEnforcements,
|
||||||
library,
|
library,
|
||||||
reportCats,
|
reportCats,
|
||||||
reservedVanityBypass,
|
reservedVanityBypass,
|
||||||
@ -174,6 +175,7 @@ export const AddBotSubmitSchema: Yup.SchemaOf<AddBotSubmit> = Yup.object({
|
|||||||
.min(100, '봇 설명은 최소 100자여야합니다.')
|
.min(100, '봇 설명은 최소 100자여야합니다.')
|
||||||
.max(1500, '봇 설명은 최대 1500자여야합니다.')
|
.max(1500, '봇 설명은 최대 1500자여야합니다.')
|
||||||
.required('봇 설명은 필수 항목입니다.'),
|
.required('봇 설명은 필수 항목입니다.'),
|
||||||
|
enforcements: Yup.array(Yup.string().oneOf(Object.keys(botEnforcements))),
|
||||||
_csrf: Yup.string().required(),
|
_csrf: Yup.string().required(),
|
||||||
_captcha: Yup.string().required(),
|
_captcha: Yup.string().required(),
|
||||||
})
|
})
|
||||||
@ -190,6 +192,7 @@ export interface AddBotSubmit {
|
|||||||
category: string | string[]
|
category: string | string[]
|
||||||
intro: string
|
intro: string
|
||||||
desc: string
|
desc: string
|
||||||
|
enforcements: string[]
|
||||||
_csrf: string
|
_csrf: string
|
||||||
_captcha: string
|
_captcha: string
|
||||||
}
|
}
|
||||||
@ -303,6 +306,7 @@ export function getManageBotSchema(perkAvailable = false) {
|
|||||||
.min(100, '봇 설명은 최소 100자여야합니다.')
|
.min(100, '봇 설명은 최소 100자여야합니다.')
|
||||||
.max(1500, '봇 설명은 최대 1500자여야합니다.')
|
.max(1500, '봇 설명은 최대 1500자여야합니다.')
|
||||||
.required('봇 설명은 필수 항목입니다.'),
|
.required('봇 설명은 필수 항목입니다.'),
|
||||||
|
enforcements: Yup.array(Yup.string().oneOf(Object.keys(botEnforcements))),
|
||||||
_csrf: Yup.string().required(),
|
_csrf: Yup.string().required(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,6 +353,7 @@ export interface ManageBot {
|
|||||||
desc: string
|
desc: string
|
||||||
vanity: string
|
vanity: string
|
||||||
banner: string
|
banner: string
|
||||||
|
enforcements: string[]
|
||||||
bg: string
|
bg: string
|
||||||
_csrf: string
|
_csrf: string
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user