feat: add open review deny log and max denies restriction (#510)

* feat: add open review log channel and embed

* chore: do not include submit page

* chore: mention instead of date

* feat: add max denies error

* typo: 더 이상

Co-authored-by: Junseo Park <wonderlandpark@outlook.kr>

* feat: add exceptions to deny count

* fix: invalid embed used

Co-authored-by: Junseo Park <wonderlandpark@outlook.kr>

* fix: invalid guild

Co-authored-by: Junseo Park <wonderlandpark@outlook.kr>

* fix: invalid position

Co-authored-by: Junseo Park <wonderlandpark@outlook.kr>

* fix: proper reason check position

Co-authored-by: Junseo Park <wonderlandpark@outlook.kr>

* feat: sepcific error message

* refactor: change reason embed format

* fix: knex andWhereNot method to whereNotIn method

Co-authored-by: Junseo Park <wonderlandpark@outlook.kr>
This commit is contained in:
Eunwoo Choi 2022-08-15 21:22:55 +09:00 committed by GitHub
parent ca55dc8597
commit 516f72ad08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 15 deletions

View File

@ -76,6 +76,12 @@ const Bots = RequestHandler()
message: '디스코드 서버에 참가해주세요.', message: '디스코드 서버에 참가해주세요.',
errors: ['봇 신청하시기 위해서는 공식 디스코드 서버에 참가해주셔야합니다.'], errors: ['봇 신청하시기 위해서는 공식 디스코드 서버에 참가해주셔야합니다.'],
}) })
else if (result === 5)
return ResponseWrapper(res, {
code: 403,
message: '더 이상 해당 봇에 대한 심사 요청을 하실 수 없습니다.',
errors: ['해당 봇은 심사에서 3회 이상 거부되었습니다. 더 이상의 심사를 요청하실 수 없습니다.', '이의 제기를 원하시는 경우 디스코드 서버를 통해 문의해주세요.'],
})
get.botSubmits.clear(user) get.botSubmits.clear(user)
await discordLog('BOT/SUBMIT', user, new MessageEmbed().setDescription(`[${result.id}/${result.date}](${KoreanbotsEndPoints.URL.submittedBot(result.id, result.date)})`), { await discordLog('BOT/SUBMIT', user, new MessageEmbed().setDescription(`[${result.id}/${result.date}](${KoreanbotsEndPoints.URL.submittedBot(result.id, result.date)})`), {
@ -154,7 +160,7 @@ const Bots = RequestHandler()
) )
return ResponseWrapper(res, { code: 200 }) return ResponseWrapper(res, { code: 200 })
} }
}) })
interface GetApiRequest extends NextApiRequest { interface GetApiRequest extends NextApiRequest {

View File

@ -5,7 +5,7 @@ import tracer from 'dd-trace'
import RequestHandler from '@utils/RequestHandler' import RequestHandler from '@utils/RequestHandler'
import ResponseWrapper from '@utils/ResponseWrapper' import ResponseWrapper from '@utils/ResponseWrapper'
import { get, update } from '@utils/Query' import { get, update } from '@utils/Query'
import { DiscordBot, getBotReviewLogChannel } from '@utils/DiscordBot' import { DiscordBot, getBotReviewLogChannel, getOpenBotReviewLogChannel } from '@utils/DiscordBot'
import { BotSubmissionDenyReasonPresetsName, KoreanbotsEndPoints } from '@utils/Constants' import { BotSubmissionDenyReasonPresetsName, KoreanbotsEndPoints } from '@utils/Constants'
const DenyBotSubmit = RequestHandler() const DenyBotSubmit = RequestHandler()
@ -20,6 +20,9 @@ const DenyBotSubmit = RequestHandler()
const embed = new MessageEmbed().setTitle('거부').setColor('RED').setDescription(`[${submit.id}/${submit.date}](${KoreanbotsEndPoints.URL.submittedBot(submit.id, submit.date)})`).setTimestamp() const embed = new MessageEmbed().setTitle('거부').setColor('RED').setDescription(`[${submit.id}/${submit.date}](${KoreanbotsEndPoints.URL.submittedBot(submit.id, submit.date)})`).setTimestamp()
if(req.body.reviewer || req.body.reason) embed.addField('📃 정보', `${req.body.reason ? `사유: ${BotSubmissionDenyReasonPresetsName[req.body.reason] || req.body.reason}\n`: ''}${req.body.reviewer ? `심사자: ${req.body.reviewer}` : ''}`) if(req.body.reviewer || req.body.reason) embed.addField('📃 정보', `${req.body.reason ? `사유: ${BotSubmissionDenyReasonPresetsName[req.body.reason] || req.body.reason}\n`: ''}${req.body.reviewer ? `심사자: ${req.body.reviewer}` : ''}`)
await getBotReviewLogChannel().send(embed) await getBotReviewLogChannel().send(embed)
const openEmbed = new MessageEmbed().setTitle('거부').setColor('RED').setDescription(`<@${submit.id}> (${submit.id})`).setTimestamp()
if(req.body.reason) openEmbed.addField('📃 사유', `${req.body.reason ? `${BotSubmissionDenyReasonPresetsName[req.body.reason] || req.body.reason}\n`: '없음'}`)
await getOpenBotReviewLogChannel().send(openEmbed)
tracer.trace('botSubmits.deny', span => { tracer.trace('botSubmits.deny', span => {
span.setTag('id', submit.id) span.setTag('id', submit.id)
span.setTag('date', submit.date) span.setTag('date', submit.date)
@ -41,4 +44,4 @@ interface ApiRequest extends NextApiRequest {
} }
} }
export default DenyBotSubmit export default DenyBotSubmit

View File

@ -10,6 +10,7 @@ const statsLoggingChannelID = '653227346962153472'
const reviewGuildID = '906537041326637086' const reviewGuildID = '906537041326637086'
const botReviewLogChannelID = '906551334063439902' const botReviewLogChannelID = '906551334063439902'
const openBotReviewLogChannelID = '1008376563731013643'
DiscordBot.on('ready', async () => { DiscordBot.on('ready', async () => {
console.log('I\'m Ready') console.log('I\'m Ready')
@ -25,9 +26,10 @@ export const getReportChannel = (): Discord.TextChannel => getMainGuild().channe
export const getLoggingChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(loggingChannelID) as Discord.TextChannel export const getLoggingChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(loggingChannelID) as Discord.TextChannel
export const getBotReviewLogChannel = (): Discord.TextChannel => getReviewGuild().channels.cache.get(botReviewLogChannelID) as Discord.TextChannel export const getBotReviewLogChannel = (): Discord.TextChannel => getReviewGuild().channels.cache.get(botReviewLogChannelID) as Discord.TextChannel
export const getStatsLoggingChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(statsLoggingChannelID) as Discord.TextChannel export const getStatsLoggingChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(statsLoggingChannelID) as Discord.TextChannel
export const getOpenBotReviewLogChannel = (): Discord.TextChannel => getMainGuild().channels.cache.get(openBotReviewLogChannelID) as Discord.TextChannel
export const discordLog = async (type: string, issuerID: string, embed?: Discord.MessageEmbed, attachment?: { content: string, format: string}, content?: string): Promise<void> => { export const discordLog = async (type: string, issuerID: string, embed?: Discord.MessageEmbed, attachment?: { content: string, format: string}, content?: string): Promise<void> => {
getLoggingChannel().send({ getLoggingChannel().send({
content: `[${type}] <@${issuerID}> (${issuerID})\n${content || ''}`, content: `[${type}] <@${issuerID}> (${issuerID})\n${content || ''}`,
embed: embed && embed.setTitle(type).setTimestamp(new Date()), embed: embed && embed.setTitle(type).setTimestamp(new Date()),
...(attachment && { files: [ ...(attachment && { files: [
@ -35,4 +37,4 @@ export const discordLog = async (type: string, issuerID: string, embed?: Discord
] ]
}) })
}) })
} }

View File

@ -66,7 +66,7 @@ async function getBot(id: string, topLevel=true):Promise<Bot> {
} }
await knex('bots').update({ name: discordBot.username }).where({ id }) await knex('bots').update({ name: discordBot.username }).where({ id })
} }
return res[0] ?? null return res[0] ?? null
@ -388,12 +388,15 @@ async function voteServer(userID: string, serverID: string): Promise<number|bool
* @returns 2 - Already submitted ID * @returns 2 - Already submitted ID
* @returns 3 - Bot User does not exists * @returns 3 - Bot User does not exists
* @returns 4 - Discord not Joined * @returns 4 - Discord not Joined
* @returns 5 - 3 or more denies
* @returns obj - Success * @returns obj - Success
*/ */
async function submitBot(id: string, data: AddBotSubmit):Promise<1|2|3|4|SubmittedBot> { async function submitBot(id: string, data: AddBotSubmit):Promise<1|2|3|4|5|SubmittedBot> {
const submits = await knex('submitted').select(['id']).where({ state: 0 }).andWhere('owners', 'LIKE', `%${id}%`) const submits = await knex('submitted').select(['id']).where({ state: 0 }).andWhere('owners', 'LIKE', `%${id}%`)
if(submits.length > 1) return 1 if(submits.length > 1) return 1
const botId = data.id const botId = data.id
const identicalSubmits = await knex('submitted').select(['id']).where({ id: botId, state: 2 }).whereNotIn('reason', ['PRIVATE', 'OFFLINE', 'ABSENT_AT_DISCORD']) // 다음 사유를 제외한 다른 사유의 3회 이상 거부 존재시 봇 등록 제한.
if(identicalSubmits.length >= 3) return 5
const date = Math.round(+new Date()/1000) const date = Math.round(+new Date()/1000)
const sameID = await knex('submitted').select(['id']).where({ id: botId, state: 0 }) const sameID = await knex('submitted').select(['id']).where({ id: botId, state: 0 })
const bot = await get.bot.load(data.id) const bot = await get.bot.load(data.id)
@ -417,7 +420,7 @@ async function submitBot(id: string, data: AddBotSubmit):Promise<1|2|3|4|Submitt
discord: data.discord, discord: data.discord,
state: 0 state: 0
}) })
return await getBotSubmit(botId, date) return await getBotSubmit(botId, date)
} }
@ -565,8 +568,8 @@ async function getDiscordUser(id: string):Promise<DiscordUser> {
} }
/** /**
* *
* @param info * @param info
* @returns 1 - UnVerified * @returns 1 - UnVerified
* @returns 2 - Blocked * @returns 2 - Blocked
*/ */
@ -747,14 +750,14 @@ export const get = {
serverSpec: getServerSpec, serverSpec: getServerSpec,
list: { list: {
category: new DataLoader( category: new DataLoader(
async (key: string[]) => async (key: string[]) =>
(await Promise.all(key.map(async (k: string) => { (await Promise.all(key.map(async (k: string) => {
const json = JSON.parse(k) const json = JSON.parse(k)
return await getBotList('CATEGORY', json.page, json.category) return await getBotList('CATEGORY', json.page, json.category)
}))).map(row => serialize(row)) }))).map(row => serialize(row))
, { cacheMap: new TLRU({ maxStoreSize: 50, maxAgeMs: 500000 }) }), , { cacheMap: new TLRU({ maxStoreSize: 50, maxAgeMs: 500000 }) }),
search: new DataLoader( search: new DataLoader(
async (key: string[]) => async (key: string[]) =>
(await Promise.all(key.map(async (k: string) => { (await Promise.all(key.map(async (k: string) => {
const json = JSON.parse(k) const json = JSON.parse(k)
const res = await getBotList('SEARCH', json.page, json.query) const res = await getBotList('SEARCH', json.page, json.query)
@ -776,14 +779,14 @@ export const get = {
}, },
serverList: { serverList: {
category: new DataLoader( category: new DataLoader(
async (key: string[]) => async (key: string[]) =>
(await Promise.all(key.map(async (k: string) => { (await Promise.all(key.map(async (k: string) => {
const json = JSON.parse(k) const json = JSON.parse(k)
return await getServerList('CATEGORY', json.page, json.category) return await getServerList('CATEGORY', json.page, json.category)
}))).map(row => serialize(row)) }))).map(row => serialize(row))
, { cacheMap: new TLRU({ maxStoreSize: 50, maxAgeMs: 500000 }) }), , { cacheMap: new TLRU({ maxStoreSize: 50, maxAgeMs: 500000 }) }),
search: new DataLoader( search: new DataLoader(
async (key: string[]) => async (key: string[]) =>
(await Promise.all(key.map(async (k: string) => { (await Promise.all(key.map(async (k: string) => {
const json = JSON.parse(k) const json = JSON.parse(k)
const res = await getServerList('SEARCH', json.page, json.query) const res = await getServerList('SEARCH', json.page, json.query)
@ -857,4 +860,4 @@ export const ratelimit = {
addRequest(ip, imageRateLimit) addRequest(ip, imageRateLimit)
return imageRateLimit.get(ip) return imageRateLimit.get(ip)
} }
} }