feat: added widget

This commit is contained in:
Junseo Park 2021-02-24 22:49:14 +09:00
parent a11366078f
commit b6e8e99460
3 changed files with 92 additions and 2 deletions

View File

@ -0,0 +1,56 @@
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import ResponseWrapper from '@utils/ResponseWrapper'
import { WidgetOptionsSchema } from '@utils/Yup'
import { badgen } from 'badgen'
import { get } from '@utils/Query'
import { formatNumber } from '@utils/Tools'
import { BotBadgeType, DiscordEnpoints } from '@utils/Constants'
const Widget: NextApiHandler = async(req: ApiRequest, res: NextApiResponse) => {
const { id: param, type, style='flat', scale=1 } = 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
}).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: '존재하지 않는 봇입니다.' })
console.log(data)
const userImage = !data.avatar ? null : await get.images.user.load(DiscordEnpoints.CDN.user(data.id, data.avatar, { format: 'png', size: 128 }))
console.log(userImage)
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: `data:image/png;base64,${img.toString('base64')}`
}
res.send(badgen(badgeData))
}
interface ApiRequest extends NextApiRequest {
query: {
type: string
id: string
style?: string
scale?: string
}
}
export default Widget

View File

@ -1,5 +1,5 @@
import { ImageOptions, KoreanbotsImageOptions } from '@types'
import { makeImageURL } from './Tools'
import { Bot, ImageOptions, KoreanbotsImageOptions } from '@types'
import { formatNumber, makeImageURL } from './Tools'
export const Status = {
online: {
@ -129,6 +129,20 @@ export const BASE_URLs = {
api: 'https://discord.com/api',
cdn: 'https://cdn.discordapp.com'
}
export const BotBadgeType = (data: Bot) => {
return {
servers: {
label: '서버수',
status: formatNumber(data.servers)
},
votes: {
label: '하트',
status: `${formatNumber(data.votes)}`
}
}
}
export const DiscordEnpoints = {
Token: BASE_URLs.api + '/oauth2/token',
Me: BASE_URLs.api + '/v8/users/@me',

View File

@ -38,6 +38,25 @@ interface ImageOptions {
type ext = 'webp' | 'png' | 'gif'
type ImageSize = '128' | '256' | '512'
export const WidgetOptionsSchema: Yup.SchemaOf<WidgetOptions> = Yup.object({
id: Yup.string().required(),
ext: Yup.mixed<widgetExt>().oneOf(['svg']).required(),
type: Yup.mixed<widgetType>().oneOf(['votes', 'servers']).required(),
scale: Yup.number().positive().min(0.5).max(3).required(),
style: Yup.mixed<'flat'|'classic'>().oneOf(['flat', 'classic']).default('flat')
})
interface WidgetOptions {
id: string
ext: widgetExt
type: widgetType
scale: number
style: 'flat' | 'classic'
}
type widgetType = 'votes' | 'servers'
type widgetExt = 'svg'
export const PageCount = Yup.number().integer().positive().required()
export const OauthCallbackSchema: Yup.SchemaOf<OauthCallback> = Yup.object({
@ -111,4 +130,5 @@ export const ManageBotSchema = Yup.object({
owners: Yup.array(Yup.string()).min(1, '최소 한 명의 소유자는 입력해주세요.').max(10, '소유자는 최대 10명까지만 가능합니다.').unique('소유자 아이디는 중복될 수 없습니다.').required('소유자는 필수 항목입니다.'),
_csrf: Yup.string().required()
})
export default Yup