diff --git a/commands/submit.js b/commands/submit.js index ee44dfb..aecfd87 100644 --- a/commands/submit.js +++ b/commands/submit.js @@ -48,7 +48,7 @@ async function execute(interaction) { const id = interaction.options.getInteger("asset_id"); try { - const info = await noblox.getProductInfo(id); + const info = await getProductInfo(id); if (info.AssetTypeId != 10) { await interaction.reply({content: `(id: ${id}) is not a valid model ID.`, ephemeral: true}); return; @@ -104,4 +104,37 @@ module.exports = { .setRequired(true)) , execute -}; \ No newline at end of file +}; + +function getProductInfo (asset) { + return new Promise(async (resolve, reject) => { + const httpOpt = { + url: `//economy.roblox.com/v2/assets/${asset}/details`, + options: { + resolveWithFullResponse: true, + method: 'GET' + } + } + try { + const res = await noblox.http(httpOpt); + if (res.statusCode === 200) { + resolve(JSON.parse(res.body)); + } else { + // Sourced from: https://stackoverflow.com/a/32278428 + const isAnObject = (val_1) => !!(val_1 instanceof Array || val_1 instanceof Object); + + const body = isAnObject(res.body) ? JSON.parse(res.body) : {}; + if (body.errors && body.errors.length > 0) { + const errors = body.errors.map((e) => { + return e.message; + }); + reject(new Error(`${res.statusCode} ${errors.join(', ')}`)); + } else { + reject(new Error(`${res.statusCode} ${res.body}`)); + } + } + } catch (error) { + return reject(error); + } + }) +} \ No newline at end of file diff --git a/commands/take.js b/commands/take.js index 7bfaa99..98795ef 100644 --- a/commands/take.js +++ b/commands/take.js @@ -14,10 +14,10 @@ async function execute(interaction) { } const id = interaction.options.getInteger("asset_id"); await noblox.setCookie(cookie).then(async () => { - + let info; // validate that this is a model try { - const info = await noblox.getProductInfo(id); + info = await getProductInfo(id); if (info.AssetTypeId != 10) { await interaction.reply({content: `(id: ${id}) is not a valid model ID.`, ephemeral: true}); return; @@ -28,7 +28,7 @@ async function execute(interaction) { return; } - noblox.buy(id, 0).then(async () => { + buy(undefined, await noblox.getGeneralToken(), info, 0).then(async () => { await interaction.reply( ` Now that your map (id: ${id}) has been taken by the ${game} maptest bot you can load it into the ${game} maptest place. To load your map, join the game and say @@ -66,4 +66,89 @@ module.exports = { .setRequired(true)) , execute -}; \ No newline at end of file +}; + +async function buy (jar, token, product, price) { + const robux = product.PriceInRobux || 0 + const productId = product.ProductId + if (price) { + if (typeof price === 'number') { + if (robux !== price) { + throw new Error('Price requirement not met. Requested price: ' + price + ' Actual price: ' + robux) + } + } else if (typeof price === 'object') { + const high = price.high + const low = price.low + if (high) { + if (robux > high) { + throw new Error('Price requirement not met. Requested price: <=' + high + ' Actual price: ' + robux) + } + } + if (low) { + if (robux < low) { + throw new Error('Price requirement not met. Requested price: >=' + low + ' Actual price: ' + robux) + } + } + } + } + const httpOpt = { + url: '//economy.roblox.com/v1/purchases/products/' + productId, + options: { + method: 'POST', + jar: jar, + headers: { + 'X-CSRF-TOKEN': token + }, + json: { + expectedCurrency: 1, + expectedPrice: robux, + expectedSellerId: product.Creator.Id + } + } + } + const json = await noblox.http(httpOpt); + let err = json.errorMsg; + if (json.reason === 'InsufficientFunds') { + err = 'You need ' + json.shortfallPrice + ' more robux to purchase this item.'; + } else if (json.errorMsg) { + err = json.errorMsg; + } + if (!err) { + return { productId, price: robux }; + } else { + throw new Error(err); + } +} + +function getProductInfo (asset) { + return new Promise(async (resolve, reject) => { + const httpOpt = { + url: `//economy.roblox.com/v2/assets/${asset}/details`, + options: { + resolveWithFullResponse: true, + method: 'GET' + } + } + try { + const res = await noblox.http(httpOpt); + if (res.statusCode === 200) { + resolve(JSON.parse(res.body)); + } else { + // Sourced from: https://stackoverflow.com/a/32278428 + const isAnObject = (val_1) => !!(val_1 instanceof Array || val_1 instanceof Object); + + const body = isAnObject(res.body) ? JSON.parse(res.body) : {}; + if (body.errors && body.errors.length > 0) { + const errors = body.errors.map((e) => { + return e.message; + }); + reject(new Error(`${res.statusCode} ${errors.join(', ')}`)); + } else { + reject(new Error(`${res.statusCode} ${res.body}`)); + } + } + } catch (error) { + return reject(error); + } + }) +} \ No newline at end of file