2022-05-13 17:01:16 +00:00
const { SlashCommandBuilder } = require ( '@discordjs/builders' ) ;
const { parse } = require ( "csv-parse/sync" ) ;
const fs = require ( 'node:fs' ) ;
const noblox = require ( "noblox.js" ) ;
2022-10-22 04:04:23 +00:00
const axios = require ( "axios" ) . default ;
2024-04-15 08:13:32 +00:00
const { submissions , commands , cookies } = require ( "../config/config.js" ) ;
2024-08-28 04:11:28 +00:00
const { getAssetInfo , SubmissionColumnsString , createSubmissionLine , getSubmissionLine , validateMapAsset , getValidationMessage } = require ( "../common.js" ) ;
2022-07-12 02:09:07 +00:00
async function robloxUserFromDiscord ( id ) {
if ( isNaN ( id ) ) return undefined ;
try {
2022-10-22 04:04:23 +00:00
const res = await axios . get ( ` https://api.fiveman1.net/v1/users/ ${ id } ` ) ;
return res . data . result . robloxId ;
2024-04-24 06:28:07 +00:00
} catch {
2022-07-12 02:09:07 +00:00
return undefined ;
}
}
async function robloxUsernameFromId ( id ) {
if ( isNaN ( id ) ) return undefined ;
try {
2022-10-22 04:04:23 +00:00
const res = await axios . get ( ` https://users.roblox.com/v1/users/ ${ id } ` ) ;
return res . data . name ;
2024-04-24 06:28:07 +00:00
} catch {
2022-07-12 02:09:07 +00:00
return undefined ;
}
}
2022-05-13 17:01:16 +00:00
2024-04-24 06:28:07 +00:00
/ * *
* @ param { import ( 'discord.js' ) . ChatInputCommandInteraction } interaction
* /
2022-05-13 17:01:16 +00:00
async function execute ( interaction ) {
2022-10-22 04:04:23 +00:00
const userId = await robloxUserFromDiscord ( interaction . user . id ) ;
2022-07-12 02:09:07 +00:00
if ( ! userId ) {
2024-04-25 17:33:55 +00:00
await interaction . editReply ( "🚫 You don't have a Roblox account linked with your Discord account. Use !link with the rbhop dog bot to link your account." ) ;
2022-07-12 02:09:07 +00:00
return ;
}
2022-05-13 17:01:16 +00:00
2024-04-25 17:33:55 +00:00
const game = interaction . options . getString ( "game" , true ) ;
2023-03-08 20:37:40 +00:00
const fname = submissions [ game ] ;
if ( fname === undefined ) {
2024-04-25 17:33:55 +00:00
await interaction . editReply ( "🚫 Invalid game specified!" ) ;
2022-05-13 17:01:16 +00:00
return ;
}
if ( ! fs . existsSync ( fname ) ) {
2024-04-17 00:58:24 +00:00
fs . writeFileSync ( fname , SubmissionColumnsString ) ;
2022-05-13 17:01:16 +00:00
}
2024-04-24 06:28:07 +00:00
const id = interaction . options . getInteger ( "asset_id" , true ) ;
2024-08-28 02:28:33 +00:00
noblox . setCookie ( cookies [ game ] , false ) ;
2024-04-15 08:13:32 +00:00
2024-04-25 17:33:55 +00:00
try {
// Check that the bot owns this model
2024-08-28 04:11:28 +00:00
const robloxUser = await noblox . getAuthenticatedUser ( ) ;
if ( ! ( await noblox . getOwnership ( robloxUser . id , id , "Asset" ) ) ) {
2024-08-27 02:38:17 +00:00
const msg = ` 🚫 The ${ game } maptest bot's inventory does not contain this asset (id: \` ${ id } \` ). You must use the /take command first. ` ;
2024-04-25 17:33:55 +00:00
await interaction . editReply ( msg ) ;
return ;
}
} catch ( error ) {
if ( error . message !== "400 The specified Asset does not exist!" ) {
throw error ;
}
2024-08-27 02:38:17 +00:00
await interaction . editReply ( ` 🚫 This asset does not exist (id: \` ${ id } \` ). ` ) ;
2024-04-15 08:13:32 +00:00
return ;
}
2024-04-16 02:15:35 +00:00
const assetInfo = await getAssetInfo ( id ) ;
2024-08-22 03:48:30 +00:00
if ( ! assetInfo . isModel ) {
2024-08-27 02:38:17 +00:00
await interaction . editReply ( ` 🚫 This asset (id: \` ${ id } \` ) is not a model. Your map must be a model. ` ) ;
2024-04-25 17:33:55 +00:00
return ;
}
2024-04-16 02:17:33 +00:00
if ( assetInfo . creatorId !== userId ) {
2024-04-16 02:15:35 +00:00
const assetUsernamePromise = robloxUsernameFromId ( assetInfo . creatorId ) ;
const interactionUsernamePromise = robloxUsernameFromId ( userId ) ;
const assetUsername = await assetUsernamePromise ;
const interactionUsername = await interactionUsernamePromise ;
2024-04-25 17:33:55 +00:00
const msg = ` 🚫 The account linked to your Discord ( ${ interactionUsername } ) is not the owner of this model ( ${ assetUsername } ), so you cannot submit it. ` ;
await interaction . editReply ( msg ) ;
2022-05-13 17:01:16 +00:00
return ;
}
2024-04-17 00:58:24 +00:00
const csvFile = fs . readFileSync ( fname ) ;
const lines = parse ( csvFile , { delimiter : ',' , fromLine : 2 } ) ;
2022-05-13 17:01:16 +00:00
2024-04-17 00:58:24 +00:00
for ( let lineStr of lines ) {
const line = getSubmissionLine ( lineStr ) ;
if ( id === line . modelId ) {
2024-08-27 02:38:17 +00:00
await interaction . editReply ( ` 🚫 This map (id: \` ${ id } \` ) was already submitted on <t: ${ line . timestamp } :d>. ` ) ;
2022-05-13 17:01:16 +00:00
return ;
}
2024-04-24 06:28:07 +00:00
}
2024-04-24 16:03:25 +00:00
// Validate and send the validation result
const validation = await validateMapAsset ( id , game ) ;
2024-04-24 06:28:07 +00:00
const msg = getValidationMessage ( validation , game , true ) ;
2024-04-24 16:03:25 +00:00
await interaction . editReply ( msg ) ;
2024-04-24 06:28:07 +00:00
if ( ! validation . valid ) {
await interaction . followUp ( "Due to having problems, your map was **NOT submitted**." ) ;
return ;
}
2022-05-13 17:01:16 +00:00
2024-04-24 06:28:07 +00:00
let csvString = SubmissionColumnsString ;
for ( let lineStr of lines ) {
const line = getSubmissionLine ( lineStr ) ;
csvString += createSubmissionLine ( line . modelId , line . timestamp , line . userId , line . username , line . displayName , line . creator ) ;
2024-04-17 00:58:24 +00:00
}
2022-05-13 17:01:16 +00:00
2024-04-17 00:58:24 +00:00
const unixTimestamp = Math . round ( + new Date ( ) / 1000 ) ;
2024-04-24 06:28:07 +00:00
csvString += createSubmissionLine ( id , unixTimestamp , userId , await robloxUsernameFromId ( userId ) , validation . displayName , validation . creator ) ;
2024-04-17 00:58:24 +00:00
fs . writeFileSync ( fname , csvString ) ;
2022-05-13 17:01:16 +00:00
2024-08-27 02:38:17 +00:00
await interaction . followUp ( ` Map (id: \` ${ id } \` ) successfully submitted. ` ) ;
2022-05-13 17:01:16 +00:00
}
module . exports = {
data : new SlashCommandBuilder ( )
. setName ( 'submit' )
. setDescription ( 'Submit your map' )
. addStringOption ( option =>
option . setName ( "game" )
. setDescription ( "Select the maptest game" )
. setRequired ( true )
2023-03-19 02:21:59 +00:00
. addChoices ( ... commands ) )
2022-05-13 17:01:16 +00:00
. addIntegerOption ( option =>
option . setName ( "asset_id" )
. setDescription ( "The asset ID of the model" )
. setRequired ( true ) )
,
execute
2024-04-15 08:13:32 +00:00
} ;