Skip to content

Commit b7ca0cf

Browse files
Feat: 신뢰된 봇 특전 수정 기능 추가 (#673)
* feat: camofy urls * chore: unify standards * feat: api changes for trusted bot perks * feat: trusted bot perks on edit page * chore: unify * fix: wtf * feat: hide perks menu for non-trusted bots * fix: camo should be proceed at server-side * type: typing issue * fix: conflict * fix: editing page on vanity code * fix: removed reserved page * feat: reserved vanity * fix: for not found * fix: bypass reserved vanity for offical bot * chore: apply prettier * chore: add webhook log for vanity change --------- Co-authored-by: skinmaker1345 <[email protected]>
1 parent f68da03 commit b7ca0cf

File tree

13 files changed

+188
-24
lines changed

13 files changed

+188
-24
lines changed

.env.demo.local

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ REVIEW_LOG_WEBHOOK_URL=
3333
OPEN_REVIEW_LOG_WEBHOOK_URL=
3434
STATS_LOG_WEBHOOK_URL=
3535
REPORT_WEBHOOK_URL=
36+
NOTICE_LOG_WEBHOOK_URL=

components/BotCard.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ const BotCard: React.FC<BotCardProps> = ({ manage = false, bot }) => {
1818
<div
1919
className='relative mx-auto h-full rounded-2xl bg-little-white text-black shadow-xl dark:bg-discord-black dark:text-white'
2020
style={
21-
checkBotFlag(bot.flags, 'trusted') && bot.banner
21+
(checkBotFlag(bot.flags, 'trusted') || checkBotFlag(bot.flags, 'partnered')) &&
22+
bot.banner
2223
? {
2324
background: `linear-gradient(to right, rgba(34, 36, 38, 0.68), rgba(34, 36, 38, 0.68)), url("${bot.banner}") center top / cover no-repeat`,
2425
color: 'white',

components/ServerCard.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ const ServerCard: React.FC<BotCardProps> = ({ type, server }) => {
2727
<div
2828
className='relative mx-auto h-full rounded-2xl bg-little-white text-black shadow-xl dark:bg-discord-black dark:text-white'
2929
style={
30-
checkServerFlag(server.flags, 'trusted') && server.banner
30+
(checkServerFlag(server.flags, 'trusted') ||
31+
checkServerFlag(server.flags, 'partnered')) &&
32+
server.banner
3133
? {
3234
background: `linear-gradient(to right, rgba(34, 36, 38, 0.68), rgba(34, 36, 38, 0.68)), url("${server.banner}") center top / cover no-repeat`,
3335
color: 'white',

pages/api/v2/bots/[id]/index.ts

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
import RequestHandler from '@utils/RequestHandler'
1717
import { User } from '@types'
1818
import {
19+
checkBotFlag,
1920
checkUserFlag,
2021
diff,
2122
inspect,
@@ -25,7 +26,6 @@ import {
2526
} from '@utils/Tools'
2627
import { discordLog, getMainGuild, webhookClients } from '@utils/DiscordBot'
2728
import { KoreanbotsEndPoints } from '@utils/Constants'
28-
import { userInfo } from 'os'
2929

3030
const patchLimiter = rateLimit({
3131
windowMs: 2 * 60 * 1000,
@@ -128,7 +128,11 @@ const Bots = RequestHandler()
128128
: `${userinfo.username}#${userinfo.tag}`,
129129
iconURL:
130130
KoreanbotsEndPoints.URL.root +
131-
KoreanbotsEndPoints.CDN.avatar(userinfo.id, { format: 'png', size: 256, hash: userinfo.avatar }),
131+
KoreanbotsEndPoints.CDN.avatar(userinfo.id, {
132+
format: 'png',
133+
size: 256,
134+
hash: userinfo.avatar,
135+
}),
132136
url: KoreanbotsEndPoints.URL.user(userinfo.id),
133137
})
134138
.setTitle('대기 중')
@@ -211,19 +215,60 @@ const Bots = RequestHandler()
211215
const csrfValidated = checkToken(req, res, req.body._csrf)
212216
if (!csrfValidated) return
213217

214-
const validated = await ManageBotSchema.validate(req.body, { abortEarly: false })
218+
const validated: ManageBot = await ManageBotSchema.validate(req.body, { abortEarly: false })
215219
.then((el) => el)
216220
.catch((e) => {
217221
ResponseWrapper(res, { code: 400, errors: e.errors })
218222
return null
219223
})
220224

221225
if (!validated) return
226+
if (
227+
!checkBotFlag(bot.flags, 'trusted') &&
228+
!checkBotFlag(bot.flags, 'partnered') &&
229+
(validated.vanity || validated.banner || validated.bg)
230+
)
231+
return ResponseWrapper(res, {
232+
code: 403,
233+
message: '해당 봇은 특전을 이용할 권한이 없습니다.',
234+
})
235+
if (validated.vanity) {
236+
const vanity = await get.bot.load(validated.vanity)
237+
if (vanity && vanity.id !== bot.id) {
238+
return ResponseWrapper(res, {
239+
code: 403,
240+
message: '이미 사용중인 한디리 커스텀 URL 입니다.',
241+
errors: ['다른 커스텀 URL로 다시 시도해주세요.'],
242+
})
243+
}
222244

245+
await webhookClients.internal.noticeLog.send({
246+
embeds: [
247+
{
248+
title: '한디리 커스텀 URL 변경',
249+
description: `봇: ${bot.name} - <@${bot.id}> ([${bot.id}](${KoreanbotsEndPoints.URL.bot(
250+
bot.id
251+
)}))`,
252+
fields: [
253+
{
254+
name: '이전',
255+
value: bot.vanity || '없음',
256+
},
257+
{
258+
name: '이후',
259+
value: validated.vanity || '없음',
260+
},
261+
],
262+
color: Colors.Blue,
263+
}
264+
],
265+
})
266+
}
223267
const result = await update.bot(req.query.id, validated)
224268
if (result === 0) return ResponseWrapper(res, { code: 400 })
225269
else {
226270
get.bot.clear(req.query.id)
271+
get.bot.clear(bot.vanity)
227272
const embed = new EmbedBuilder().setDescription(
228273
`${bot.name} - <@${bot.id}> ([${bot.id}](${KoreanbotsEndPoints.URL.bot(bot.id)}))`
229274
)
@@ -237,6 +282,9 @@ const Bots = RequestHandler()
237282
discord: bot.discord,
238283
intro: bot.intro,
239284
category: JSON.stringify(bot.category),
285+
vanity: bot.vanity,
286+
banner: bot.banner,
287+
bg: bot.bg,
240288
},
241289
{
242290
prefix: validated.prefix,
@@ -247,6 +295,9 @@ const Bots = RequestHandler()
247295
discord: validated.discord,
248296
intro: validated.intro,
249297
category: JSON.stringify(validated.category),
298+
vanity: validated.vanity,
299+
banner: validated.banner,
300+
bg: validated.bg,
250301
}
251302
)
252303
diffData.forEach((d) => {

pages/bots/[id]/edit.tsx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { ParsedUrlQuery } from 'querystring'
99
import { getJosaPicker } from 'josa'
1010

1111
import { get } from '@utils/Query'
12-
import { checkUserFlag, cleanObject, makeBotURL, parseCookie, redirectTo } from '@utils/Tools'
12+
import { checkBotFlag, checkUserFlag, cleanObject, makeBotURL, parseCookie, redirectTo } from '@utils/Tools'
1313
import { ManageBot, ManageBotSchema } from '@utils/Yup'
1414
import { botCategories, botCategoryDescription, library } from '@utils/Constants'
1515
import { Bot, Theme, User } from '@types'
@@ -58,7 +58,7 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
5858
else return null
5959
}
6060

61-
if (!bot) return <NotFound />
61+
if (!bot?.id) return <NotFound />
6262
if (!user)
6363
return (
6464
<Login>
@@ -70,6 +70,7 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
7070
!checkUserFlag(user.flags, 'staff')
7171
)
7272
return <Forbidden />
73+
const isPerkAvailable = checkBotFlag(bot.flags, 'trusted') || checkBotFlag(bot.flags, 'partnered')
7374
return (
7475
<Container paddingTop className='pb-10 pt-5'>
7576
<NextSeo title={`${bot.name} 수정하기`} description='봇의 정보를 수정합니다.' />
@@ -87,6 +88,9 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
8788
url: bot.url,
8889
git: bot.git,
8990
discord: bot.discord,
91+
vanity: isPerkAvailable && bot.vanity,
92+
banner: isPerkAvailable && bot.banner,
93+
bg: isPerkAvailable && bot.bg,
9094
_csrf: csrfToken,
9195
})}
9296
validationSchema={ManageBotSchema}
@@ -269,6 +273,44 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
269273
<Markdown text={values.desc} />
270274
</Segment>
271275
</Label>
276+
{
277+
isPerkAvailable && (
278+
<>
279+
<Divider />
280+
<h2 className='pt-2 text-2xl font-semibold text-koreanbots-green'>신뢰된 봇 특전 설정</h2>
281+
<span className='mt-1 text-sm text-gray-400'>신뢰된 봇의 혜택을 만나보세요. (커스텀 URL과 배너/배경 이미지는 이용약관 및 가이드라인을 준수해야하며 위반 시 신뢰된 봇 자격이 박탈될 수 있습니다.)</span>
282+
<Label
283+
For='vanity'
284+
label='한디리 커스텀 URL'
285+
labelDesc='고유한 커스텀 URL을 설정해주세요.'
286+
error={errors.vanity && touched.vanity ? errors.vanity : null}
287+
288+
>
289+
<div className='flex items-center'>
290+
koreanbots.dev/bots/
291+
<Input name='vanity' placeholder='koreanbots' />
292+
</div>
293+
294+
</Label>
295+
<Label
296+
For='banner'
297+
label='배너 URL'
298+
labelDesc='봇 목록의 카드에 표시되는 이미지입니다.'
299+
error={errors.banner && touched.banner ? errors.banner : null}
300+
>
301+
<Input name='banner' placeholder='https://koreanbots.dev/logo.png' />
302+
</Label>
303+
<Label
304+
For='bg'
305+
label='배경 URL'
306+
labelDesc='봇 페이지 배경에 표시되는 이미지입니다.'
307+
error={errors.bg && touched.bg ? errors.bg : null}
308+
>
309+
<Input name='bg' placeholder='https://koreanbots.dev/logo.png' />
310+
</Label>
311+
</>
312+
)
313+
}
272314
<Divider />
273315
<p className='mb-5 mt-2 text-base'>
274316
<span className='font-semibold text-red-500'> *</span> = 필수 항목
@@ -278,6 +320,7 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
278320
<i className='far fa-save' /> 저장
279321
</>
280322
</Button>
323+
281324
</Form>
282325
)}
283326
</Formik>
@@ -574,9 +617,11 @@ const ManageBotPage: NextPage<ManageBotProps> = ({ bot, user, csrfToken, theme }
574617
export const getServerSideProps = async (ctx: Context) => {
575618
const parsed = parseCookie(ctx.req)
576619
const user = await get.Authorization(parsed?.token)
620+
const bot = await get.bot.load(ctx.query.id)
621+
const spec = await get.botSpec(bot?.id || '', user || '')
577622
return {
578623
props: {
579-
bot: await get.bot.load(ctx.query.id),
624+
bot: { ...bot, banner: spec?.banner || null, bg: spec?.bg || null },
580625
user: await get.user.load(user || ''),
581626
csrfToken: getToken(ctx.req, ctx.res),
582627
},

pages/bots/koreanbots.tsx

Lines changed: 0 additions & 10 deletions
This file was deleted.

pages/servers/[id]/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ const Servers: NextPage<ServersProps> = ({ data, desc, date, user, theme }) => {
4242
const [emojisModal, setEmojisModal] = useState(false)
4343
const [ownersModal, setOwnersModal] = useState(false)
4444
const [owners, setOwners] = useState<User[]>(null)
45-
const bg = checkBotFlag(data?.flags, 'trusted') && data?.banner
45+
const bg =
46+
(checkBotFlag(data?.flags, 'trusted') || checkBotFlag(data?.flags, 'partnered')) && data?.bg
4647
const router = useRouter()
4748
useEffect(() => {
4849
if (data)
@@ -143,7 +144,12 @@ const Servers: NextPage<ServersProps> = ({ data, desc, date, user, theme }) => {
143144
</div>
144145
<div className='w-full lg:flex'>
145146
<div className='w-full text-center lg:w-2/12'>
146-
<ServerIcon id={data.id} size={256} className='w-full rounded-full' hash={data.icon} />
147+
<ServerIcon
148+
id={data.id}
149+
size={256}
150+
className='w-full rounded-full'
151+
hash={data.icon}
152+
/>
147153
</div>
148154
<div className='w-full grow px-5 py-12 text-center lg:w-5/12 lg:text-left'>
149155
<h1 className='mb-2 mt-3 text-4xl font-bold' style={bg ? { color: 'white' } : {}}>

types/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ export interface BotSpec {
8989
webhookURL: string | null
9090
webhookStatus: WebhookStatus
9191
token: string
92+
banner: string | null
93+
bg: string | null
9294
}
9395

9496
export interface ServerSpec {
@@ -351,7 +353,7 @@ export interface ImageOptions {
351353
export interface KoreanbotsImageOptions {
352354
format?: 'webp' | 'png' | 'gif'
353355
size?: 128 | 256 | 512
354-
hash?: string;
356+
hash?: string
355357
}
356358

357359
export enum DiscordImageType {

utils/Constants.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,3 +626,10 @@ export const GuildPermissions = {
626626
},
627627
],
628628
}
629+
630+
export const reservedVanityBypass = [
631+
'653534001742741552',
632+
'784618064167698472',
633+
'653083797763522580',
634+
'807561475014262785',
635+
]

utils/DiscordBot.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ export const webhookClients = {
5757
{ url: process.env.REPORT_WEBHOOK_URL ?? dummyURL },
5858
{ allowedMentions: { parse: [] } }
5959
),
60+
noticeLog: new Discord.WebhookClient(
61+
{ url: process.env.NOTICE_LOG_WEBHOOK_URL ?? dummyURL },
62+
{ allowedMentions: { parse: [] } }
63+
),
6064
},
6165
}
6266

0 commit comments

Comments
 (0)