-
-
404
+ return (
+
+
+
+ 404
+
-
- { ErrorText[404] }
-
+
+ {ErrorText[404]}
+
+
-
+ )
}
export default NotFound
diff --git a/pages/_document.tsx b/pages/_document.tsx
index ce9a511..22291e3 100644
--- a/pages/_document.tsx
+++ b/pages/_document.tsx
@@ -10,8 +10,10 @@ class MyDocument extends Document {
return (
-
+
-
+
diff --git a/pages/api/[...404].ts b/pages/api/[...404].ts
index ca28208..ff3e918 100644
--- a/pages/api/[...404].ts
+++ b/pages/api/[...404].ts
@@ -1,9 +1,8 @@
import ResponseWrapper from '@utils/ResponseWrapper'
import RequestHandler from '@utils/RequestHandler'
-const NotFound = RequestHandler()
- .all(async(_req, res) => {
- return ResponseWrapper(res, { code: 404, message: '์์ฒญํ์ URL์ ํ์ด์ง๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.' })
- })
+const NotFound = RequestHandler().all(async (_req, res) => {
+ return ResponseWrapper(res, { code: 404, message: '์์ฒญํ์ URL์ ํ์ด์ง๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.' })
+})
export default NotFound
diff --git a/pages/api/_custom/429.ts b/pages/api/_custom/429.ts
index 1431034..fc74259 100644
--- a/pages/api/_custom/429.ts
+++ b/pages/api/_custom/429.ts
@@ -3,7 +3,11 @@ import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
const RateLimit: NextApiHandler = (_req: NextApiRequest, res: NextApiResponse) => {
res.statusCode = 429
- return ResponseWrapper(res, { code: 429, message: '์ง์ ๋ ์๊ฐ์ ๋๋ฌด ๋ง์ ์์ฒญ์ ๋ณด๋์ต๋๋ค. ์ ์ ๋ค์ ์๋ํด์ฃผ์ธ์.', errors: ['์ง์ ๋ ์๊ฐ์ ๋๋ฌด ๋ง์ ์์ฒญ์ ๋ณด๋์ต๋๋ค. ์ ์ ๋ค์ ์๋ํด์ฃผ์ธ์.'] })
+ return ResponseWrapper(res, {
+ code: 429,
+ message: '์ง์ ๋ ์๊ฐ์ ๋๋ฌด ๋ง์ ์์ฒญ์ ๋ณด๋์ต๋๋ค. ์ ์ ๋ค์ ์๋ํด์ฃผ์ธ์.',
+ errors: ['์ง์ ๋ ์๊ฐ์ ๋๋ฌด ๋ง์ ์์ฒญ์ ๋ณด๋์ต๋๋ค. ์ ์ ๋ค์ ์๋ํด์ฃผ์ธ์.'],
+ })
}
export default RateLimit
diff --git a/pages/api/auth/discord/callback.ts b/pages/api/auth/discord/callback.ts
index eb8873c..218eaec 100644
--- a/pages/api/auth/discord/callback.ts
+++ b/pages/api/auth/discord/callback.ts
@@ -11,51 +11,62 @@ import { update } from '@utils/Query'
import { verify } from '@utils/Jwt'
import RequestHandler from '@utils/RequestHandler'
-const Callback = RequestHandler()
- .get(async(req: ApiRequest, res) => {
- const validate = await OauthCallbackSchema.validate(req.query).then(r=> r).catch((e) => {
+const Callback = RequestHandler().get(async (req: ApiRequest, res) => {
+ const validate = await OauthCallbackSchema.validate(req.query)
+ .then(r => r)
+ .catch(e => {
ResponseWrapper(res, { code: 400, errors: e.errors })
return null
})
-
- if(!validate) return
-
- res.statusCode = 200
- const token:DiscordTokenInfo = await fetch(DiscordEnpoints.Token, {
- method: 'POST',
- body: formData({
- client_id: process.env.DISCORD_CLIENT_ID,
- redirect_uri: process.env.KOREANBOTS_URL + '/api/auth/discord/callback',
- client_secret: process.env.DISCORD_CLIENT_SECRET,
- scope: process.env.DISCORD_SCOPE,
- grant_type: 'authorization_code',
- code: req.query.code
- }),
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded'
- }
- }).then(r=> r.json())
- if(token.error) return ResponseWrapper(res, { code: 400, errors: ['์ฌ๋ฐ๋ฅด์ง ์์ ์ฝ๋์
๋๋ค.'] })
+ if (!validate) return
- const user:DiscordUserInfo = await fetch(DiscordEnpoints.Me, {
- method: 'GET',
- headers: {
- Authorization: `${token.token_type} ${token.access_token}`
- }
- }).then(r => r.json())
+ res.statusCode = 200
+ const token: DiscordTokenInfo = await fetch(DiscordEnpoints.Token, {
+ method: 'POST',
+ body: formData({
+ client_id: process.env.DISCORD_CLIENT_ID,
+ redirect_uri: process.env.KOREANBOTS_URL + '/api/auth/discord/callback',
+ client_secret: process.env.DISCORD_CLIENT_SECRET,
+ scope: process.env.DISCORD_SCOPE,
+ grant_type: 'authorization_code',
+ code: req.query.code,
+ }),
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ }).then(r => r.json())
+ if (token.error) return ResponseWrapper(res, { code: 400, errors: ['์ฌ๋ฐ๋ฅด์ง ์์ ์ฝ๋์
๋๋ค.'] })
- const userToken = await update.assignToken({ id: user.id, access_token: token.access_token, expires_in: token.expires_in, refresh_token: token.refresh_token, email: user.email, username: user.username, discriminator: user.discriminator })
- const info = verify(userToken)
- res.setHeader('set-cookie', serialize('token', userToken, {
+ const user: DiscordUserInfo = await fetch(DiscordEnpoints.Me, {
+ method: 'GET',
+ headers: {
+ Authorization: `${token.token_type} ${token.access_token}`,
+ },
+ }).then(r => r.json())
+
+ const userToken = await update.assignToken({
+ id: user.id,
+ access_token: token.access_token,
+ expires_in: token.expires_in,
+ refresh_token: token.refresh_token,
+ email: user.email,
+ username: user.username,
+ discriminator: user.discriminator,
+ })
+ const info = verify(userToken)
+ res.setHeader(
+ 'set-cookie',
+ serialize('token', userToken, {
expires: new Date(info.exp * 1000),
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
sameSite: 'lax',
- path: '/'
- }))
- res.redirect(301, '/callback/discord')
- })
+ path: '/',
+ })
+ )
+ res.redirect(301, '/callback/discord')
+})
interface ApiRequest extends NextApiRequest {
query: {
diff --git a/pages/api/auth/discord/index.ts b/pages/api/auth/discord/index.ts
index 6cacee4..cc72fd6 100644
--- a/pages/api/auth/discord/index.ts
+++ b/pages/api/auth/discord/index.ts
@@ -2,9 +2,11 @@ import { NextApiRequest, NextApiResponse } from 'next'
import { generateOauthURL } from '@utils/Tools'
import RequestHandler from '@utils/RequestHandler'
-const Discord = RequestHandler()
- .get(async (_req: NextApiRequest, res: NextApiResponse) => {
- res.redirect(301, generateOauthURL('discord', process.env.DISCORD_CLIENT_ID, process.env.DISCORD_SCOPE))
- })
+const Discord = RequestHandler().get(async (_req: NextApiRequest, res: NextApiResponse) => {
+ res.redirect(
+ 301,
+ generateOauthURL('discord', process.env.DISCORD_CLIENT_ID, process.env.DISCORD_SCOPE)
+ )
+})
export default Discord
diff --git a/pages/api/auth/discord/logout.ts b/pages/api/auth/discord/logout.ts
index 431347e..fb3f281 100644
--- a/pages/api/auth/discord/logout.ts
+++ b/pages/api/auth/discord/logout.ts
@@ -1,14 +1,15 @@
import { serialize } from 'cookie'
import RequestHandler from '@utils/RequestHandler'
-
-const Logout = RequestHandler()
- .get(async(req, res) => {
- res.setHeader('Cache-control', 'no-cache')
- res.setHeader('set-cookie', serialize('token', '', {
+const Logout = RequestHandler().get(async (req, res) => {
+ res.setHeader('Cache-control', 'no-cache')
+ res.setHeader(
+ 'set-cookie',
+ serialize('token', '', {
maxAge: -1,
- path: '/'
- }))
- res.redirect(301, '/')
- })
-export default Logout
\ No newline at end of file
+ path: '/',
+ })
+ )
+ res.redirect(301, '/')
+})
+export default Logout
diff --git a/pages/api/v1/[[...deprecated]].ts b/pages/api/v1/[[...deprecated]].ts
index 27bcf9e..4c3c155 100644
--- a/pages/api/v1/[[...deprecated]].ts
+++ b/pages/api/v1/[[...deprecated]].ts
@@ -1,13 +1,12 @@
import ResponseWrapper from '@utils/ResponseWrapper'
import RequestHandler from '@utils/RequestHandler'
-const Deprecated = RequestHandler()
- .get(async (_req, res) => {
- return ResponseWrapper(res, {
- code: 406,
- message: 'ํด๋น API ๋ฒ์ ์ ์ง์ ์ข
๋ฃ๋์์ต๋๋ค.',
- version: 1,
- })
+const Deprecated = RequestHandler().get(async (_req, res) => {
+ return ResponseWrapper(res, {
+ code: 406,
+ message: 'ํด๋น API ๋ฒ์ ์ ์ง์ ์ข
๋ฃ๋์์ต๋๋ค.',
+ version: 1,
})
+})
export default Deprecated
diff --git a/pages/api/v2/applications/bots/[id]/index.ts b/pages/api/v2/applications/bots/[id]/index.ts
index c203c96..4be1aa6 100644
--- a/pages/api/v2/applications/bots/[id]/index.ts
+++ b/pages/api/v2/applications/bots/[id]/index.ts
@@ -8,25 +8,25 @@ import RequestHandler from '@utils/RequestHandler'
import { User } from '@types'
-const BotApplications = RequestHandler()
- .patch(async (req: ApiRequest, res) => {
- const user = await get.Authorization(req.cookies.token)
- if(!user) return ResponseWrapper(res, { code: 401 })
- const csrfValidated = checkToken(req, res, req.body._csrf)
- if(!csrfValidated) return
- const validated = await DeveloperBotSchema.validate(req.body, { abortEarly: false }).then(el => el).catch(e => {
+const BotApplications = RequestHandler().patch(async (req: ApiRequest, res) => {
+ const user = await get.Authorization(req.cookies.token)
+ if (!user) return ResponseWrapper(res, { code: 401 })
+ const csrfValidated = checkToken(req, res, req.body._csrf)
+ if (!csrfValidated) return
+ const validated = await DeveloperBotSchema.validate(req.body, { abortEarly: false })
+ .then(el => el)
+ .catch(e => {
ResponseWrapper(res, { code: 400, errors: e.errors })
return null
})
- if(!validated) return
- const bot = await get.bot.load(req.query.id)
- if(!bot) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ๋ด์
๋๋ค.' })
- if(!(bot.owners as User[]).find(el => el.id === user)) return ResponseWrapper(res, { code: 403 })
- await update.updateBotApplication(req.query.id, { webhook: validated.webhook || null })
- return ResponseWrapper(res, { code: 200 })
-
- })
+ if (!validated) return
+ const bot = await get.bot.load(req.query.id)
+ if (!bot) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ๋ด์
๋๋ค.' })
+ if (!(bot.owners as User[]).find(el => el.id === user)) return ResponseWrapper(res, { code: 403 })
+ await update.updateBotApplication(req.query.id, { webhook: validated.webhook || null })
+ return ResponseWrapper(res, { code: 200 })
+})
interface ApiRequest extends NextApiRequest {
body: DeveloperBot
@@ -35,4 +35,4 @@ interface ApiRequest extends NextApiRequest {
}
}
-export default BotApplications
\ No newline at end of file
+export default BotApplications
diff --git a/pages/api/v2/applications/bots/[id]/reset.ts b/pages/api/v2/applications/bots/[id]/reset.ts
index 3a899b5..ae4856d 100644
--- a/pages/api/v2/applications/bots/[id]/reset.ts
+++ b/pages/api/v2/applications/bots/[id]/reset.ts
@@ -8,31 +8,32 @@ import RequestHandler from '@utils/RequestHandler'
import { User } from '@types'
-const ResetApplication = RequestHandler()
- .post(async (req: ApiRequest, res) => {
- const user = await get.Authorization(req.cookies.token)
- if(!user) return ResponseWrapper(res, { code: 401 })
- const csrfValidated = checkToken(req, res, req.body._csrf)
- if(!csrfValidated) return
- const validated = await ResetBotTokenSchema.validate(req.body, { abortEarly: false }).then(el => el).catch(e => {
+const ResetApplication = RequestHandler().post(async (req: ApiRequest, res) => {
+ const user = await get.Authorization(req.cookies.token)
+ if (!user) return ResponseWrapper(res, { code: 401 })
+ const csrfValidated = checkToken(req, res, req.body._csrf)
+ if (!csrfValidated) return
+ const validated = await ResetBotTokenSchema.validate(req.body, { abortEarly: false })
+ .then(el => el)
+ .catch(e => {
ResponseWrapper(res, { code: 400, errors: e.errors })
return null
})
- if(!validated) return
- const bot = await get.bot.load(req.query.id)
- if(!bot) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ๋ด์
๋๋ค.' })
- if(!(bot.owners as User[]).find(el => el.id === user)) return ResponseWrapper(res, { code: 403 })
- const d = await update.resetBotToken(req.query.id, validated.token)
- if(!d) return ResponseWrapper(res, { code: 500, message: '๋ฌด์ธ๊ฐ ์๋ชป๋์์ต๋๋ค.' })
- return ResponseWrapper(res, { code: 200, data: { token: d }})
- })
+ if (!validated) return
+ const bot = await get.bot.load(req.query.id)
+ if (!bot) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ๋ด์
๋๋ค.' })
+ if (!(bot.owners as User[]).find(el => el.id === user)) return ResponseWrapper(res, { code: 403 })
+ const d = await update.resetBotToken(req.query.id, validated.token)
+ if (!d) return ResponseWrapper(res, { code: 500, message: '๋ฌด์ธ๊ฐ ์๋ชป๋์์ต๋๋ค.' })
+ return ResponseWrapper(res, { code: 200, data: { token: d } })
+})
- interface ApiRequest extends NextApiRequest {
- body: ResetBotToken
- query: {
- id: string
- }
- }
+interface ApiRequest extends NextApiRequest {
+ body: ResetBotToken
+ query: {
+ id: string
+ }
+}
-export default ResetApplication
\ No newline at end of file
+export default ResetApplication
diff --git a/pages/api/v2/bots/[id].ts b/pages/api/v2/bots/[id].ts
index 04491a9..9ba3c11 100644
--- a/pages/api/v2/bots/[id].ts
+++ b/pages/api/v2/bots/[id].ts
@@ -7,29 +7,56 @@ import { AddBotSubmit, AddBotSubmitSchema } from '@utils/Yup'
import RequestHandler from '@utils/RequestHandler'
const Bots = RequestHandler()
- .get(async(req: GetApiRequest, res) => {
+ .get(async (req: GetApiRequest, res) => {
const bot = await get.bot.load(req.query.id)
- if(!bot) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ๋ด์
๋๋ค.' })
+ if (!bot) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ๋ด์
๋๋ค.' })
else return ResponseWrapper(res, { code: 200, data: bot })
})
.post(async (req: PostApiRequest, res) => {
const user = await get.Authorization(req.cookies.token)
- if(!user) return ResponseWrapper(res, { code: 401 })
+ if (!user) return ResponseWrapper(res, { code: 401 })
const csrfValidated = checkToken(req, res, req.body._csrf)
- if(!csrfValidated) return
+ if (!csrfValidated) return
- const validated = await AddBotSubmitSchema.validate(req.body, { abortEarly: false }).then(el => el).catch(e => {
- ResponseWrapper(res, { code: 400, errors: e.errors })
- return null
- })
+ const validated = await AddBotSubmitSchema.validate(req.body, { abortEarly: false })
+ .then(el => el)
+ .catch(e => {
+ ResponseWrapper(res, { code: 400, errors: e.errors })
+ return null
+ })
- if(!validated) return
- if(validated.id !== req.query.id) return ResponseWrapper(res, { code: 400, errors: ['์์ฒญ ์ฃผ์์ Body์ ์ ๋ณด๊ฐ ๋ค๋ฆ
๋๋ค.'] })
+ if (!validated) return
+ if (validated.id !== req.query.id)
+ return ResponseWrapper(res, { code: 400, errors: ['์์ฒญ ์ฃผ์์ Body์ ์ ๋ณด๊ฐ ๋ค๋ฆ
๋๋ค.'] })
const result = await put.submitBot(user, validated)
- if(result === 1) return ResponseWrapper(res, { code: 403, message: '์ด๋ฏธ ๋๊ธฐ์ค์ธ ๋ด์ด ์์ต๋๋ค.', errors: ['ํ ๋ฒ์ ์ต๋ 2๊ฐ์ ๋ด๊น์ง๋ง ์ ์ฒญํ์ค ์ ์์ต๋๋ค.\n๋ค๋ฅธ ๋ด๋ค์ ์ฌ์ฌ๊ฐ ์๋ฃ๋ ๋ค์ ์ ์ฒญํด์ฃผ์ธ์.'] })
- else if(result === 2) return ResponseWrapper(res, { code: 406, message: 'ํด๋น ๋ด์ ์ด๋ฏธ ์ฌ์ฌ์ค์ด๊ฑฐ๋ ์ด๋ฏธ ๋ฑ๋ก๋์ด์์ต๋๋ค.', errors: ['ํด๋น ์์ด๋์ ๋ด์ ์ด๋ฏธ ์ฌ์ฌ์ค์ด๊ฑฐ๋ ๋ฑ๋ก๋์ด์์ต๋๋ค. ๋ณธ์ธ ์์ ์ ๋ด์ด๊ณ ์ ์ฒญํ์ ์ ์ด ์์ผ์๋ค๋ฉด ๋ฌธ์ํด์ฃผ์ธ์.'] })
- else if(result === 3) return ResponseWrapper(res, { code: 404, message: '์ฌ๋ฐ๋ฅด์ง ์์ ๋ด ์์ด๋์
๋๋ค.', errors: ['ํด๋น ์์ด๋์ ๋ด์ ์กด์ฌํ์ง ์์ต๋๋ค. ๋ค์ ํ์ธํด์ฃผ์ธ์.'] })
- else if(result === 4) return ResponseWrapper(res, { code: 403, message: '๋์ค์ฝ๋ ์๋ฒ์ ์ฐธ๊ฐํด์ฃผ์ธ์.' , errors: ['๋ด ์ ์ฒญํ์๊ธฐ ์ํด์๋ ๊ณต์ ๋์ค์ฝ๋ ์๋ฒ์ ์ฐธ๊ฐํด์ฃผ์
์ผํฉ๋๋ค.'] })
+ if (result === 1)
+ return ResponseWrapper(res, {
+ code: 403,
+ message: '์ด๋ฏธ ๋๊ธฐ์ค์ธ ๋ด์ด ์์ต๋๋ค.',
+ errors: [
+ 'ํ ๋ฒ์ ์ต๋ 2๊ฐ์ ๋ด๊น์ง๋ง ์ ์ฒญํ์ค ์ ์์ต๋๋ค.\n๋ค๋ฅธ ๋ด๋ค์ ์ฌ์ฌ๊ฐ ์๋ฃ๋ ๋ค์ ์ ์ฒญํด์ฃผ์ธ์.',
+ ],
+ })
+ else if (result === 2)
+ return ResponseWrapper(res, {
+ code: 406,
+ message: 'ํด๋น ๋ด์ ์ด๋ฏธ ์ฌ์ฌ์ค์ด๊ฑฐ๋ ์ด๋ฏธ ๋ฑ๋ก๋์ด์์ต๋๋ค.',
+ errors: [
+ 'ํด๋น ์์ด๋์ ๋ด์ ์ด๋ฏธ ์ฌ์ฌ์ค์ด๊ฑฐ๋ ๋ฑ๋ก๋์ด์์ต๋๋ค. ๋ณธ์ธ ์์ ์ ๋ด์ด๊ณ ์ ์ฒญํ์ ์ ์ด ์์ผ์๋ค๋ฉด ๋ฌธ์ํด์ฃผ์ธ์.',
+ ],
+ })
+ else if (result === 3)
+ return ResponseWrapper(res, {
+ code: 404,
+ message: '์ฌ๋ฐ๋ฅด์ง ์์ ๋ด ์์ด๋์
๋๋ค.',
+ errors: ['ํด๋น ์์ด๋์ ๋ด์ ์กด์ฌํ์ง ์์ต๋๋ค. ๋ค์ ํ์ธํด์ฃผ์ธ์.'],
+ })
+ else if (result === 4)
+ return ResponseWrapper(res, {
+ code: 403,
+ message: '๋์ค์ฝ๋ ์๋ฒ์ ์ฐธ๊ฐํด์ฃผ์ธ์.',
+ errors: ['๋ด ์ ์ฒญํ์๊ธฐ ์ํด์๋ ๊ณต์ ๋์ค์ฝ๋ ์๋ฒ์ ์ฐธ๊ฐํด์ฃผ์
์ผํฉ๋๋ค.'],
+ })
return ResponseWrapper(res, { code: 200, data: result })
})
.patch(async (req, res) => {
@@ -49,4 +76,4 @@ interface PostApiRequest extends GetApiRequest {
}
}
-export default Bots
\ No newline at end of file
+export default Bots
diff --git a/pages/api/v2/search/bots.ts b/pages/api/v2/search/bots.ts
index 3e1b3b7..80a3240 100644
--- a/pages/api/v2/search/bots.ts
+++ b/pages/api/v2/search/bots.ts
@@ -7,28 +7,32 @@ import { SearchQuerySchema } from '@utils/Yup'
import { BotList } from '@types'
-const SearchBots = RequestHandler()
- .get(async (req: ApiRequest, res: NextApiResponse) => {
- const validated = await SearchQuerySchema.validate({ q: req.query.q, page: req.query.page }).then(el => el).catch(e => {
+const SearchBots = RequestHandler().get(async (req: ApiRequest, res: NextApiResponse) => {
+ const validated = await SearchQuerySchema.validate({ q: req.query.q, page: req.query.page })
+ .then(el => el)
+ .catch(e => {
ResponseWrapper(res, { code: 400, errors: e.errors })
})
- if(!validated) return
+ if (!validated) return
- let result: BotList
- try {
- result = await get.list.search.load(JSON.stringify({ page: validated.page, query: validated.q }))
- } catch {
- return ResponseWrapper(res, { code: 400, message: '๊ฒ์ ๋ฌธ๋ฒ์ด ์๋ชป๋์์ต๋๋ค.' })
- }
- if(result.totalPage < validated.page || result.currentPage !== validated.page) return ResponseWrapper(res, { code: 404, message: '๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค.' })
- else ResponseWrapper
(res, { code: 200, data: result })
- })
+ let result: BotList
+ try {
+ result = await get.list.search.load(
+ JSON.stringify({ page: validated.page, query: validated.q })
+ )
+ } catch {
+ return ResponseWrapper(res, { code: 400, message: '๊ฒ์ ๋ฌธ๋ฒ์ด ์๋ชป๋์์ต๋๋ค.' })
+ }
+ if (result.totalPage < validated.page || result.currentPage !== validated.page)
+ return ResponseWrapper(res, { code: 404, message: '๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค.' })
+ else ResponseWrapper(res, { code: 200, data: result })
+})
interface ApiRequest extends NextApiRequest {
- query: {
- q: string
- page: string
- }
+ query: {
+ q: string
+ page: string
+ }
}
-export default SearchBots
\ No newline at end of file
+export default SearchBots
diff --git a/pages/api/v2/users/[id].ts b/pages/api/v2/users/[id].ts
index 9dd6d9a..69d052c 100644
--- a/pages/api/v2/users/[id].ts
+++ b/pages/api/v2/users/[id].ts
@@ -4,13 +4,12 @@ import { get } from '@utils/Query'
import ResponseWrapper from '@utils/ResponseWrapper'
import RequestHandler from '@utils/RequestHandler'
-const Users = RequestHandler()
- .get(async(req: ApiRequest, res) => {
- console.log(req.query)
- const user = await get.user.load(req.query?.id)
- if(!user) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ์ ์ ์
๋๋ค.' })
- else return ResponseWrapper(res, { code: 200, data: user })
- })
+const Users = RequestHandler().get(async (req: ApiRequest, res) => {
+ console.log(req.query)
+ const user = await get.user.load(req.query?.id)
+ if (!user) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ์ ์ ์
๋๋ค.' })
+ else return ResponseWrapper(res, { code: 200, data: user })
+})
interface ApiRequest extends NextApiRequest {
query: {
@@ -18,4 +17,4 @@ interface ApiRequest extends NextApiRequest {
}
}
-export default Users
\ No newline at end of file
+export default Users
diff --git a/pages/api/widget/bots/[type]/[id].ts b/pages/api/widget/bots/[type]/[id].ts
index 853d249..ab22bae 100644
--- a/pages/api/widget/bots/[type]/[id].ts
+++ b/pages/api/widget/bots/[type]/[id].ts
@@ -8,41 +8,49 @@ import { get } from '@utils/Query'
import { BotBadgeType, DiscordEnpoints } from '@utils/Constants'
import RequestHandler from '@utils/RequestHandler'
-const Widget= RequestHandler()
- .get(async(req: ApiRequest, res: NextApiResponse) => {
- const { id: param, type, style='flat', scale=1, icon=true } = req.query
- const splitted = param.split('.')
+const Widget = RequestHandler().get(async (req: ApiRequest, res: NextApiResponse) => {
+ const { id: param, type, style = 'flat', scale = 1, icon = true } = req.query
+ const splitted = param.split('.')
- const validated = await WidgetOptionsSchema.validate({
- id: splitted.slice(0, splitted.length - 1).join('.'),
- ext: splitted[splitted.length - 1],
- style,
- type,
- scale,
- icon
- }).then(el=> el).catch(e=> {
+ const validated = await WidgetOptionsSchema.validate({
+ id: splitted.slice(0, splitted.length - 1).join('.'),
+ ext: splitted[splitted.length - 1],
+ style,
+ type,
+ scale,
+ icon,
+ })
+ .then(el => el)
+ .catch(e => {
ResponseWrapper(res, { code: 400, errors: e.errors })
return null
})
- if(!validated) return
-
- const data = await get.bot.load(validated.id)
-
- if(!data) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ๋ด์
๋๋ค.' })
- const userImage = !data.avatar ? null : await get.images.user.load(DiscordEnpoints.CDN.user(data.id, data.avatar, { format: 'png', size: 128 }))
- const img = userImage || await get.images.user.load(DiscordEnpoints.CDN.default(data.tag, { format: 'png', size: 128 }))
- res.setHeader('content-type', 'image/svg+xml; charset=utf-8')
- const badgeData = {
- ...BotBadgeType(data)[type],
- style: validated.style,
- scale: validated.scale,
- icon: validated.icon ? `data:image/png;base64,${img.toString('base64')}` : null
- }
+ if (!validated) return
- res.send(badgen(badgeData))
-
- })
+ const data = await get.bot.load(validated.id)
+
+ if (!data) return ResponseWrapper(res, { code: 404, message: '์กด์ฌํ์ง ์๋ ๋ด์
๋๋ค.' })
+ const userImage = !data.avatar
+ ? null
+ : await get.images.user.load(
+ DiscordEnpoints.CDN.user(data.id, data.avatar, { format: 'png', size: 128 })
+ )
+ const img =
+ userImage ||
+ (await get.images.user.load(
+ DiscordEnpoints.CDN.default(data.tag, { format: 'png', size: 128 })
+ ))
+ res.setHeader('content-type', 'image/svg+xml; charset=utf-8')
+ const badgeData = {
+ ...BotBadgeType(data)[type],
+ style: validated.style,
+ scale: validated.scale,
+ icon: validated.icon ? `data:image/png;base64,${img.toString('base64')}` : null,
+ }
+
+ res.send(badgen(badgeData))
+})
interface ApiRequest extends NextApiRequest {
query: {
@@ -54,4 +62,4 @@ interface ApiRequest extends NextApiRequest {
}
}
-export default Widget
\ No newline at end of file
+export default Widget
diff --git a/pages/bots/[id]/vote.tsx b/pages/bots/[id]/vote.tsx
index c8dde3a..6d69766 100644
--- a/pages/bots/[id]/vote.tsx
+++ b/pages/bots/[id]/vote.tsx
@@ -21,7 +21,7 @@ const Segment = dynamic(() => import('@components/Segment'))
const SEO = dynamic(() => import('@components/SEO'))
const Advertisement = dynamic(() => import('@components/Advertisement'))
-const VoteBot: NextPage = ({ data, user, csrfToken }) => {
+const VoteBot: NextPage = ({ data, csrfToken }) => {
console.log(csrfToken)
const router = useRouter()
if(!data?.id) return
diff --git a/pages/bots/koreanbots.tsx b/pages/bots/koreanbots.tsx
index 4500048..e7070be 100644
--- a/pages/bots/koreanbots.tsx
+++ b/pages/bots/koreanbots.tsx
@@ -1,10 +1,10 @@
import { NextPage } from 'next'
import { useRouter } from 'next/router'
-const Reserved:NextPage = () => {
+const Reserved: NextPage = () => {
const router = useRouter()
router.push('/bots/iu')
return <>>
}
-export default Reserved
\ No newline at end of file
+export default Reserved
diff --git a/pages/developers/index.tsx b/pages/developers/index.tsx
index 223cb93..102c7a7 100644
--- a/pages/developers/index.tsx
+++ b/pages/developers/index.tsx
@@ -7,4 +7,4 @@ const Developers: NextPage = () => {
return <>>
}
-export default Developers
\ No newline at end of file
+export default Developers
diff --git a/postcss.config.js b/postcss.config.js
index 2048076..8d7fea0 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -14,4 +14,4 @@ module.exports = {
},
],
],
-}
\ No newline at end of file
+}
diff --git a/renovate.json b/renovate.json
index d8b137d..10afbef 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,11 +1,7 @@
{
- "labels": ["meta: dependencies"],
- "reviewers": ["team:koreanbots-devs"],
- "schedule": [
- "before 8am"
- ],
- "extends": [
- "config:base"
- ],
- "timezone": "Asia/Seoul"
+ "labels": ["meta: dependencies"],
+ "reviewers": ["team:koreanbots-devs"],
+ "schedule": ["before 8am"],
+ "extends": ["config:base"],
+ "timezone": "Asia/Seoul"
}
diff --git a/tests/utils.test.ts b/tests/utils.test.ts
index f51a311..1a13b61 100644
--- a/tests/utils.test.ts
+++ b/tests/utils.test.ts
@@ -19,7 +19,9 @@ test('checking Permission', () => {
})
test('check CDN URL', () => {
- expect(DiscordEnpoints.CDN.user('000000000000000000', 'abcdefghijklm', { format: 'jpg', size: 1024 })).toBe('https://cdn.discordapp.com/avatars/000000000000000000/abcdefghijklm.jpg?size=1024')
+ expect(
+ DiscordEnpoints.CDN.user('000000000000000000', 'abcdefghijklm', { format: 'jpg', size: 1024 })
+ ).toBe('https://cdn.discordapp.com/avatars/000000000000000000/abcdefghijklm.jpg?size=1024')
})
-export { }
\ No newline at end of file
+export {}
diff --git a/tsconfig.json b/tsconfig.json
index 3037474..268f1fe 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,36 +1,25 @@
{
- "compilerOptions": {
- "baseUrl": ".",
- "paths": {
- "@components/*": ["components/*"],
- "@utils/*": ["utils/*"],
- "@types": ["types/index.ts"]
-
- },
- "target": "es5",
- "lib": [
- "dom",
- "dom.iterable",
- "esnext"
- ],
- "allowJs": true,
- "skipLibCheck": true,
- "strict": false,
- "forceConsistentCasingInFileNames": true,
- "noEmit": true,
- "esModuleInterop": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "jsx": "preserve"
- },
- "include": [
- "next-env.d.ts",
- "**/*.ts",
- "**/*.tsx"
- ],
- "exclude": [
- "node_modules"
- ]
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@components/*": ["components/*"],
+ "@utils/*": ["utils/*"],
+ "@types": ["types/index.ts"]
+ },
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": false,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve"
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
+ "exclude": ["node_modules"]
}
diff --git a/types/global.d.ts b/types/global.d.ts
index d6df91f..c3fa95b 100644
--- a/types/global.d.ts
+++ b/types/global.d.ts
@@ -3,4 +3,4 @@ declare module 'yup' {
class ArraySchema extends Yup.array {
unique(format?: string): this
}
-}
\ No newline at end of file
+}
diff --git a/types/index.ts b/types/index.ts
index 6ddf413..dda02e5 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -46,7 +46,7 @@ export enum UserFlags {
general = 0 << 0,
staff = 1 << 0,
bughunter = 1 << 1,
- premium = 1 << 2
+ premium = 1 << 2,
}
export enum BotFlags {
@@ -56,23 +56,23 @@ export enum BotFlags {
partnered = 1 << 3,
verifed = 1 << 4,
premium = 1 << 5,
- hackerthon = 1 << 6
+ hackerthon = 1 << 6,
}
export enum DiscordUserFlags {
- DISCORD_EMPLOYEE = 1 << 0,
- DISCORD_PARTNER = 1 << 1,
- HYPESQUAD_EVENTS = 1 << 2,
- BUGHUNTER_LEVEL_1 = 1 << 3,
- HOUSE_BRAVERY = 1 << 6,
- HOUSE_BRILLIANCE = 1 << 7,
- HOUSE_BALANCE = 1 << 8,
- EARLY_SUPPORTER = 1 << 9,
- TEAM_USER = 1 << 10,
- SYSTEM = 1 << 12,
- BUGHUNTER_LEVEL_2 = 1 << 14,
- VERIFIED_BOT = 1 << 16,
- VERIFIED_DEVELOPER = 1 << 17
+ DISCORD_EMPLOYEE = 1 << 0,
+ DISCORD_PARTNER = 1 << 1,
+ HYPESQUAD_EVENTS = 1 << 2,
+ BUGHUNTER_LEVEL_1 = 1 << 3,
+ HOUSE_BRAVERY = 1 << 6,
+ HOUSE_BRILLIANCE = 1 << 7,
+ HOUSE_BALANCE = 1 << 8,
+ EARLY_SUPPORTER = 1 << 9,
+ TEAM_USER = 1 << 10,
+ SYSTEM = 1 << 12,
+ BUGHUNTER_LEVEL_2 = 1 << 14,
+ VERIFIED_BOT = 1 << 16,
+ VERIFIED_DEVELOPER = 1 << 17,
}
export interface BotList {
@@ -97,7 +97,6 @@ export interface SubmittedBot {
discord: string | null
state: number
reason: string | null
-
}
export interface DiscordTokenInfo {
@@ -215,7 +214,7 @@ export enum DiscordImageType {
EMOJI = 'emoji',
GUILD = 'guild',
USER = 'user',
- FALLBACK = 'default'
+ FALLBACK = 'default',
}
export interface CsrfContext extends NextPageContext {
@@ -226,7 +225,7 @@ export interface CsrfRequestMessage extends IncomingMessage {
csrfToken(): string
}
-export interface ResponseProps {
+export interface ResponseProps {
code?: number
message?: string
version?: number
@@ -234,6 +233,6 @@ export interface ResponseProps {
errors?: string[]
}
-interface Data {
+interface Data {
[key: string]: T
}
diff --git a/utils/Csrf.ts b/utils/Csrf.ts
index e29d7bc..fa66bcd 100644
--- a/utils/Csrf.ts
+++ b/utils/Csrf.ts
@@ -9,20 +9,23 @@ const csrfKey = '_csrf'
const Token = new csrf()
-export const tokenCreate = ():string => Token.create(process.env.CSRF_SECRET)
+export const tokenCreate = (): string => Token.create(process.env.CSRF_SECRET)
-export const tokenVerify = (token: string):boolean => Token.verify(process.env.CSRF_SECRET, token)
+export const tokenVerify = (token: string): boolean => Token.verify(process.env.CSRF_SECRET, token)
export const getToken = (req: IncomingMessage, res: ServerResponse) => {
const parsed = parse(req.headers.cookie || '')
- let key:string = parsed[csrfKey]
- if(!key || !tokenVerify(key)) {
+ let key: string = parsed[csrfKey]
+ if (!key || !tokenVerify(key)) {
key = tokenCreate()
- res.setHeader('set-cookie', serialize(csrfKey, key, {
- expires: new Date(+new Date() + 24 * 60 * 60 * 1000),
- httpOnly: true,
- path: '/'
- }))
+ res.setHeader(
+ 'set-cookie',
+ serialize(csrfKey, key, {
+ expires: new Date(+new Date() + 24 * 60 * 60 * 1000),
+ httpOnly: true,
+ path: '/',
+ })
+ )
}
return key
@@ -30,8 +33,8 @@ export const getToken = (req: IncomingMessage, res: ServerResponse) => {
export const checkToken = (req: NextApiRequest, res: NextApiResponse, token: string): boolean => {
const parsed = parse(req.headers.cookie || '')
- if(parsed[csrfKey] !== token || !tokenVerify(token)) {
+ if (parsed[csrfKey] !== token || !tokenVerify(token)) {
ResponseWrapper(res, { code: 400, message: 'CSRF ๊ฒ์ฆ ์๋ฌ (ํ์ด์ง๋ฅผ ์๋ก๊ณ ์นจํด์ฃผ์ธ์)' })
return false
} else return true
-}
\ No newline at end of file
+}
diff --git a/utils/DiscordBot.ts b/utils/DiscordBot.ts
index 3bd7acf..34c6cf6 100644
--- a/utils/DiscordBot.ts
+++ b/utils/DiscordBot.ts
@@ -12,4 +12,4 @@ DiscordBot.on('ready', async () => {
DiscordBot.login(process.env.DISCORD_TOKEN)
const getMainGuild = () => DiscordBot.guilds.cache.get(guildID)
-export { DiscordBot, getMainGuild }
\ No newline at end of file
+export { DiscordBot, getMainGuild }
diff --git a/utils/Fetch.ts b/utils/Fetch.ts
index db88b47..ba14e4e 100644
--- a/utils/Fetch.ts
+++ b/utils/Fetch.ts
@@ -1,11 +1,15 @@
import { ResponseProps } from '@types'
import { KoreanbotsEndPoints } from './Constants'
-const Fetch = async (endpoint: string, options?: RequestInit):Promise> => {
- const url = KoreanbotsEndPoints.baseAPI + ( endpoint.startsWith('/') ? endpoint : '/' + endpoint)
-
- const res = await fetch(url, { method: 'GET', headers: { 'content-type': 'application/json', ...options.headers }, ...options })
-
+const Fetch = async (endpoint: string, options?: RequestInit): Promise> => {
+ const url = KoreanbotsEndPoints.baseAPI + (endpoint.startsWith('/') ? endpoint : '/' + endpoint)
+
+ const res = await fetch(url, {
+ method: 'GET',
+ headers: { 'content-type': 'application/json', ...options.headers },
+ ...options,
+ })
+
let json = {}
try {
@@ -13,8 +17,8 @@ const Fetch = async (endpoint: string, options?: RequestInit):Promise ratelimit.limit ? ratelimit.limit : ratelimit.used))
+ res.setHeader(
+ 'x-ratelimit-remaining',
+ 600 - (ratelimit.used > ratelimit.limit ? ratelimit.limit : ratelimit.used)
+ )
res.setHeader('x-ratelimit-reset', Math.round(ratelimit.reset / 1000))
- if(ratelimit.limit < ratelimit.used) {
- if(ratelimit.onLimitExceed) ratelimit.onLimitExceed(res)
+ if (ratelimit.limit < ratelimit.used) {
+ if (ratelimit.onLimitExceed) ratelimit.onLimitExceed(res)
else ResponseWrapper(res, { code: 429 })
return true
}
}
-
interface RateLimit {
used: number
limit: number
- reset: number,
- onLimitExceed: (res: NextApiResponse)=> void | Promise
-}
\ No newline at end of file
+ reset: number
+ onLimitExceed: (res: NextApiResponse) => void | Promise
+}
diff --git a/utils/Regex.ts b/utils/Regex.ts
index c3b39c1..b9cb648 100644
--- a/utils/Regex.ts
+++ b/utils/Regex.ts
@@ -6,7 +6,8 @@ export const Prefix = /^[^\s]/
export const HTTPProtocol = /^https?:\/\/.*?/
export const Url = urlRegex({ strict: true })
-export const Emoji = '(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])'
+export const Emoji =
+ '(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])'
export const Heading = '(.*?)<\\/h(\\d)>'
export const EmojiSyntax = ':(\\w+):'
export const ImageTag = /
]*?alt\s*=\s*['"]([^'"]*?)['"][^>]*?>/
diff --git a/utils/RequestHandler.ts b/utils/RequestHandler.ts
index 0c11124..0c283b0 100644
--- a/utils/RequestHandler.ts
+++ b/utils/RequestHandler.ts
@@ -2,14 +2,15 @@ import { NextApiRequest, NextApiResponse } from 'next'
import nc from 'next-connect'
import ResponseWrapper from '@utils/ResponseWrapper'
-const RequestHandler = () => nc({
- onNoMatch(_req, res) {
- return ResponseWrapper(res, { code: 405 })
- },
- onError(err, _req, res) {
- console.error(err)
- return ResponseWrapper(res, { code: 500 })
- }
-})
+const RequestHandler = () =>
+ nc({
+ onNoMatch(_req, res) {
+ return ResponseWrapper(res, { code: 405 })
+ },
+ onError(err, _req, res) {
+ console.error(err)
+ return ResponseWrapper(res, { code: 500 })
+ },
+ })
-export default RequestHandler
\ No newline at end of file
+export default RequestHandler
diff --git a/utils/ResponseWrapper.ts b/utils/ResponseWrapper.ts
index 8b1a422..5fb3177 100644
--- a/utils/ResponseWrapper.ts
+++ b/utils/ResponseWrapper.ts
@@ -2,14 +2,19 @@ import http from 'http'
import { NextApiResponse } from 'next'
import { ResponseProps } from '@types'
import { ErrorText } from './Constants'
-export default function ResponseWrapper(
+export default function ResponseWrapper(
res: NextApiResponse,
- { code=200, message, version = 2, data, errors }: ResponseProps
+ { code = 200, message, version = 2, data, errors }: ResponseProps
) {
if (!code) throw new Error('`code` is required.')
if (!http.STATUS_CODES[code]) throw new Error('Invalid http code.')
res.statusCode = code
res.setHeader('Access-Control-Allow-Origin', process.env.KOREANBOTS_URL)
- res.json({ code, data, errors, version, ...(message || !data ? { message: message || ErrorText[code] || http.STATUS_CODES[code] } : {}) })
+ res.json({
+ code,
+ data,
+ errors,
+ version,
+ ...(message || !data ? { message: message || ErrorText[code] || http.STATUS_CODES[code] } : {}),
+ })
}
-
diff --git a/utils/Yup.ts b/utils/Yup.ts
index 275e649..6caba65 100644
--- a/utils/Yup.ts
+++ b/utils/Yup.ts
@@ -1,4 +1,3 @@
-import { TokenExpiredError } from 'jsonwebtoken'
import * as Yup from 'yup'
import YupKorean from 'yup-locales-ko'
import { ListType } from '../types'
@@ -8,17 +7,23 @@ import { HTTPProtocol, ID, Prefix, Url, Vanity } from './Regex'
Yup.setLocale(YupKorean)
Yup.addMethod(Yup.array, 'unique', function(message, mapper = a => a) {
return this.test('unique', message || 'array must be unique', function(list) {
- return list.length === new Set(list.map(mapper)).size
+ return list.length === new Set(list.map(mapper)).size
})
})
export const botListArgumentSchema: Yup.SchemaOf = Yup.object({
- type: Yup.mixed().oneOf(['VOTE', 'TRUSTED', 'NEW', 'PARTNERED', 'CATEGORY', 'SEARCH']).required(),
- page: Yup.number().positive().integer().notRequired().default(1),
- query: Yup.string().notRequired()
+ type: Yup.mixed()
+ .oneOf(['VOTE', 'TRUSTED', 'NEW', 'PARTNERED', 'CATEGORY', 'SEARCH'])
+ .required(),
+ page: Yup.number()
+ .positive()
+ .integer()
+ .notRequired()
+ .default(1),
+ query: Yup.string().notRequired(),
})
-export interface botListArgument {
+export interface botListArgument {
type: ListType
page?: number
query?: string
@@ -26,8 +31,12 @@ export interface botListArgument {
export const ImageOptionsSchema: Yup.SchemaOf = Yup.object({
id: Yup.string().required(),
- ext: Yup.mixed().oneOf(['webp', 'png', 'gif']).required(),
- size: Yup.mixed().oneOf(['128', '256', '512']).required()
+ ext: Yup.mixed()
+ .oneOf(['webp', 'png', 'gif'])
+ .required(),
+ size: Yup.mixed()
+ .oneOf(['128', '256', '512'])
+ .required(),
})
interface ImageOptions {
@@ -41,11 +50,21 @@ type ImageSize = '128' | '256' | '512'
export const WidgetOptionsSchema: Yup.SchemaOf = Yup.object({
id: Yup.string().required(),
- ext: Yup.mixed().oneOf(['svg']).required(),
- type: Yup.mixed().oneOf(['votes', 'servers', 'status']).required(),
- scale: Yup.number().positive().min(0.5).max(3).required(),
- style: Yup.mixed<'flat'|'classic'>().oneOf(['flat', 'classic']).default('flat'),
- icon: Yup.boolean().default(true)
+ ext: Yup.mixed()
+ .oneOf(['svg'])
+ .required(),
+ type: Yup.mixed()
+ .oneOf(['votes', 'servers', 'status'])
+ .required(),
+ scale: Yup.number()
+ .positive()
+ .min(0.5)
+ .max(3)
+ .required(),
+ style: Yup.mixed<'flat' | 'classic'>()
+ .oneOf(['flat', 'classic'])
+ .default('flat'),
+ icon: Yup.boolean().default(true),
})
interface WidgetOptions {
@@ -60,15 +79,20 @@ interface WidgetOptions {
type widgetType = 'votes' | 'servers' | 'status'
type widgetExt = 'svg'
-export const PageCount = Yup.number().integer().positive().required()
+export const PageCount = Yup.number()
+ .integer()
+ .positive()
+ .required()
export const OauthCallbackSchema: Yup.SchemaOf = Yup.object({
- code: Yup.string().required()
+ code: Yup.string().required(),
})
export const botCategoryListArgumentSchema: Yup.SchemaOf = Yup.object({
page: PageCount,
- category: Yup.mixed().oneOf(categories).required()
+ category: Yup.mixed()
+ .oneOf(categories)
+ .required(),
})
interface botCategoryListArgument {
@@ -81,8 +105,17 @@ interface OauthCallback {
}
export const SearchQuerySchema: Yup.SchemaOf = Yup.object({
- q: Yup.string().min(2, '์ต์ 2๊ธ์ ์ด์ ์
๋ ฅํด์ฃผ์ธ์.').max(50).required('๊ฒ์์ด๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.').label('๊ฒ์์ด'),
- page: Yup.number().positive().integer().notRequired().default(1).label('ํ์ด์ง')
+ q: Yup.string()
+ .min(2, '์ต์ 2๊ธ์ ์ด์ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(50)
+ .required('๊ฒ์์ด๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.')
+ .label('๊ฒ์์ด'),
+ page: Yup.number()
+ .positive()
+ .integer()
+ .notRequired()
+ .default(1)
+ .label('ํ์ด์ง'),
})
interface SearchQuery {
@@ -91,18 +124,49 @@ interface SearchQuery {
}
export const AddBotSubmitSchema: Yup.SchemaOf = Yup.object({
- agree: Yup.boolean().oneOf([true], '์๋จ์ ์ฒดํฌ๋ฐ์ค๋ฅผ ํด๋ฆญํด์ฃผ์ธ์.').required('์๋จ์ ์ฒดํฌ๋ฐ์ค๋ฅผ ํด๋ฆญํด์ฃผ์ธ์.'),
- id: Yup.string().matches(ID, '์ฌ๋ฐ๋ฅธ ๋ด ID๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.').required('๋ด ID๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- prefix: Yup.string().matches(Prefix, '์ ๋์ฌ๋ ๋์ด์ฐ๊ธฐ๋ก ์์ํ ์ ์์ต๋๋ค.').min(1, '์ ๋์ฌ๋ ์ต์ 1์์ฌ์ผํฉ๋๋ค.').max(32, '์ ๋์ฌ๋ ์ต๋ 32์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.').required('์ ๋์ฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- library: Yup.string().oneOf(library).required('๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- website: Yup.string().matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.').matches(Url, '์ฌ๋ฐ๋ฅธ ์น์ฌ์ดํธ URL์ ์
๋ ฅํด์ฃผ์ธ์.').max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- url: Yup.string().matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.').matches(Url, '์ฌ๋ฐ๋ฅธ ์ด๋๋งํฌ URL์ ์
๋ ฅํด์ฃผ์ธ์.').max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- git: Yup.string().matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.').matches(Url, '์ฌ๋ฐ๋ฅธ ๊น URL์ ์
๋ ฅํด์ฃผ์ธ์.').max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- discord: Yup.string().matches(Vanity, '๋์ค์ฝ๋ ์ด๋์ฝ๋ ํ์์ ์ง์ผ์ฃผ์ธ์.').min(2, '์ง์ ๋์ค์ฝ๋๋ ์ต์ 2์์ฌ์ผํฉ๋๋ค.').max(32, '์ง์ ๋์ค์ฝ๋๋ ์ต๋ 32์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- category: Yup.array(Yup.string().oneOf(categories)).min(1, '์ต์ ํ ๊ฐ์ ์นดํ
๊ณ ๋ฆฌ๋ฅผ ์ ํํด์ฃผ์ธ์.').unique('์นดํ
๊ณ ๋ฆฌ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.').required('์นดํ
๊ณ ๋ฆฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- intro: Yup.string().min(2, '๋ด ์๊ฐ๋ ์ต์ 2์์ฌ์ผํฉ๋๋ค.').max(60, '๋ด ์๊ฐ๋ ์ต๋ 60์์ฌ์ผํฉ๋๋ค.').required('๋ด ์๊ฐ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- desc: Yup.string().min(100, '๋ด ์ค๋ช
์ ์ต์ 100์์ฌ์ผํฉ๋๋ค.').max(1500, '๋ด ์ค๋ช
์ ์ต๋ 1500์์ฌ์ผํฉ๋๋ค.').required('๋ด ์ค๋ช
์ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- _csrf: Yup.string().required()
+ agree: Yup.boolean()
+ .oneOf([true], '์๋จ์ ์ฒดํฌ๋ฐ์ค๋ฅผ ํด๋ฆญํด์ฃผ์ธ์.')
+ .required('์๋จ์ ์ฒดํฌ๋ฐ์ค๋ฅผ ํด๋ฆญํด์ฃผ์ธ์.'),
+ id: Yup.string()
+ .matches(ID, '์ฌ๋ฐ๋ฅธ ๋ด ID๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.')
+ .required('๋ด ID๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ prefix: Yup.string()
+ .matches(Prefix, '์ ๋์ฌ๋ ๋์ด์ฐ๊ธฐ๋ก ์์ํ ์ ์์ต๋๋ค.')
+ .min(1, '์ ๋์ฌ๋ ์ต์ 1์์ฌ์ผํฉ๋๋ค.')
+ .max(32, '์ ๋์ฌ๋ ์ต๋ 32์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.')
+ .required('์ ๋์ฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ library: Yup.string()
+ .oneOf(library)
+ .required('๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ website: Yup.string()
+ .matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.')
+ .matches(Url, '์ฌ๋ฐ๋ฅธ ์น์ฌ์ดํธ URL์ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ url: Yup.string()
+ .matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.')
+ .matches(Url, '์ฌ๋ฐ๋ฅธ ์ด๋๋งํฌ URL์ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ git: Yup.string()
+ .matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.')
+ .matches(Url, '์ฌ๋ฐ๋ฅธ ๊น URL์ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ discord: Yup.string()
+ .matches(Vanity, '๋์ค์ฝ๋ ์ด๋์ฝ๋ ํ์์ ์ง์ผ์ฃผ์ธ์.')
+ .min(2, '์ง์ ๋์ค์ฝ๋๋ ์ต์ 2์์ฌ์ผํฉ๋๋ค.')
+ .max(32, '์ง์ ๋์ค์ฝ๋๋ ์ต๋ 32์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ category: Yup.array(Yup.string().oneOf(categories))
+ .min(1, '์ต์ ํ ๊ฐ์ ์นดํ
๊ณ ๋ฆฌ๋ฅผ ์ ํํด์ฃผ์ธ์.')
+ .unique('์นดํ
๊ณ ๋ฆฌ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.')
+ .required('์นดํ
๊ณ ๋ฆฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ intro: Yup.string()
+ .min(2, '๋ด ์๊ฐ๋ ์ต์ 2์์ฌ์ผํฉ๋๋ค.')
+ .max(60, '๋ด ์๊ฐ๋ ์ต๋ 60์์ฌ์ผํฉ๋๋ค.')
+ .required('๋ด ์๊ฐ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ desc: Yup.string()
+ .min(100, '๋ด ์ค๋ช
์ ์ต์ 100์์ฌ์ผํฉ๋๋ค.')
+ .max(1500, '๋ด ์ค๋ช
์ ์ต๋ 1500์์ฌ์ผํฉ๋๋ค.')
+ .required('๋ด ์ค๋ช
์ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ _csrf: Yup.string().required(),
})
export interface AddBotSubmit {
@@ -121,32 +185,66 @@ export interface AddBotSubmit {
}
export const ManageBotSchema = Yup.object({
- prefix: Yup.string().matches(Prefix, '์ ๋์ฌ๋ ๋์ด์ฐ๊ธฐ๋ก ์์ํ ์ ์์ต๋๋ค.').min(1, '์ ๋์ฌ๋ ์ต์ 1์์ฌ์ผํฉ๋๋ค.').max(32, '์ ๋์ฌ๋ ์ต๋ 32์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.').required('์ ๋์ฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- library: Yup.string().oneOf(library).required('๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- website: Yup.string().matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.').matches(Url, '์ฌ๋ฐ๋ฅธ ์น์ฌ์ดํธ URL์ ์
๋ ฅํด์ฃผ์ธ์.').max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- url: Yup.string().matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.').matches(Url, '์ฌ๋ฐ๋ฅธ ์ด๋๋งํฌ URL์ ์
๋ ฅํด์ฃผ์ธ์.').max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- git: Yup.string().matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.').matches(Url, '์ฌ๋ฐ๋ฅธ ๊น URL์ ์
๋ ฅํด์ฃผ์ธ์.').max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- discord: Yup.string().matches(Vanity, '๋์ค์ฝ๋ ์ด๋์ฝ๋ ํ์์ ์ง์ผ์ฃผ์ธ์.').min(2, '์ง์ ๋์ค์ฝ๋๋ ์ต์ 2์์ฌ์ผํฉ๋๋ค.').max(32, '์ง์ ๋์ค์ฝ๋๋ ์ต๋ 32์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- category: Yup.array(Yup.string().oneOf(categories)).min(1, '์ต์ ํ ๊ฐ์ ์นดํ
๊ณ ๋ฆฌ๋ฅผ ์ ํํด์ฃผ์ธ์.').unique('์นดํ
๊ณ ๋ฆฌ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.').required('์นดํ
๊ณ ๋ฆฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- intro: Yup.string().min(2, '๋ด ์๊ฐ๋ ์ต์ 2์์ฌ์ผํฉ๋๋ค.').max(60, '๋ด ์๊ฐ๋ ์ต๋ 60์์ฌ์ผํฉ๋๋ค.').required('๋ด ์๊ฐ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- desc: Yup.string().min(100, '๋ด ์ค๋ช
์ ์ต์ 100์์ฌ์ผํฉ๋๋ค.').max(1500, '๋ด ์ค๋ช
์ ์ต๋ 1500์์ฌ์ผํฉ๋๋ค.').required('๋ด ์ค๋ช
์ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- owners: Yup.array(Yup.string()).min(1, '์ต์ ํ ๋ช
์ ์์ ์๋ ์
๋ ฅํด์ฃผ์ธ์.').max(10, '์์ ์๋ ์ต๋ 10๋ช
๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.').unique('์์ ์ ์์ด๋๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.').required('์์ ์๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
- _csrf: Yup.string().required()
+ prefix: Yup.string()
+ .matches(Prefix, '์ ๋์ฌ๋ ๋์ด์ฐ๊ธฐ๋ก ์์ํ ์ ์์ต๋๋ค.')
+ .min(1, '์ ๋์ฌ๋ ์ต์ 1์์ฌ์ผํฉ๋๋ค.')
+ .max(32, '์ ๋์ฌ๋ ์ต๋ 32์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.')
+ .required('์ ๋์ฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ library: Yup.string()
+ .oneOf(library)
+ .required('๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ website: Yup.string()
+ .matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.')
+ .matches(Url, '์ฌ๋ฐ๋ฅธ ์น์ฌ์ดํธ URL์ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ url: Yup.string()
+ .matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.')
+ .matches(Url, '์ฌ๋ฐ๋ฅธ ์ด๋๋งํฌ URL์ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ git: Yup.string()
+ .matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.')
+ .matches(Url, '์ฌ๋ฐ๋ฅธ ๊น URL์ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(64, 'URL์ ์ต๋ 64์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ discord: Yup.string()
+ .matches(Vanity, '๋์ค์ฝ๋ ์ด๋์ฝ๋ ํ์์ ์ง์ผ์ฃผ์ธ์.')
+ .min(2, '์ง์ ๋์ค์ฝ๋๋ ์ต์ 2์์ฌ์ผํฉ๋๋ค.')
+ .max(32, '์ง์ ๋์ค์ฝ๋๋ ์ต๋ 32์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ category: Yup.array(Yup.string().oneOf(categories))
+ .min(1, '์ต์ ํ ๊ฐ์ ์นดํ
๊ณ ๋ฆฌ๋ฅผ ์ ํํด์ฃผ์ธ์.')
+ .unique('์นดํ
๊ณ ๋ฆฌ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.')
+ .required('์นดํ
๊ณ ๋ฆฌ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ intro: Yup.string()
+ .min(2, '๋ด ์๊ฐ๋ ์ต์ 2์์ฌ์ผํฉ๋๋ค.')
+ .max(60, '๋ด ์๊ฐ๋ ์ต๋ 60์์ฌ์ผํฉ๋๋ค.')
+ .required('๋ด ์๊ฐ๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ desc: Yup.string()
+ .min(100, '๋ด ์ค๋ช
์ ์ต์ 100์์ฌ์ผํฉ๋๋ค.')
+ .max(1500, '๋ด ์ค๋ช
์ ์ต๋ 1500์์ฌ์ผํฉ๋๋ค.')
+ .required('๋ด ์ค๋ช
์ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ owners: Yup.array(Yup.string())
+ .min(1, '์ต์ ํ ๋ช
์ ์์ ์๋ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(10, '์์ ์๋ ์ต๋ 10๋ช
๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.')
+ .unique('์์ ์ ์์ด๋๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.')
+ .required('์์ ์๋ ํ์ ํญ๋ชฉ์
๋๋ค.'),
+ _csrf: Yup.string().required(),
})
export const DeveloperBotSchema: Yup.SchemaOf = Yup.object({
- webhook: Yup.string().matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.').matches(Url, '์ฌ๋ฐ๋ฅธ ์นํ
URL์ ์
๋ ฅํด์ฃผ์ธ์.').max(150, 'URL์ ์ต๋ 150์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
- _csrf: Yup.string().required()
+ webhook: Yup.string()
+ .matches(HTTPProtocol, 'http:// ๋๋ https:// ๋ก ์์ํด์ผํฉ๋๋ค.')
+ .matches(Url, '์ฌ๋ฐ๋ฅธ ์นํ
URL์ ์
๋ ฅํด์ฃผ์ธ์.')
+ .max(150, 'URL์ ์ต๋ 150์๊น์ง๋ง ๊ฐ๋ฅํฉ๋๋ค.'),
+ _csrf: Yup.string().required(),
})
export interface DeveloperBot {
- webhook: string | null
+ webhook: string | null
_csrf: string
}
export const ResetBotTokenSchema = Yup.object({
token: Yup.string().required(),
- _csrf: Yup.string().required()
+ _csrf: Yup.string().required(),
})
export interface ResetBotToken {
diff --git a/utils/useOutsideClick.ts b/utils/useOutsideClick.ts
index 35dfa3f..954b3f6 100644
--- a/utils/useOutsideClick.ts
+++ b/utils/useOutsideClick.ts
@@ -1,7 +1,7 @@
import { RefObject, useEffect } from 'react'
const useOutsideClick = (ref: RefObject, callback: () => void) => {
- const handleClick = (e) => {
+ const handleClick = e => {
if (ref.current && !ref.current.contains(e.target)) {
callback()
}
@@ -16,4 +16,4 @@ const useOutsideClick = (ref: RefObject, callback: () => void) => {
})
}
-export default useOutsideClick
\ No newline at end of file
+export default useOutsideClick