core/utils/Constants.ts
Junseo Park 678fae4112
Feature/serverlist skeleton (#468)
* deps: added mongoose

* feat(*): added mongo and saving invited count

* chore(env): updated mongo configuration

* chore: updated next-env.d.ts

* chore(*): changed categories to botCategories

* chore(Image): maded image component

* feat(ServerCard): added ServerCard component

* feat(ServerIcon): added ServerIcon component

* feat(Tools): added server related functions

* feat(Mongo): added serverSchema

* chore(Hero): support serverlist

* feat(Owner): added crown

* feat(icons): added icons api

* feat(Yup): added AddServerSubmitSchema

* types: added server related types

* chore(BotCard): changed bot category link

* chore(Hero): changed category links

* feat(ServerCard): added unreachable state display

* feat(Yup): added ManageServerSchema

* feat(Query): added server related queries

* feat(Constants): added server related stuffs

* types: added updatedAt field for ServerData

* feat(pages/servers/*): added server pages

* feat(*): moved bot category rotue

* typo: fixed typo issue

* feat(pages/addserver/*): added add server page

* feat(api/servers): added server related api

* feat(pages/servers): added server edit page

* feat(pages/bots): changed bot list route

* feat(*): server categories

* feat(pages/users): added owned server list

* chore(pages/bots): changed image size

* feat(docker-compose): added bot

* ci: made some changes

* types: fixed type

* types(Search): fixed type

* types(*): fixed type

* fix(*): missing fields

* fix: Hero type typo issue

* ci(*): missing sentry org slug

* ci(*): fix

* feat(*): added and changed search pages

* Update pages/addserver/[id].tsx

Co-authored-by: Ryu JuHeon <saidbysolo@gmail.com>

* feat(api/search): added servers search api

* feat(pages/panel): added server list in manage page

* feat(Search): supporting server search at SearchBox

* feat(pages/apllications/servers): added server application page

* chore(docker-compose): changed image link

* chore(utils): removing server cache at submit

* chore(image/icons): added debug code

* chore(*): changed component names

* chore(Query): decreased server cache ttl

* fix(Query): error on addserver page

close: https://github.com/koreanbots/serverlist-testing/issues/10

* fix(Query): not using vote type

close: https://github.com/koreanbots/serverlist-testing/issues/9

* fix(Constants): fixed category unexpected char

close: https://github.com/koreanbots/serverlist-testing/issues/8

* fix(Query): serialize server data

* fix(Query): returning null on boost level 0

* fix(page/servers): displaying n/a on boostTier null

close: https://github.com/koreanbots/serverlist-testing/issues/4

* fix(pages/servers): hiding emoji list if no emoji

close: https://github.com/koreanbots/serverlist-testing/issues/1

* typo(pages/servers): bot to server

close: https://github.com/koreanbots/serverlist-testing/issues/2

* fix(components/Hero): editing vote list link

close: https://github.com/koreanbots/serverlist-testing/issues/11

* chore(*): changed list route

* feat(pages/servers/list/votes): added server vote list page

close: https://github.com/koreanbots/serverlist-testing/issues/12

* feat(Dockerfile): added pre-build

* fix(Image): image broken when fallbackSrc not given

close: https://github.com/koreanbots/serverlist-testing/issues/5

* ci: checking out submodules

* fix(ServerCard): bot category displayed at ServerCard

close: https://github.com/koreanbots/serverlist-testing/issues/16

* feat(*): supporting opengraph image for server

* fix(utils/Constants): fixed type missing on og

* feat(pages/servers): not forcing emoji width

* chore(utils/Yup): fixed agree checkbox error message

* typo(utils/Yup): fixed bot to server

* feat(pages/servers): improved emoji display

* chore(api/images/discord/icons): removed debug code

* chore(pages/servers): removed crown for owner

close: https://github.com/koreanbots/serverlist-testing/issues/19

* fix(utils/Query): returning date as string

close: https://github.com/koreanbots/serverlist-testing/issues/23

* fix(ServerCard): changed manage link from bot manage link

* fix(ServerCard): same height for every card

* chore: removed debug code

* chore(pages/addserver): showing as invite for server kicked bot

* typo(*): fixed typo issues

* types: added nullable type

* feat(Navbar): added list menu

* chore: showing warning for server data not fetched

* chore: changed main page (combined bots and servers)

* typo(*): replace '한국 디스코드봇 리스트' with '한국 디스코드 리스트'

* chore: added Hero component combined state

* typo: changed name

* fix(Navbar): fix link href

* typo: fix about page for serverlist

* chore: decrease font size

* fix: server category tag link

* fix: bot category link

* feat: added server widget

* fix(ServerCard): fixed servername overflowing

* chore: forcing re-login when discord server data fetch fails

* fix: error causing on owner not registered

* fix: making state same for join button

* fix: filtering owner if null

* fix(servers/[id]): fix error causing if owner is null

* fix(addserver): fixed error occuring for users not logged in

* fix(Constant): fixed og image extension getting popped

* typo: fixed typo issue

* fix: showing forbidden page for non-owner users

* feat: invite guide for server which bot left

* fix: invalid path for paginator on bot page

Co-authored-by: Hajin Lim <zero734kr@gmail.com>
Co-authored-by: Ryu JuHeon <saidbysolo@gmail.com>
2021-11-06 23:57:46 +09:00

523 lines
14 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Bot, ImageOptions, KoreanbotsImageOptions, Server } from '@types'
import { KeyMap } from 'react-hotkeys'
import { formatNumber, makeImageURL } from './Tools'
// Website META DATA
export const TITLE = '한국 디스코드 리스트'
export const DESCRIPTION = '다양한 국내 디스코드 봇들을 확인하고, 초대해보세요!'
export const THEME_COLOR = '#3366FF'
export const DSKR_BOT_ID = '784618064167698472'
export const VOTE_COOLDOWN = 12 * 60 * 60 * 1000
export const BUG_REPORTERS = ['260303569591205888']
export const BUG_REPORT_GROUPS = ['경북소프트웨어고등학교 해킹방어 그룹']
export const Status = {
online: {
text: '온라인',
color: 'green-400',
},
idle: {
text: '자리 비움',
color: 'yellow-300',
},
dnd: {
text: '다른 용무중',
color: 'red-500',
},
offline: {
text: '오프라인',
color: 'gray-500',
},
streaming: {
text: '방송중',
color: 'purple-500'
},
null: {
text: '알 수 없음',
color: 'gray-500',
},
'???': {
text: '알 수 없음',
color: 'gray-500',
},
}
export const library = [
'discord.js',
'Eris',
'discord.py',
'discordcr',
'Nyxx',
'Discord.Net',
'DSharpPlus',
'Nostrum',
'coxir',
'DiscordGo',
'Discord4J',
'Javacord',
'JDA',
'Discordia',
'RestCord',
'Yasmin',
'disco',
'discordrb',
'serenity',
'SwiftDiscord',
'Sword',
'기타',
'비공개',
]
export const botCategories = [
// 상위 카테고리
'관리',
'뮤직',
'전적',
'게임',
'도박',
'로깅',
'빗금 명령어',
'웹 대시보드',
'밈',
'레벨링',
'유틸리티',
'대화',
'NSFW',
'검색',
// 검색
'학교',
'코로나19',
// 유틸리티
'번역',
// 전적
'오버워치',
'리그 오브 레전드',
'배틀그라운드',
'마인크래프트'
]
export const botCategoryIcon = {
'관리': 'fas fa-cogs',
'뮤직': 'fas fa-music',
'전적': 'fas fa-puzzle-piece',
'웹 대시보드': 'fas fa-sliders-h',
'로깅': 'fas fa-pencil-alt',
'빗금 명령어': null,
'도박': 'fas fa-money-bill-alt',
'게임': 'fas fa-gamepad',
'밈': 'fas fa-image',
'레벨링': 'fas fa-angle-double-up',
'유틸리티': 'fas fa-tools',
'번역': 'fas fa-language',
'대화': 'fas fa-comments',
'NSFW': 'fas fa-exclamation-triangle',
'검색': 'fas fa-search',
'학교': 'fas fa-school',
'코로나19': 'fas fa-viruses',
'오버워치': 'fas fa-mask',
'리그 오브 레전드': 'fas fa-chess',
'배틀그라운드': 'fas fa-meteor',
'마인크래프트': 'fas fa-cubes'
}
export const serverCategories = [
'커뮤니티',
'IT & 과학',
'봇',
'친목',
'음악',
'교육',
'연애',
// 게임
'게임',
'오버워치',
'리그 오브 레전드',
'배틀그라운드',
'마인크래프트'
]
export const serverCategoryIcon = {
'커뮤니티': 'fas fa-comments',
'친목': 'fas fa-user-friends',
'음악': 'fas fa-music',
'IT & 과학': 'fas fa-flask',
'봇': 'fas fa-robot',
'교육': 'fas fa-graduation-cap',
'연애': 'fas fa-hand-holding-heart',
'게임': 'fas fa-gamepad',
'오버워치': 'fas fa-mask',
'리그 오브 레전드': 'fas fa-chess',
'배틀그라운드': 'fas fa-meteor',
'마인크래프트': 'fas fa-cubes'
}
export const reportCats = [
'위법',
'봇을 이용한 테러',
'괴롭힘, 모욕, 명예훼손',
'스팸, 도배, 의미없는 텍스트',
'폭력, 자해, 테러 옹호하거나 조장하는 컨텐츠',
'오픈소스 라이선스, 저작권 위반 등 권리 침해',
'Discord ToS 또는 한국 디스코드 리스트 가이드라인 위반',
'기타',
]
export const serverReportCats = [
'위법',
'괴롭힘, 모욕, 명예훼손',
'폭력, 자해, 테러 옹호하거나 조장하는 컨텐츠',
'저작권 위반 등 권리 침해',
'Discord ToS 또는 한국 디스코드 리스트 가이드라인 위반',
'기타',
]
export const imageSafeHost = [
'koreanbots.dev',
'githubusercontent.com',
'cdn.discordapp.com'
]
export const MessageColor = {
success: 'bg-green-200 text-green-800',
error: 'bg-red-200 text-red-800',
warning: 'bg-yellow-50 text-yellow-700',
info: 'bg-blue-200 text-blue-800'
}
export const BASE_URLs = {
api: 'https://discord.com/api',
invite: 'https://discord.gg',
cdn: 'https://cdn.discordapp.com',
camo: 'https://camo.koreanbots.dev'
}
export const BotBadgeType = (data: Bot) => {
return {
servers: {
label: '서버수',
status: data.servers === 0 ? 'N/A' : formatNumber(data.servers),
color: '7289DA'
},
votes: {
label: '하트',
status: `${formatNumber(data.votes)}`,
color: 'ef4444'
},
status: {
label: '상태',
status: Status[data.status]?.text || '알 수 없음',
color: {
online: '34d399',
idle: 'fcd34d',
dnd: 'ef4444',
streaming: '8b5cf6'
}[data.status] || '6b7280'
}
}
}
export const ServerBadgeType = (data: Server) => {
return {
members: {
label: '멤버수',
status: !data.members ? 'N/A' : formatNumber(data.members),
color: '7289DA'
},
votes: {
label: '하트',
status: `${formatNumber(data.votes)}`,
color: 'ef4444'
},
boost: {
label: '부스트',
status: `${!data.boostTier ? 0 : data.boostTier}레벨`,
color: 'fe73fa'
}
}
}
export const DiscordEnpoints = {
Token: BASE_URLs.api + '/oauth2/token',
Me: BASE_URLs.api + '/v9/users/@me',
Guilds: BASE_URLs.api + '/v9/users/@me/guilds',
InviteApplication: (id: string, perms: { [perm: string]: boolean }, scope: string, redirect?: string, guild_id?: string): string => `${BASE_URLs.api}/oauth2/authorize?client_id=${id ? id.split(' ')[0] : 'CLIENT_ID'}&permissions=${Object.keys(perms).filter(el => perms[el]).map(el => Number(el)).reduce((prev, curr) => prev | curr, 0)}&scope=${scope ? encodeURI(scope) : 'bot'}${redirect ? `&redirect_uri=${encodeURIComponent(redirect)}` : ''}${guild_id ? `&guild_id=${guild_id}` : ''}`,
ServerInvite: (code: string): string => `${BASE_URLs.invite}/${code}`,
CDN: class CDN {
static root = BASE_URLs.cdn
static emoji (id: string, options:ImageOptions={}) { return makeImageURL(`${this.root}/emojis/${id}`, options) }
static guild (id: string, hash: string, options:ImageOptions={}) { return makeImageURL(`${this.root}/icons/${id}/${hash}`, options) }
static default (tag: string|number, options:ImageOptions={}) { return makeImageURL(`${this.root}/embed/avatars/${!isNaN(Number(tag)) ? Number(tag) % 5 : 0}`, options) }
static user (id: string, hash: string, options:ImageOptions={}) { return makeImageURL(`${this.root}/avatars/${id}/${hash}`, options) }
}
}
export const KoreanbotsEndPoints = {
OG: class {
static root = 'https://og.kbots.link'
static origin = 'https://koreanbots.dev'
static generate(id: string, name: string, bio: string, tags: string[], stats: string[], type: 'bot' | 'server') {
const u = new URL(this.root)
u.pathname = name + '.png'
u.searchParams.append('image', this.origin + ( type === 'bot' ? KoreanbotsEndPoints.CDN.avatar(id, { format: 'webp', size: 256 }) : KoreanbotsEndPoints.CDN.icon(id, { format: 'webp', size: 256 }) ))
u.searchParams.append('bio', bio)
u.searchParams.append('type', type)
tags.map(t => u.searchParams.append('tags', t))
stats.map(s => u.searchParams.append('stats', s))
return u.href
}
static bot(id: string, name: string, bio: string, tags: string[], stats: string[]) {
return this.generate(id, name, bio, tags, stats, 'bot')
}
static server(id: string, name: string, bio: string, tags: string[], stats: string[]) {
return this.generate(id, name, bio, tags, stats, 'server')
}
},
CDN: class {
static root = '/api/image'
static avatar (id: string, options: KoreanbotsImageOptions) { return makeImageURL(`${this.root}/discord/avatars/${id}`, options) }
static icon (id: string, options: KoreanbotsImageOptions) { return makeImageURL(`${this.root}/discord/icons/${id}`, options) }
},
URL: class {
static root = process.env.KOREANBOTS_URL || 'https://koreanbots.dev'
static bot (id: string) { return `${this.root}/bots/${id}` }
static server (id: string) { return `${this.root}/servers/${id}` }
static user (id: string) { return `${this.root}/users/${id}` }
static submittedBot(id: string, date: number) { return `${this.root}/pendingBots/${id}/${date}` }
static searchBot(query: string) { return `${this.root}/bots/search?q=${encodeURIComponent(query)}` }
static searchServer(query: string) { return `${this.root}/servers/search?q=${encodeURIComponent(query)}` }
},
baseAPI: '/api/v2',
login: '/api/auth/discord',
logout: '/api/auth/discord/logout'
}
export const SpecialEndPoints = {
Github: {
Content: (owner: string, repo: string, path: string) => `https://api.github.com/repos/${owner}/${repo}/contents/${path}`,
Token: (clientID: string, clientSecret: string, code: string) => `https://github.com/login/oauth/access_token?client_id=${clientID}&client_secret=${clientSecret}&code=${code}`,
Me: 'https://api.github.com/user'
},
HCaptcha: {
Verify: 'https://hcaptcha.com/siteverify'
}
}
export const GlobalRatelimitIgnore = [
'/api/image/discord/avatars/'
]
export const Oauth = {
discord: (clientID: string, scope: string) => `https://discord.com/oauth2/authorize?client_id=${clientID}&scope=${scope}&permissions=0&response_type=code&redirect_uri=${process.env.KOREANBOTS_URL}/api/auth/discord/callback&prompt=none`,
github: (clientID: string) => `https://github.com/login/oauth/authorize?client_id=${clientID}&redirect_uri=${process.env.KOREANBOTS_URL}/api/auth/github/callback`
}
export const git = { 'github.com': { icon: 'github', text: 'GitHub' }, 'gitlab.com': { icon: 'gitlab', text: 'GitLab' }}
export const KoreanbotsDiscord = 'https://discord.gg/JEh53MQ'
export const ThemeColors = [{ name: '파랑', rgb: 'rgb(51, 102, 255)', hex: '#3366FF', color: 'koreanbots-blue' }, { name: '하양', rgb: 'rgb(251, 251, 251)', hex: '#FBFBFB', color: 'little-white' }, { name: '검정', rgb: 'rgb(27, 30, 35)', hex: '#1B1E23', color: 'very-black' }, { name: '보라', rgb: 'rgb(114, 137, 218)', hex: '#7289DA', color: 'discord-blurple' } ]
export const KoreanbotsEmoji = [{
name: '한국 디스코드 리스트',
short_names: ['koreanbots', 'kbots', 'dbkr'],
emoticons: [],
keywords: ['koreanbots', '한국 디스코드 리스트', '한디리', 'kbots'],
imageUrl: '/logo.png'
},
{
name: 'Discord',
short_names: ['discord'],
emoticons: [],
keywords: ['discord', '디스코드', '디코'],
imageUrl: '/emojis/discord.svg'
},
{
name: 'Javascript',
short_names: ['javascript', 'js'],
emoticons: [],
keywords: ['javascript', 'js', '자바스크립트'],
imageUrl: '/emojis/javascript.png'
},
{
name: 'Python',
short_names: ['python', 'py'],
emoticons: [],
keywords: ['python', 'py', '파이썬'],
imageUrl: '/emojis/python.png'
}]
export const shortcutKeyMap: KeyMap = {
SHORTCUT_HELP: ['command+/', 'ctrl+/'],
CHANGE_THEME: ['command+shift+d', 'ctrl+shift+d']
}
export const ErrorText = {
DEFAULT: '예상치 못한 에러가 발생하였습니다.',
400: '올바르지 않은 요청입니다.',
401: '로그인이 필요합니다.',
402: '결제가 필요합니다.',
403: '권한이 없습니다.',
404: '페이지가 존재하지 않습니다.',
405: '해당 요청 방법은 허용되지 않습니다.',
406: '연결을 받아드릴 수 없습니다.',
429: '지정된 시간에 너무 많은 요청을 보내셨습니다. 잠시 후 다시 시도해주세요.',
500: '서버 내부 오류가 발생하였습니다.',
502: '올바르지 않은 게이트웨이입니다.'
}
export const ErrorMessage = ['지나가던 고양이가 선을 밟았어요..', '무언가 잘못되었어요..!', '이게 아닌데...', '어쩜 이렇게 오류가 또 나는건지?']
export const ServerIntroList = ['한국어를 배울 수 있는 최고의 공간입니다!', '김치의 다양한 요리법을 소개하는 서버입니다.', '좋아하는 노래를 들을 수 있는 곳 입니다.', '게임을 함께 할 사람을 찾을 수 있습니다.']
export const BotSubmissionDenyReasonPresetsName = {
MISSING_VERIFY: '개발자 확인 불가',
OFFLINE: '봇 오프라인',
INVALID_CATEGORY: '올바르지 않은 카테고리',
PRIVATE: '프라이빗 봇',
LICENSE_VIOLATION: '오픈소스 라이선스 위반',
ABSENT_AT_DISCORD: '공식 디스코드 서버 미참여'
}
export const GuildPermissions = {
general: [
{
name: '채널 보기',
flag: 0x00000400
},
{
name: '채널 관리하기',
flag: 0x00000010,
twofactor: true
},
{
name: '역할 관리하기',
flag: 0x10000000,
twofactor: true
},
{
name: '이모티콘 관리하기',
flag: 0x40000000,
twofactor: true
},
{
name: '감사 로그 보기',
flag: 0x00000080
},
{
name: '웹후크 관리하기',
flag: 0x20000000,
twofactor: true
},
{
name: '서버 관리하기',
flag: 0x00000020,
twofactor: true
}
],
membership: [
{
name: '초대 코드 만들기',
flag: 0x00000001
},
{
name: '별명 변경하기',
flag: 0x04000000
},
{
name: '별명 관리하기',
flag: 0x08000000
},
{
name: '멤버 추방하기',
flag: 0x00000002,
twofactor: true
},
{
name: '멤버 차단하기',
flag: 0x00000004,
twofactor: true
}
],
channel: [
{
name: '메세지 보내기',
flag: 0x00000800
},
{
name: '링크 첨부',
flag: 0x00004000
},
{
name: '파일 첨부',
flag: 0x00008000
},
{
name: '반응 추가하기',
flag: 0x00000040
},
{
name: '외부 이모티콘 사용',
flag: 0x00040000
},
{
name: '@everyone, @here 모든 역할 멘션하기',
flag: 0x00020000
},
{
name: '메세지 관리',
flag: 0x00002000,
twofactor: true
},
{
name: '메세지 기록 보기',
flag: 0x00010000
},
{
name: '텍스트 음성 변환 메세지 전송',
flag: 0x00001000
},
{
name: '빗금 명령어 사용',
flag: 0x80000000
}
],
voice: [
{
name: '연결',
flag: 0x00100000
},
{
name: '말하기',
flag: 0x00200000
},
{
name: '동영상',
flag: 0x00000200
},
{
name: '음성 감지 사용',
flag: 0x02000000
},
{
name: '우선 발언권',
flag: 0x00000100
},
{
name: '멤버들의 마이크 음소거하기',
flag: 0x00400000
},
{
name: '멤버의 헤드셋 음소거하기',
flag: 0x00800000
},
{
name: '멤버 이동',
flag: 0x01000000
}
],
advanced: [
{
name: '관리자',
flag: 0x8,
twofactor: true
}
]
}