diff --git a/commands/API/chat.js b/commands/API/chat.js index e182de1..0104a55 100644 --- a/commands/API/chat.js +++ b/commands/API/chat.js @@ -1,5 +1,6 @@ const { MongoClient, ServerApiVersion, ConnectionClosedEvent } = require('mongodb'); const { exit } = require('process'); +const { checkResponses } = require('./wordlist.js'); async function getResponse(convo, bot) { @@ -45,6 +46,11 @@ async function convoManager(clientinp, bot, message) { const doc = docs[0]; if (!doc) { return message.reply('You aren\'t currently in a conversation\nUse _!startconvo_ to start one!'); } + //Checking Section + const check = checkResponses(message.content, "I'm sorry, I can't do that"); + if (check != null) { return message.reply(check); } + + let convo = doc.convo; convo += `\nHuman: ${message.content}\n`;; @@ -62,6 +68,7 @@ async function convoManager(clientinp, bot, message) { }); } } + //"Hello! discord_user:" module.exports = { name: 'chat', diff --git a/commands/API/stripe.js b/commands/API/stripe.js new file mode 100644 index 0000000..86f9ed1 --- /dev/null +++ b/commands/API/stripe.js @@ -0,0 +1,175 @@ +/* +-----WEBHOOKS ARE RECIEVED AND MONITORED HERE----- +https://glitch.com/edit/#!/selmer-bot-listener +-------------------------------------------------- +*/ + +const { MongoClient, ServerApiVersion } = require('mongodb'); +const { MessageActionRow, MessageSelectMenu } = require('discord.js'); + + +//Called from the dropdown menu +async function createSubscriptionManual(bot, interaction, id, priceID) { + const stripe = bot.stripe; + const mongouri = bot.mongouri; + + //Start Error Checking + if (!id) { console.log('....What? How?'); return interaction.editReply("Uh oh, something happened with the Stripe Discord ID check, please contact support!"); } + + const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 }); + new Promise(async function(resolve, reject) { + client.connect(async (err) => { + if (err) { return console.log(err); } + + const dbo = client.db('main').collection('authorized'); + await dbo.findOne({'discordID': id}).then(async (doc) => { + var userID; + + if (doc != undefined) { + client.close(); + + reject(`An account with the tag <@${id}> already exists!`); + } else { + const stripeUser = await stripe.customers.create({ + metadata: { 'discordID': id } + }); + userID = stripeUser.id; + + //Add to the database (I have to wait for the insertion) + await dbo.insertOne({stripeID: userID, discordID: id, paid: false, startDateUTC: null, tier: 0}).then(() => { client.close(); resolve(userID); }); + } + }); + }); + + }).then(async (userID) => { + + //Deal with the session + const billingPortalSession = await stripe.billingPortal.sessions.create({ + customer: userID, + return_url: "https://linktr.ee/selmerbot", + }); + + + const session = await stripe.checkout.sessions.create( + { + payment_method_types: ["card"], + line_items: [ + { + price: priceID, + quantity: 1, + }, + ], + customer: userID, + mode: "subscription", + success_url: billingPortalSession.url, + cancel_url: "https://linktr.ee/selmerbot" + }); + + interaction.editReply(session.url); + }).catch((err) => { interaction.editReply(err); }) +} + + +async function changeSubscriptionManual(bot, message) { + const stripe = bot.stripe; + const mongouri = bot.mongouri; + const id = message.author.id; + + //Start Error Checking + if (!id) { return console.log('....What? How?'); } + + const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 }); + new Promise(async function(resolve, reject) { + client.connect(async (err) => { + if (err) { return console.log(err); } + + const dbo = client.db('main').collection('authorized'); + await dbo.findOne({'discordID': id}).then(async (doc) => { + var userID; + + if (doc != undefined) { + userID = doc.stripeID; + client.close(); + resolve(userID); + } else { + client.close(); + + reject(`No user with the ID of <@${message.author.id}>`); + } + }); + }); + + }).then(async (userID) => { + const session = await stripe.billingPortal.sessions.create({ + customer: userID, + return_url: "https://linktr.ee/selmerbot", + }); + message.reply(session.url); + // console.log(session.url); + }).catch((err) => { + message.reply(err); + // console.log(err); + }); +} + + +function createDropDown(bot, message) { + // const stripe = bot.stripe; + + const stripe = bot.stripe; + + const pl = []; + const vl = []; + stripe.products.list({ + limit: 3, + }).then((prod) => { + prod.data.forEach((obj) => { + const pricePromise = stripe.prices.retrieve(obj.default_price); + var newObj = {label: obj.name, description: null, value: `${obj.default_price}`} + pl.push(pricePromise); + vl.push(newObj); + }); + + let n = Promise.all(pl); + let i = 0; + n.then((t) => { + t.forEach(data => { + let price = data.unit_amount/100; + vl[i].description = `The $${price} tier`; + i++; + }); + + + const row = new MessageActionRow() + .addComponents( + new MessageSelectMenu() + .setCustomId(`${message.author.id}|premium`) + .setPlaceholder('Nothing selected') + .addOptions(vl) + ); + + message.channel.send({ content: `Please choose a tier`, components: [row] }); + }); + }); +} + + +function handleInp(bot, message) { + if (message.content == '!premium help') { + message.reply('Use _!premium buy_ to get premium or use _!premium manage_ to change or cancel your subscription\n_Disclaimer: Selmer Bot uses Stripe to manage payments. Read more at *https://stripe.com/ *_'); + } else if (message.content == '!premium buy') { + createDropDown(bot, message); + } else if (message.content == '!premium manage') { + changeSubscriptionManual(bot, message) + } + +} + + +module.exports = { + name: 'premium', + description: 'everything payment', + execute(message, args, Discord, Client, bot) { + message.reply("Please DM Selmer bot to use this command!"); + }, handleInp, createSubscriptionManual +} \ No newline at end of file diff --git a/commands/API/wordlist.js b/commands/API/wordlist.js new file mode 100644 index 0000000..8f93537 --- /dev/null +++ b/commands/API/wordlist.js @@ -0,0 +1,34 @@ +//Remember to strip all non-alpha chars from string (including ' ) + +wordlist = { + pay: ['pay me', 'give me money', 'send money', 'send me money', 'send cash', 'PayPal me', 'venmo me', 'cashapp me', 'cash app me'], + name: ['what is your name', 'whats your name', 'what are you called'] +} + + +function checkResponses(convoOG, answer) { + if (answer.indexOf("I'm sorry, I can't do that") == -1) { console.log('what?'); return 'none'} + // remove all uneccesary chars + convo = convoOG.replace(/\W/g, ' ').toLowerCase(); + + var b = 'none'; + wordlist.name.forEach((w) => { if (convo.includes(w)) { b = 'name'; return }}) + wordlist.pay.forEach((w) => { if (convo.includes(w)) { b = 'pay'; return }}) + + if (b === 'pay') { + //Exctract the number + var amt = convoOG.match(/(\d+)/)[0]; + + + if (matches) { + currency = convoOG[convoOG.indexOf(amt) - 1]; + //Do something with pay API to get the amount here + } + } else if (b == 'name') { + return 'My name is Selmer Bot!'; + } else { return null; } + + return b; +} + +module.exports = { checkResponses } \ No newline at end of file diff --git a/commands/dev only/spam_collection.js b/commands/dev only/spam_collection.js new file mode 100644 index 0000000..e07963f --- /dev/null +++ b/commands/dev only/spam_collection.js @@ -0,0 +1,60 @@ +// EVERYTHING IN THIS FILE SHOULD BE ABLE TO RUN INDEPENDANTLY OF THE BOT + + +const Stripe = require('stripe'); +const APIKey = process.env.APIKey // require('./config.json').APIKey; +const stripe = Stripe(APIKey); +const mongouri = process.env.APIKey // require('./config.json').mongooseURI; +const { MongoClient, ServerApiVersion } = require('mongodb'); + + +function cleardb(db) { + //Triggers about a week before the end of the month and clears out all the "spam" entries + const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 }); + new Promise(async function(resolve, reject) { + client.connect(async (err) => { + const dbo = client.db('main').collection(db); + dbo.find({paid: false, tier: 0}).toArray((err, docs) => { + if (err) { return console.log(err); } + + if (docs[0] != undefined) { + //Add them all to an array and resolve because deleting in a find() causes cyclic dependancies + resolve(docs); + } else { + reject(); + } + }); + }); + }).then((docs) => { + const dbo = client.db('main').collection(db); + const d = new Date().toUTCString(); + + //Keep track of what was collected (chack later?) + var newObj = {db: db, date: d, count: 0, results: []}; + + docs.forEach(i => { + //{discord id, stripe id} + newObj.results.push({did: i.discordID, sid: i.stripeID}); + newObj.count ++; + + try { + //For some reason, these aren't deleted in Stripe, just archived so they can't do anything new + //See https://stripe.com/docs/api/customers/delete + stripe.customers.del(i.stripeID); + } catch (err) { console.log("err"); } + }); + + dbo.deleteMany({paid: false, tier: 0}); + + //Add the newObj to another collection (ordered by date?) + const spam_coll = client.db('main').collection("spam_collection_results"); + + spam_coll.insertOne(newObj); + }).catch((err) => { console.log('none'); }); + + client.close(); +} + +module.exports = { cleardb } + +//Does not include the day check, see the "selmer-bot-listener" app for that \ No newline at end of file diff --git a/commands/dm_handler.js b/commands/dm_handler.js index 057e25a..d04e922 100644 --- a/commands/dm_handler.js +++ b/commands/dm_handler.js @@ -1,4 +1,5 @@ const { convoManager } = require('./API/chat.js'); +const { handleInp } = require('./API/stripe'); const { MongoClient, ServerApiVersion, ConnectionClosedEvent } = require('mongodb'); function handle_dm(message, bot) { @@ -24,6 +25,8 @@ function handle_dm(message, bot) { }); client.close(); + } else if (message.content.indexOf('!premium') != -1) { + handleInp(bot, message); } else { return message.reply('UNUSABLE DM COMMAND DETECTED'); } diff --git a/commands/interactionhandler.js b/commands/interactionhandler.js index f63af91..dd53dbf 100644 --- a/commands/interactionhandler.js +++ b/commands/interactionhandler.js @@ -1,4 +1,5 @@ const { MongoClient, ServerApiVersion } = require('mongodb'); +const { createSubscriptionManual } = require('./API/stripe.js'); async function handle_interaction(interaction, mongouri, turnManager, bot, STATE, items, xp_collection) { @@ -65,8 +66,7 @@ async function handle_interaction(interaction, mongouri, turnManager, bot, STATE //Menu Selection else if (interaction.isSelectMenu()) { const id = interaction.customId.substring(0, interaction.customId.indexOf('|')) - const command = interaction.customId.substring(interaction.customId.indexOf('|'), interaction.customId.length - interaction.customId.indexOf('|')) - console.log(command); + // const command = interaction.customId.substring(interaction.customId.indexOf('|'), interaction.customId.length - interaction.customId.indexOf('|')) if (interaction.customId.toLowerCase().indexOf('|heal') != -1) { const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 }); @@ -107,6 +107,16 @@ async function handle_interaction(interaction, mongouri, turnManager, bot, STATE }); } else if (interaction.customId.toLowerCase().indexOf('|item') != -1) { + } else if (interaction.customId.split('|')[1] == 'premium') { + //Check if the person subscribing and the person clicking are the same (group DM catch) + const user = interaction.customId.split('|')[0]; + if (interaction.user.id == user) { + // await interaction.deferReply(); + await interaction.update({ content: 'TIER SELECTED PLEASE HOLD', components: [] }); + await createSubscriptionManual(bot, interaction, user, interaction.values[0]); + + //Handle the interaction here + } } //menu else ifs here @@ -114,4 +124,7 @@ async function handle_interaction(interaction, mongouri, turnManager, bot, STATE } -module.exports = { handle_interaction } \ No newline at end of file +module.exports = { handle_interaction } + +//values: [ 'price_1LI5pzFtuywsbrwdlY1gWMkV' ] +//values: [ 'price_1LIpROFtuywsbrwdmxOb8Baj' ] \ No newline at end of file diff --git a/main.js b/main.js index 4281950..55d9c73 100644 --- a/main.js +++ b/main.js @@ -4,6 +4,7 @@ const { MongoClient, ServerApiVersion } = require('mongodb'); const fs = require('fs'); // const OpenAI = require('openai-api') const { Configuration, OpenAIApi } = require("openai"); +const Stripe = require('stripe'); const turnManager = require('./commands/turnManager.js'); const { welcome } = require('./commands/admin/welcome.js'); @@ -13,30 +14,31 @@ const { exit } = require('process'); const BASE_LVL_XP = 20; -//Token area +//#region Token area + //Adding integration for development mode let token; let IDM = false; let home_server; let MLAIKEY; - +let StripeAPIKey; if (process.env.token != undefined) { //Use "setx NAME VALUE" in the local powershell terminal to set token = process.env.token; home_server = process.env.home_server; MLAIKEY = process.env.MLAIKEY; + StripeAPIKey = process.env.StripeAPIKey; } else { token = require('./config.json').token; home_server = require('./config.json').home_server; IDM = true; - MLAIKEY = new require('./config.json').MLAIKEY; + MLAIKEY = require('./config.json').MLAIKEY; + StripeAPIKey = require('./config.json').StripeAPIKey; } -// const { token } = require('./config.json'); -//Heroku part -// const { token } = process.env.token; +//#endregion const bot = new Client({ intents: [ @@ -65,9 +67,10 @@ const configuration = new Configuration({ }); bot.openai = new OpenAIApi(configuration); bot.temptext = ''; +bot.stripe = Stripe(StripeAPIKey); -//MongoDB integration +//#region MongoDB integration //Development support let mongouritemp; if (process.env.MONGODB_URI) { @@ -79,62 +82,47 @@ const mongouri = mongouritemp; bot.mongouri = mongouri; const { connect } = require('mongoose'); -bot.on("guildCreate", guild => { - guild.roles.create({ name: 'Selmer Bot Mod' }); - - //const role = guild.roles.cache.find((role) => role.name === 'Selmer Bot Mod'); // member.roles.cache.has('role-id-here'); - const server = bot.guilds.cache.get(guild.id); - const owner = server.members.fetch(guild.ownerId).then(function(owner) { - owner.send('Thank you for adding Selmer Bot to your server!\nPlease give people you want to have access to Selmer Bot\'s restricted commands the "_Selmer Bot Mod_" role.'); - owner.send('To help set up Selmer Bot to work better with your server, use _!setup help_ in a channel Selmer Bot is in!'); - }); - - //Set up the server - const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 }); - client.connect(err => { - if (err) { return console.log(err); } - - const dbo = client.db(guild.id).collection('SETUP'); - dbo.insertMany([{_id: 'WELCOME', 'welcomechannel': null, 'welcomemessage': null, 'welcomebanner': null}]); - }); - - client.close(); -}); +//#endregion MongoDB Integration end -//MongoDB Integration end -// let item = items.filter(function (item) { return item.name.toLowerCase() == 'grapes'; }); +//#region set up bot commands + +// const commandFiles = fs.readdirSync('./commands/').filter(file => file.endsWith('.js')); // Obsolete? bot.commands = new Discord.Collection(); +const forbiddenFolders = ['db', 'API', 'dev only']; -const commandFiles = fs.readdirSync('./commands/').filter(file => file.endsWith('.js')); - - -bot.commands = new Discord.Collection(); fs.readdirSync('./commands') .forEach(dir => { - if (dir != 'db' && !dir.endsWith('.js')) { + if (!forbiddenFolders.includes(dir) && !dir.endsWith('.js')) { fs.readdirSync(`./commands/${dir}`) .filter(file => file.endsWith('.js')) .forEach(file => { const command = require(`./commands/${dir}/${file}`); bot.commands.set(command.name, command); }); - } + } else { console.log(dir); } }); - //Set these two manually because all the seperate games can't be included in the command list (all managed by the 'game' file) +//Set these two manually because all the seperate games can't be included in the command list (all managed by the 'game' file) let temp_command = require("./commands/db/econ.js"); const { STATE } = require('./commands/db/econ.js'); bot.commands.set('econ', temp_command); temp_command = require('./commands/games/game.js'); bot.commands.set('game', temp_command); -// const econFiles = fs.readdirSync('./commands/inventory').filter(file => file.endsWith('.js'));; -// const currency = new Discord.Collection(); -// const { Users } = require('./commands/currency/dbObjects.js'); -// i++; +//Everything in the API should be handled by specific handler functions +const chat = require('./commands/API/chat.js'); +bot.commands.set('chat', chat); +const stripeCommands = require('./commands/API/stripe.js'); +bot.commands.set('premium', stripeCommands); + +//#endregion + + + +//#region bot.[anything] section //XP Table section let xp_collection = new Map(); @@ -188,6 +176,32 @@ bot.on('interactionCreate', async interaction => { }); + +//Add the bot to a server setup +bot.on("guildCreate", guild => { + guild.roles.create({ name: 'Selmer Bot Mod' }); + + //const role = guild.roles.cache.find((role) => role.name === 'Selmer Bot Mod'); // member.roles.cache.has('role-id-here'); + const server = bot.guilds.cache.get(guild.id); + const owner = server.members.fetch(guild.ownerId).then(function(owner) { + owner.send('Thank you for adding Selmer Bot to your server!\nPlease give people you want to have access to Selmer Bot\'s restricted commands the "_Selmer Bot Mod_" role.'); + owner.send('To help set up Selmer Bot to work better with your server, use _!setup help_ in a channel Selmer Bot is in!'); + }); + + //Set up the server + const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 }); + client.connect(err => { + if (err) { return console.log(err); } + + const dbo = client.db(guild.id).collection('SETUP'); + dbo.insertMany([{_id: 'WELCOME', 'welcomechannel': null, 'welcomemessage': null, 'welcomebanner': null}]); + }); + + client.close(); +}); + + + //Welcome new members bot.on('guildMemberAdd', async (member) => { //Check for impartial data @@ -253,9 +267,7 @@ bot.on('messageCreate', (message) => { else { bot.commands.get('econ').execute(bot, message, args, command, Discord, mongouri, items, xp_collection); } }) -//Look into integrating MySQL into SelmerBot instead of SQLite +//#endregion //Last Line(s) -// bot.login(token); - bot.login(token); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f24558a..099f093 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "random-memes": "^3.1.0", "sequelize": "^6.19.0", "sqlite3": "^5.0.3", + "stripe": "^9.11.0", "sudo": "^1.0.3", "undici": "^5.4.0", "youtube-mp3-downloader": "^0.7.10", @@ -831,6 +832,18 @@ "node": ">= 10" } }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/canvas": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.9.1.tgz", @@ -1448,6 +1461,11 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -1467,6 +1485,19 @@ "node": ">=10" } }, + "node_modules/get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -1521,6 +1552,28 @@ "node": ">=6" } }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -4617,6 +4670,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5042,6 +5103,19 @@ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/sift": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", @@ -5229,6 +5303,32 @@ "node": ">=8" } }, + "node_modules/stripe": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-9.11.0.tgz", + "integrity": "sha512-+BlGhp3xyey9uVdd32xa7t9qnJC7mQASNWa1j/tIoP1k4xYOn0ZPqCNR/IlWh8c3zfYCA7CWFWBng1tqZlR+nA==", + "dependencies": { + "@types/node": ">=8.1.0", + "qs": "^6.10.3" + }, + "engines": { + "node": "^8.1 || >=10.*" + } + }, + "node_modules/stripe/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/sudo": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sudo/-/sudo-1.0.3.tgz", @@ -6216,6 +6316,15 @@ "unique-filename": "^1.1.1" } }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "canvas": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.9.1.tgz", @@ -6655,6 +6764,11 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, "gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -6671,6 +6785,16 @@ "wide-align": "^1.1.2" } }, + "get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -6712,6 +6836,19 @@ "har-schema": "^2.0.0" } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -8892,6 +9029,11 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -9218,6 +9360,16 @@ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "sift": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", @@ -9349,6 +9501,25 @@ "ansi-regex": "^5.0.1" } }, + "stripe": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-9.11.0.tgz", + "integrity": "sha512-+BlGhp3xyey9uVdd32xa7t9qnJC7mQASNWa1j/tIoP1k4xYOn0ZPqCNR/IlWh8c3zfYCA7CWFWBng1tqZlR+nA==", + "requires": { + "@types/node": ">=8.1.0", + "qs": "^6.10.3" + }, + "dependencies": { + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, "sudo": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sudo/-/sudo-1.0.3.tgz", diff --git a/package.json b/package.json index ee7f615..5fc1d3f 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "random-memes": "^3.1.0", "sequelize": "^6.19.0", "sqlite3": "^5.0.3", + "stripe": "^9.11.0", "sudo": "^1.0.3", "undici": "^5.4.0", "youtube-mp3-downloader": "^0.7.10",