Added Payment Authorization Middleware
- Default options for commands - Verify user has enough balance to create the transaction - Need to create methods to create transactions
This commit is contained in:
@@ -14,34 +14,34 @@ module.exports = {
|
||||
.setRequired(true))
|
||||
.addNumberOption(option =>
|
||||
option.setName('temperature')
|
||||
.setDescription('Set the temperature, 0 = repetitive, 1 = random')
|
||||
.setDescription('Set the temperature, 0 = repetitive, 1 = random; Defaults to 0')
|
||||
.setRequired(false))
|
||||
.addNumberOption(option =>
|
||||
option.setName('tokens')
|
||||
.setDescription('The max amount of tokens to be spent')
|
||||
.setRequired(false)),
|
||||
example: "chat [tell me a story] [0.07] []", // Need to figure out the tokens
|
||||
isPrivileged: true,
|
||||
isPrivileged: false,
|
||||
requiresTokens: true,
|
||||
defaultTokenUsage: 100,
|
||||
deferInitialReply: true,
|
||||
async execute(interaction) {
|
||||
// Needs middleware for payment
|
||||
try {
|
||||
var params = {};
|
||||
var promptText = interaction.options.getString('prompt');
|
||||
var temperature = interaction.options.getNumber('temperature');
|
||||
var maxTokens = interaction.options.getNumber('tokens') ?? this.defaultTokenUsage;
|
||||
|
||||
try {
|
||||
var params = {};
|
||||
var prompt = encodeURIComponent(interaction.options.getString('prompt').join(" "));
|
||||
var temperature = interaction.options.getNumber('temperature');
|
||||
var maxTokens = interaction.options.getNumber('tokens');
|
||||
if (temperature) params._temperature = temperature;
|
||||
if (maxTokens) params._max_tokens = maxTokens;
|
||||
|
||||
var gptResponse = await libCore.getChat(promptText, params);
|
||||
await interaction.reply(`${interaction.member.user} ${gptResponse}`);
|
||||
|
||||
if (temperature) params._temperature = temperature;
|
||||
if (maxTokens) params._max_tokens = maxTokens;
|
||||
|
||||
var gptResponse = await prompt.libCore.getChat(prompt, params);
|
||||
await interaction.reply(`${interaction.author.username} ${gptResponse}`);
|
||||
|
||||
// Needs reply code to reply to the generation
|
||||
}catch(err){
|
||||
log.ERROR(err)
|
||||
//await interaction.reply(err.toString());
|
||||
}
|
||||
// Needs reply code to reply to the generation
|
||||
}catch(err){
|
||||
log.ERROR(err)
|
||||
//await interaction.reply(err.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
const { Events } = require('discord.js');
|
||||
const discordAuth = require('../middleware/discordAuthorization');
|
||||
const { authorizeCommand } = require('../middleware/discordAuthorization');
|
||||
const { authorizeTokenUsage } = require('../middleware/balanceAuthorization');
|
||||
|
||||
const { DebugBuilder } = require("../utilities/debugBuilder");
|
||||
const log = new DebugBuilder("server", "interactionCreate");
|
||||
@@ -18,17 +19,19 @@ module.exports = {
|
||||
|
||||
log.DEBUG(`${interaction.member.user} is running '${interaction.commandName}'`);
|
||||
|
||||
await discordAuth.authorizeCommand(interaction, command, () => {
|
||||
try {
|
||||
command.execute(interaction);
|
||||
} catch (error) {
|
||||
log.ERROR(error);
|
||||
if (interaction.replied || interaction.deferred) {
|
||||
interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true });
|
||||
} else {
|
||||
interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
|
||||
await authorizeCommand(interaction, command, async () => {
|
||||
await authorizeTokenUsage(interaction, command, async () => {
|
||||
try {
|
||||
command.execute(interaction);
|
||||
} catch (error) {
|
||||
log.ERROR(error);
|
||||
if (interaction.replied || interaction.deferred) {
|
||||
interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true });
|
||||
} else {
|
||||
interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -5,9 +5,9 @@ let parser = new Parser();
|
||||
const { FeedStorage, PostStorage } = require("./libStorage");
|
||||
const libUtils = require("./libUtils");
|
||||
const { createHash } = require("crypto");
|
||||
const { all } = require('axios');
|
||||
|
||||
const { DebugBuilder } = require("./utilities/debugBuilder");
|
||||
const { all } = require('axios');
|
||||
const log = new DebugBuilder("server", "libCore");
|
||||
|
||||
/* OpenAI config
|
||||
@@ -267,7 +267,10 @@ exports.getSlang = async function (question) {
|
||||
* @param {*} param1 Default parameters can be modified
|
||||
* @returns
|
||||
*/
|
||||
exports.getChat = async function (_prompt, { _model = "text-davinci-003", _temperature = 0, _max_tokens = 100 }) {
|
||||
exports.getChat = async (_prompt, { _model = "text-davinci-003", _temperature = 0, _max_tokens = 100 }) => {
|
||||
log.DEBUG("Getting chat with these properties: ", _prompt, _model, _temperature, _max_tokens)
|
||||
return
|
||||
/*
|
||||
const response = await openai.createCompletion({
|
||||
model: _model,
|
||||
prompt: _prompt,
|
||||
@@ -275,9 +278,9 @@ exports.getChat = async function (_prompt, { _model = "text-davinci-003", _tempe
|
||||
max_tokens: _max_tokens
|
||||
});
|
||||
|
||||
|
||||
var responseData = response.data.choices[0].text;
|
||||
return responseData;
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,9 @@ const mysql = require("mysql");
|
||||
|
||||
const rssFeedsTable = process.env.DB_RSS_FEEDS_TABLE;
|
||||
const rssPostsTable = process.env.DB_RSS_POSTS_TABLE;
|
||||
const accountsTable = process.env.DB_ACCOUNTS_TABLE;
|
||||
const transactionsTable = process.env.DB_TRANSACTIONS_TABLE;
|
||||
const pricingTable = process.env.DB_PRICING_TABLE;
|
||||
|
||||
// Helper Functions
|
||||
// Function to run and handle SQL errors
|
||||
@@ -30,6 +33,15 @@ function runSQL(sqlQuery, connection, callback = (err, rows) => {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a formatted date time string from now for MySQL
|
||||
*
|
||||
* @returns Date string for now formatted for MySQL
|
||||
*/
|
||||
function returnMysqlTime(){
|
||||
return new Date().toISOString().slice(0, 19).replace('T', ' ');
|
||||
}
|
||||
|
||||
class Storage {
|
||||
constructor(_dbTable) {
|
||||
this.connection = mysql.createPool({
|
||||
@@ -142,6 +154,63 @@ class Storage {
|
||||
}
|
||||
}
|
||||
|
||||
exports.UserStorage = class UserStorage extends Storage {
|
||||
constructor() {
|
||||
super(accountsTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a new account to the database
|
||||
* @param {*} _discordAccountId The Discord ID the the user
|
||||
* @param {*} callback The callback to be sent
|
||||
* @callback Error|Array|*
|
||||
*/
|
||||
saveAccount(_discordAccountId, callback){
|
||||
const sqlQuery = `INSERT INTO ${this.dbTable} (discord_account_id, balance) VALUES ('${_discordAccountId}', ${0});`;
|
||||
|
||||
log.DEBUG(`Adding new entry with SQL query: '${sqlQuery}'`)
|
||||
|
||||
runSQL(sqlQuery, this.connection, (err, rows) => {
|
||||
if (err) return callback(err, undefined);
|
||||
if (rows?.affectedRows > 0) return callback(undefined, rows);
|
||||
return callback(undefined, undefined);
|
||||
})
|
||||
}
|
||||
|
||||
checkBalance(_tokensToBeUsed, _account_id, callback) {
|
||||
this.getRecordBy('account_id', _account_id, (err, record) => {
|
||||
if (err) return callback(err, undefined);
|
||||
|
||||
if (record?.balance && record.balance > _tokensToBeUsed) return callback(undefined, true);
|
||||
else{
|
||||
return callback(undefined, false);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
updateBalance(){
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
exports.TransactionStorage = class TransactionStorage extends Storage {
|
||||
constructor() {
|
||||
super(transactionsTable);
|
||||
}
|
||||
|
||||
createTransaction(transaction, callback){
|
||||
const sqlQuery = `INSERT INTO ${this.dbTable} () VALUES ('${}');`;
|
||||
|
||||
log.DEBUG(`Adding new entry with SQL query: '${sqlQuery}'`)
|
||||
|
||||
runSQL(sqlQuery, this.connection, (err, rows) => {
|
||||
if (err) return callback(err, undefined);
|
||||
if (rows[0]?.id) return callback(undefined, rows);
|
||||
return callback(undefined, undefined);
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
exports.FeedStorage = class FeedStorage extends Storage {
|
||||
constructor() {
|
||||
super(rssFeedsTable);
|
||||
@@ -329,7 +398,7 @@ exports.PostStorage = class PostStorage extends Storage {
|
||||
}
|
||||
|
||||
savePost(_postObject, callback){
|
||||
const tempCreationDate = new Date().toISOString().slice(0, 19).replace('T', ' ');
|
||||
const tempCreationDate = returnMysqlTime();
|
||||
log.DEBUG("Saving Post Object:", _postObject);
|
||||
if (!_postObject?.guid || !_postObject?.link) {
|
||||
return callback(new Error("Post object malformed, check the object before saving it"), undefined)
|
||||
|
||||
97
middleware/balanceAuthorization.js
Normal file
97
middleware/balanceAuthorization.js
Normal file
@@ -0,0 +1,97 @@
|
||||
// To ensure the command caller has, 1. an account and 2. has enough balance for the request
|
||||
// The pricing table needs to be in the DB so it can be updated via API
|
||||
|
||||
const { DebugBuilder } = require("../utilities/debugBuilder");
|
||||
const log = new DebugBuilder("server", "balanceAuthorizations");
|
||||
|
||||
const { UserStorage } = require("../libStorage");
|
||||
const userStorage = new UserStorage();
|
||||
|
||||
/**
|
||||
* Check to see if the discord ID has an account associated with it
|
||||
* @param {*} _discordAccountId The discord account to look for
|
||||
* @param {*} callback The callback function to be called
|
||||
* @callback false|*
|
||||
*/
|
||||
function checkForAccount(_discordAccountId, callback){
|
||||
userStorage.getRecordBy("discord_account_id", _discordAccountId, (err, results) => {
|
||||
if (err) return callback(err, undefined);
|
||||
|
||||
if (!results) return callback(undefined, false);
|
||||
return callback(undefined, results);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an account from a discord ID
|
||||
* @param {*} _discordAccountId
|
||||
* @param {*} callback
|
||||
*/
|
||||
function createAccount(_discordAccountId, callback){
|
||||
if (!_discordAccountId) return callback(new Error("No discord account specified before creation"));
|
||||
userStorage.saveAccount(_discordAccountId, (err, results) => {
|
||||
if (err) return callback(err, undefined);
|
||||
|
||||
if (!results) return callback(new Error("No results from creating account"), undefined);
|
||||
|
||||
return callback(undefined, results);
|
||||
})
|
||||
}
|
||||
|
||||
function verifyBalance(_tokensToBeUsed, _accountId, callback){
|
||||
userStorage.checkBalance(_tokensToBeUsed, _accountId, (err, results) => {
|
||||
if (err) return callback(err, undefined);
|
||||
|
||||
if(!results) return callback(undefined, false);
|
||||
|
||||
return callback(undefined, true);
|
||||
})
|
||||
}
|
||||
|
||||
function insufficientTokensResponse(interaction){
|
||||
log.DEBUG("INSUFFICIENT TOKENS RESPONSE")
|
||||
|
||||
return interaction.reply("Sorry, not enough tokens for this request.");
|
||||
}
|
||||
|
||||
function welcomeResponse(interaction){
|
||||
log.DEBUG("WELCOME RESPONSE")
|
||||
|
||||
return interaction.reply("Hey there, you have an account now.");
|
||||
}
|
||||
|
||||
exports.authorizeTokenUsage = async (interaction, command, next) => {
|
||||
log.DEBUG("Command requires tokens? ", command.isPrivileged)
|
||||
if(!command.requiresTokens) return next(true);
|
||||
|
||||
if(!interaction.member && (!interaction.options.getNumber("tokens") || !command.defaultTokenUsage)) throw new Error("No member or tokens specified before attempting to authorize");
|
||||
const memberId = interaction.member.id;
|
||||
const tokensToBeUsed = interaction.options.getNumber("tokens") ?? command.defaultTokenUsage
|
||||
log.DEBUG(`Authorizing ${memberId} for a purchase worth ${tokensToBeUsed} tokens`)
|
||||
log.DEBUG("Checking for account associated with discord ID: ", memberId);
|
||||
await checkForAccount(memberId, async (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
log.DEBUG("Results from checking for account: ", results);
|
||||
|
||||
// First time user is attempting transaction
|
||||
if(!results){
|
||||
log.DEBUG("No account for discord ID: ", memberId);
|
||||
await createAccount(memberId, (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results) return welcomeResponse(interaction);
|
||||
})
|
||||
} else{
|
||||
// User has an account
|
||||
log.DEBUG(`Account ID: ${results.account_id} found for discord ID: ${memberId}`);
|
||||
await verifyBalance(tokensToBeUsed, results.account_id, async (err, isVerified) => {
|
||||
if (err) throw err;
|
||||
|
||||
if(!isVerified) return insufficientTokensResponse(interaction);
|
||||
|
||||
return next(isVerified);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user