From cb195616b394c12cc803b3f8959341f74a080bc0 Mon Sep 17 00:00:00 2001 From: Tben Date: Sat, 12 Aug 2023 16:46:00 +0100 Subject: [PATCH] Upgrades --- engine/engine/addUsersTableToDb.js | 77 ++++++ engine/engine/data/presets/users.json | 132 +++++++++++ engine/engine/deploy.js | 5 - engine/engine/encodingUpdate.js | 53 ----- engine/engine/grantFullPriviledges.js | 64 ----- engine/engine/lessWatch.js | 61 ----- engine/engine/readImage.js | 21 -- engine/engine/tailwindWatch.js | 27 --- engine/engine/test.js | 221 ------------------ engine/engine/updateDateTimestamps.js | 53 ----- engine/engine/updateDbSlugsForTableRecords.js | 51 ---- engine/query/get.js | 2 +- engine/query/post.js | 100 ++++++++ .../query/update-api-schema-from-local-db.js | 143 ++++++++++++ engine/user/add-user.js | 142 +++++++++++ functions/hashPassword.js | 13 ++ package.json | 2 +- types/database-schema.td.js | 2 +- users/add-user.js | 39 +++- users/get-user.js | 7 + users/login-user.js | 7 + users/reauth-user.js | 7 + users/social/github-auth.js | 11 + users/social/google-auth.js | 11 + users/update-user.js | 7 + utils/get.js | 2 +- utils/post.js | 31 +++ 27 files changed, 727 insertions(+), 564 deletions(-) create mode 100644 engine/engine/addUsersTableToDb.js create mode 100644 engine/engine/data/presets/users.json delete mode 100644 engine/engine/deploy.js delete mode 100644 engine/engine/encodingUpdate.js delete mode 100644 engine/engine/grantFullPriviledges.js delete mode 100644 engine/engine/lessWatch.js delete mode 100644 engine/engine/readImage.js delete mode 100644 engine/engine/tailwindWatch.js delete mode 100644 engine/engine/test.js delete mode 100644 engine/engine/updateDateTimestamps.js delete mode 100644 engine/engine/updateDbSlugsForTableRecords.js create mode 100644 engine/query/update-api-schema-from-local-db.js create mode 100644 engine/user/add-user.js create mode 100644 functions/hashPassword.js diff --git a/engine/engine/addUsersTableToDb.js b/engine/engine/addUsersTableToDb.js new file mode 100644 index 0000000..6ba4b03 --- /dev/null +++ b/engine/engine/addUsersTableToDb.js @@ -0,0 +1,77 @@ +// @ts-check + +/** + * ============================================================================== + * Imports + * ============================================================================== + */ +const fs = require("fs"); +const path = require("path"); +const { execSync } = require("child_process"); +const updateApiSchemaFromLocalDb = require("../query/update-api-schema-from-local-db"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * Add `users` table to user database + * ============================================================================== + * + * @param {object} params - Single object passed + * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} params.dbSchema - Database Schema Object + * + * @returns {Promise<*>} new user auth object payload + */ +module.exports = async function addUsersTableToDb({ dbSchema }) { + /** + * Initialize + * + * @description Initialize + */ + const database = process.env.DSQL_DB_NAME || ""; + /** @type {import("../../types/database-schema.td").DSQL_TableSchemaType} */ + const userPreset = require("./data/presets/users.json"); + + try { + /** + * Fetch user + * + * @description Fetch user from db + */ + const userSchemaMainFilePath = path.resolve(process.cwd(), "dsql.schema.json"); + let targetDatabase = dbSchema; + + let existingTableIndex = targetDatabase.tables.findIndex((table, index) => { + if (table.tableName === "users") { + existingTableIndex = index; + return true; + } + }); + + if (existingTableIndex >= 0) { + targetDatabase.tables[existingTableIndex] = userPreset; + } else { + targetDatabase.tables.push(userPreset); + } + + fs.writeFileSync(`${userSchemaMainFilePath}`, JSON.stringify(dbSchema, null, 4), "utf8"); + + //////////////////////////////////////// + + await updateApiSchemaFromLocalDb(); + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + } catch (error) { + console.log(error.message); + } +}; + +//////////////////////////////////////// +//////////////////////////////////////// +//////////////////////////////////////// diff --git a/engine/engine/data/presets/users.json b/engine/engine/data/presets/users.json new file mode 100644 index 0000000..2533033 --- /dev/null +++ b/engine/engine/data/presets/users.json @@ -0,0 +1,132 @@ +{ + "tableName": "users", + "tableFullName": "Users", + "fields": [ + { + "fieldName": "id", + "dataType": "BIGINT", + "notNullValue": true, + "primaryKey": true, + "autoIncrement": true + }, + { + "fieldName": "first_name", + "dataType": "VARCHAR(100)", + "notNullValue": true + }, + { + "fieldName": "last_name", + "dataType": "VARCHAR(100)", + "notNullValue": true + }, + { + "fieldName": "email", + "dataType": "VARCHAR(200)", + "notNullValue": true + }, + { + "fieldName": "phone", + "dataType": "VARCHAR(50)" + }, + { + "fieldName": "user_type", + "dataType": "VARCHAR(20)", + "defaultValue": "default" + }, + { + "fieldName": "username", + "dataType": "VARCHAR(100)", + "nullValue": true + }, + { + "fieldName": "password", + "dataType": "VARCHAR(250)", + "notNullValue": true + }, + { + "fieldName": "image", + "dataType": "VARCHAR(250)", + "defaultValue": "/images/user_images/user-preset.png" + }, + { + "fieldName": "image_thumbnail", + "dataType": "VARCHAR(250)", + "defaultValue": "/images/user_images/user-preset-thumbnail.png" + }, + { + "fieldName": "address", + "dataType": "VARCHAR(255)" + }, + { + "fieldName": "city", + "dataType": "VARCHAR(50)" + }, + { + "fieldName": "state", + "dataType": "VARCHAR(50)" + }, + { + "fieldName": "country", + "dataType": "VARCHAR(50)" + }, + { + "fieldName": "zip_code", + "dataType": "VARCHAR(50)" + }, + { + "fieldName": "social_login", + "dataType": "TINYINT", + "defaultValue": "0" + }, + { + "fieldName": "social_platform", + "dataType": "VARCHAR(50)", + "nullValue": true + }, + { + "fieldName": "social_id", + "dataType": "VARCHAR(250)", + "nullValue": true + }, + { + "fieldName": "more_user_data", + "dataType": "BIGINT", + "defaultValue": "0" + }, + { + "fieldName": "verification_status", + "dataType": "TINYINT", + "defaultValue": "0" + }, + { + "fieldName": "date_created", + "dataType": "VARCHAR(250)", + "notNullValue": true + }, + { + "fieldName": "date_created_code", + "dataType": "BIGINT", + "notNullValue": true + }, + { + "fieldName": "date_created_timestamp", + "dataType": "TIMESTAMP", + "defaultValueLiteral": "CURRENT_TIMESTAMP" + }, + { + "fieldName": "date_updated", + "dataType": "VARCHAR(250)", + "notNullValue": true + }, + { + "fieldName": "date_updated_code", + "dataType": "BIGINT", + "notNullValue": true + }, + { + "fieldName": "date_updated_timestamp", + "dataType": "TIMESTAMP", + "defaultValueLiteral": "CURRENT_TIMESTAMP" + } + ] +} diff --git a/engine/engine/deploy.js b/engine/engine/deploy.js deleted file mode 100644 index d285976..0000000 --- a/engine/engine/deploy.js +++ /dev/null @@ -1,5 +0,0 @@ -const fs = require("fs"); - -async function deploy() {} - -deploy(); diff --git a/engine/engine/encodingUpdate.js b/engine/engine/encodingUpdate.js deleted file mode 100644 index 3d00a1e..0000000 --- a/engine/engine/encodingUpdate.js +++ /dev/null @@ -1,53 +0,0 @@ -require("dotenv").config({ path: "./../.env" }); - -//////////////////////////////////////// - -const noDatabaseDbHandler = require("../functions/backend/noDatabaseDbHandler"); -const varDatabaseDbHandler = require("../functions/backend/varDatabaseDbHandler"); -const createTable = require("./utils/createTable"); -const updateTable = require("./utils/updateTable"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Grab Schema - * - * @description Grab Schema - */ -varDatabaseDbHandler({ - queryString: `SELECT user_database_tables.*,user_databases.db_full_name FROM user_database_tables JOIN user_databases ON user_database_tables.db_id=user_databases.id`, - database: "datasquirel", -}).then(async (tables) => { - for (let i = 0; i < tables.length; i++) { - const table = tables[i]; - const { id, user_id, db_id, db_full_name, table_name, table_slug, table_description } = table; - - const tableInfo = await varDatabaseDbHandler({ - queryString: `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='${db_full_name}' AND TABLE_NAME='${table_slug}'`, - database: db_full_name, - }); - - const updateDbCharset = await varDatabaseDbHandler({ - queryString: `ALTER DATABASE ${db_full_name} CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin;`, - database: db_full_name, - }); - - const updateEncoding = await varDatabaseDbHandler({ - queryString: `ALTER TABLE \`${table_slug}\` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin`, - database: db_full_name, - }); - - console.log(updateEncoding); - } - - process.exit(); -}); - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// diff --git a/engine/engine/grantFullPriviledges.js b/engine/engine/grantFullPriviledges.js deleted file mode 100644 index d91ab4e..0000000 --- a/engine/engine/grantFullPriviledges.js +++ /dev/null @@ -1,64 +0,0 @@ -require("dotenv").config({ path: "./../.env" }); - -//////////////////////////////////////// - -const noDatabaseDbHandler = require("../functions/backend/noDatabaseDbHandler"); -const serverError = require("../functions/backend/serverError"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -async function createDbFromSchema({ userId }) { - /** - * Grab Schema - * - * @description Grab Schema - */ - try { - const allDatabases = await noDatabaseDbHandler(`SHOW DATABASES`); - - const datasquirelUserDatabases = allDatabases.filter((database) => database.Database.match(/datasquirel_user_/)); - - for (let i = 0; i < datasquirelUserDatabases.length; i++) { - const datasquirelUserDatabase = datasquirelUserDatabases[i]; - const { Database } = datasquirelUserDatabase; - - const grantDbPriviledges = await noDatabaseDbHandler(`GRANT ALL PRIVILEGES ON ${Database}.* TO 'datasquirel_full_access'@'127.0.0.1' WITH GRANT OPTION`); - - console.log(grantDbPriviledges); - } - - const flushPriviledged = await noDatabaseDbHandler(`FLUSH PRIVILEGES`); - } catch (error) { - serverError({ - component: "shell/grantDbPriviledges/main-catch-error", - message: error.message, - user: { id: userId }, - }); - } - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - process.exit(); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// -} - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -const userArg = process.argv[process.argv.indexOf("--user")]; -const externalUser = process.argv[process.argv.indexOf("--user") + 1]; - -createDbFromSchema({ userId: userArg ? externalUser : null }); diff --git a/engine/engine/lessWatch.js b/engine/engine/lessWatch.js deleted file mode 100644 index 41ffee1..0000000 --- a/engine/engine/lessWatch.js +++ /dev/null @@ -1,61 +0,0 @@ -const fs = require("fs"); -const { exec } = require("child_process"); - -require("dotenv").config({ path: "./../.env" }); - -const sourceFile = process.argv.indexOf("--src") >= 0 ? process.argv[process.argv.indexOf("--src") + 1] : null; -const destinationFile = process.argv.indexOf("--dst") >= 0 ? process.argv[process.argv.indexOf("--dst") + 1] : null; - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -console.log("Running Less compiler ..."); - -const sourceFiles = sourceFile.split(","); -const dstFiles = destinationFile.split(","); - -for (let i = 0; i < sourceFiles.length; i++) { - const srcFolder = sourceFiles[i]; - const dstFile = dstFiles[i]; - - fs.watch(srcFolder, { recursive: true }, (evtType, prev) => { - if (prev?.match(/\(/) || prev?.match(/\.js$/i)) { - return; - } - - let finalSrcPath = `${srcFolder}/main.less`; - let finalDstPath = dstFile; - - if (prev?.match(/\[/)) { - const paths = prev.split("/"); - const targetPathFull = paths[paths.length - 1]; - const targetPath = targetPathFull.replace(/\[|\]/g, "").replace(/\.less/, ""); - - const destinationFileParentFolder = dstFile.replace(/\/[^\/]+\.css$/, ""); - - const targetDstFilePath = `${destinationFileParentFolder}/${targetPath}.css`; - - finalSrcPath = `${srcFolder}/${targetPathFull}`; - finalDstPath = targetDstFilePath; - } - - exec(`lessc ${finalSrcPath} ${finalDstPath?.match(/\.css$/) ? finalDstPath : finalDstPath.replace(/\/$/, "") + "/_main.css"}`, (error, stdout, stderr) => { - /** @type {Error} */ - if (error) { - console.log("ERROR =>", error.message); - - if (!evtType?.match(/change/i) && prev.match(/\[/)) { - fs.unlinkSync(finalDstPath); - } - - return; - } - - console.log("Less Compilation \x1b[32msuccessful\x1b[0m!"); - }); - }); -} diff --git a/engine/engine/readImage.js b/engine/engine/readImage.js deleted file mode 100644 index 6e05b1e..0000000 --- a/engine/engine/readImage.js +++ /dev/null @@ -1,21 +0,0 @@ -const fs = require("fs"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Grab Schema - * - * @description Grab Schema - */ -const imageBase64 = fs.readFileSync("./../public/images/unique-tokens-icon.png", "base64"); - -console.log(imageBase64.toString()); - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// diff --git a/engine/engine/tailwindWatch.js b/engine/engine/tailwindWatch.js deleted file mode 100644 index 5d65a7e..0000000 --- a/engine/engine/tailwindWatch.js +++ /dev/null @@ -1,27 +0,0 @@ -const fs = require("fs"); -const { exec } = require("child_process"); - -require("dotenv").config({ path: "./../.env" }); - -const sourceFile = process.argv.indexOf("--src") >= 0 ? process.argv[process.argv.indexOf("--src") + 1] : null; -const destinationFile = process.argv.indexOf("--dst") >= 0 ? process.argv[process.argv.indexOf("--dst") + 1] : null; - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -console.log("Running Tailwind CSS compiler ..."); - -fs.watch("./../", (curr, prev) => { - exec(`npx tailwindcss -i ./tailwind/main.css -o ./styles/tailwind.css`, (error, stdout, stderr) => { - if (error) { - console.log("ERROR =>", error.message); - return; - } - - console.log("Tailwind CSS Compilation \x1b[32msuccessful\x1b[0m!"); - }); -}); diff --git a/engine/engine/test.js b/engine/engine/test.js deleted file mode 100644 index 22f74b3..0000000 --- a/engine/engine/test.js +++ /dev/null @@ -1,221 +0,0 @@ -require("dotenv").config({ path: "./../.env" }); - -const dbEngine = require("datasquirel/engine"); -const http = require("http"); - -const datasquirel = require("datasquirel"); - -`curl http://www.dataden.tech`; - -datasquirel - .get({ - db: "test", - key: process.env.DATASQUIREL_READ_ONLY_KEY, - query: "SELECT title, slug, body FROM blog_posts", - }) - .then((response) => { - console.log(response); - }); - -// dbEngine.db -// .query({ -// dbFullName: "datasquirel", -// dbHost: process.env.DB_HOST, -// dbPassword: process.env.DB_PASSWORD, -// dbUsername: process.env.DB_USERNAME, -// query: "SHOW TABLES", -// }) -// .then((res) => { -// console.log("res =>", res); -// }); - -// run({ -// key: "bc057a2cd57922e085739c89b4985e5e676b655d7cc0ba7604659cad0a08c252040120c06597a5d22959a502a44bd816", -// db: "showmerebates", -// query: "SELECT * FROM test_table", -// }).then((res) => { -// console.log("res =>", res); -// }); - -post({ - key: "3115fce7ea7772eda75f8f0e55a1414c5c018b4920f4bc99a2d4d7000bac203c15a7036fd3d7ef55ae67a002d4c757895b5c58ff82079a04ba6d42d23d4353256985090959a58a9af8e03cb277fc7895413e6f28ae11b1cc15329c7f94cdcf9a795f54d6e1d319adc287dc147143e62d", - database: "showmerebates", - query: { - action: "delete", - table: "test_table", - identifierColumnName: "id", - identifierValue: 6, - }, -}).then((res) => { - console.log("res =>", res); -}); - -async function run({ key, db, query }) { - const httpResponse = await new Promise((resolve, reject) => { - http.request( - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: key, - }, - hostname: "localhost", - port: 7070, - path: `/api/query/get?db=${db}&query=${query - .replace(/\n|\r|\n\r/g, "") - .replace(/ {2,}/g, " ") - .replace(/ /g, "+")}`, - }, - - /** - * Callback Function - * - * @description https request callback - */ - (response) => { - var str = ""; - - response.on("data", function (chunk) { - str += chunk; - }); - - response.on("end", function () { - resolve(JSON.parse(str)); - }); - - response.on("error", (err) => { - reject(err); - }); - } - ).end(); - }); - - return httpResponse; -} - -/** - * @typedef {Object} PostReturn - * @property {boolean} success - Did the function run successfully? - * @property {(Object[]|string)} [payload=[]] - The Y Coordinate - */ - -/** - * @typedef {object} PostDataPayload - * @property {string} action - "insert" | "update" | "delete" - * @property {string} table - Table name(slug) eg "blog_posts" - * @property {string} identifierColumnName - Table identifier field name => eg. "id" OR "email" - * @property {string} identifierValue - Corresponding value of the selected field name => This - * checks identifies a the target row for "update" or "delete". Not needed for "insert" - * @property {object} data - Table insert payload object => This must have keys that match - * table fields - * @property {string?} duplicateColumnName - Duplicate column name to check for - * @property {string?} duplicateColumnValue - Duplicate column value to match. If no "update" param - * provided, function will return null - * @property {boolean?} update - Should the "insert" action update the existing entry if indeed - * the entry with "duplicateColumnValue" exists? - */ - -/** - * Post request - * ============================================================================== - * @async - * - * @param {Object} params - Single object passed - * @param {string} params.key - FULL ACCESS API Key - * @param {string} params.database - Database Name - * @param {PostDataPayload} params.query - SQL query String or Request Object - * - * @returns { Promise } - Return Object - */ -async function post({ key, query, database }) { - /** - * Make https request - * - * @description make a request to datasquirel.com - */ - const httpResponse = await new Promise((resolve, reject) => { - const reqPayloadString = JSON.stringify({ - query, - database, - }).replace(/\n|\r|\n\r/gm, ""); - - try { - JSON.parse(reqPayloadString); - } catch (error) { - console.log(error); - console.log(reqPayloadString); - - return { - success: false, - payload: null, - error: "Query object is invalid. Please Check query data values", - }; - } - - const reqPayload = reqPayloadString; - - const httpsRequest = http.request( - { - method: "POST", - headers: { - "Content-Type": "application/json", - "Content-Length": Buffer.from(reqPayload).length, - Authorization: key, - }, - hostname: "localhost", - port: 7070, - path: `/api/query/post`, - }, - - /** - * Callback Function - * - * @description https request callback - */ - (response) => { - var str = ""; - - response.on("data", function (chunk) { - str += chunk; - }); - - response.on("end", function () { - try { - resolve(JSON.parse(str)); - } catch (error) { - console.log(error.message); - console.log("Fetched Payload =>", str); - - resolve({ - success: false, - payload: null, - error: error.message, - }); - } - }); - - response.on("error", (err) => { - resolve({ - success: false, - payload: null, - error: err.message, - }); - }); - } - ); - - httpsRequest.write(reqPayload); - - httpsRequest.on("error", (error) => { - console.log("HTTPS request ERROR =>", error); - }); - - httpsRequest.end(); - }); - - //////////////////////////////////////// - //////////////////////////////////////// - //////////////////////////////////////// - - return httpResponse; -} diff --git a/engine/engine/updateDateTimestamps.js b/engine/engine/updateDateTimestamps.js deleted file mode 100644 index 0752f5c..0000000 --- a/engine/engine/updateDateTimestamps.js +++ /dev/null @@ -1,53 +0,0 @@ -require("dotenv").config({ path: "./../.env" }); - -//////////////////////////////////////// - -const noDatabaseDbHandler = require("../functions/backend/noDatabaseDbHandler"); -const varDatabaseDbHandler = require("../functions/backend/varDatabaseDbHandler"); -const createTable = require("./utils/createTable"); -const updateTable = require("./utils/updateTable"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Grab Schema - * - * @description Grab Schema - */ -varDatabaseDbHandler({ - queryString: `SELECT user_database_tables.*,user_databases.db_full_name FROM user_database_tables JOIN user_databases ON user_database_tables.db_id=user_databases.id`, - database: "datasquirel", -}).then(async (tables) => { - for (let i = 0; i < tables.length; i++) { - const table = tables[i]; - const { id, user_id, db_id, db_full_name, table_name, table_slug, table_description } = table; - - const tableInfo = await varDatabaseDbHandler({ - queryString: `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='${db_full_name}' AND TABLE_NAME='${table_slug}'`, - database: db_full_name, - }); - - const updateCreationDateTimestamp = await varDatabaseDbHandler({ - queryString: `ALTER TABLE \`${table_slug}\` MODIFY COLUMN date_created_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP`, - database: db_full_name, - }); - - const updateDateTimestamp = await varDatabaseDbHandler({ - queryString: `ALTER TABLE \`${table_slug}\` MODIFY COLUMN date_updated_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`, - database: db_full_name, - }); - - console.log("Date Updated Column updated"); - } - - process.exit(); -}); - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// diff --git a/engine/engine/updateDbSlugsForTableRecords.js b/engine/engine/updateDbSlugsForTableRecords.js deleted file mode 100644 index 96bd436..0000000 --- a/engine/engine/updateDbSlugsForTableRecords.js +++ /dev/null @@ -1,51 +0,0 @@ -require("dotenv").config({ path: "./../.env" }); - -//////////////////////////////////////// - -const noDatabaseDbHandler = require("../functions/backend/noDatabaseDbHandler"); -const serverError = require("../functions/backend/serverError"); -const varDatabaseDbHandler = require("../functions/backend/varDatabaseDbHandler"); -const createTable = require("./utils/createTable"); -const updateTable = require("./utils/updateTable"); - -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ -/** ****************************************************************************** */ - -/** - * Grab Schema - * - * @description Grab Schema - */ -varDatabaseDbHandler({ - queryString: `SELECT DISTINCT db_id FROM user_database_tables`, - database: "datasquirel", -}).then(async (tables) => { - // console.log(tables); - // process.exit(); - - for (let i = 0; i < tables.length; i++) { - const table = tables[i]; - - try { - const { db_id } = table; - const dbSlug = await global.DB_HANDLER(`SELECT db_slug FROM user_databases WHERE id='${db_id}'`); - const updateTableSlug = await global.DB_HANDLER(`UPDATE user_database_tables SET db_slug='${dbSlug[0].db_slug}' WHERE db_id='${db_id}'`); - } catch (error) { - serverError({ - component: "shell/updateDbSlugsForTableRecords/main-catch-error", - message: error.message, - user: {}, - }); - } - } - - process.exit(); -}); - -//////////////////////////////////////// -//////////////////////////////////////// -//////////////////////////////////////// diff --git a/engine/query/get.js b/engine/query/get.js index 409fcd1..9152abb 100644 --- a/engine/query/get.js +++ b/engine/query/get.js @@ -5,7 +5,7 @@ const runQuery = require("./utils/runQuery"); /** * @typedef {Object} LocalGetReturn * @property {boolean} success - Did the function run successfully? - * @property {(Object[]|string|null|object)} [payload] - GET request results + * @property {*} [payload] - GET request results * @property {string} [msg] - Message * @property {string} [error] - Error Message */ diff --git a/engine/query/post.js b/engine/query/post.js index e69de29..0bdb361 100644 --- a/engine/query/post.js +++ b/engine/query/post.js @@ -0,0 +1,100 @@ +// @ts-check + +const runQuery = require("./utils/runQuery"); + +/** + * @typedef {Object} LocalPostReturn + * @property {boolean} success - Did the function run successfully? + * @property {*} [payload] - GET request results + * @property {string} [msg] - Message + * @property {string} [error] - Error Message + */ + +/** + * @typedef {Object} LocalPostQueryObject + * @property {string | import("../../utils/post").PostDataPayload} query - Table Name + * @property {string} [tableName] - Table Name + * @property {string[]} [queryValues] - GET request results + */ + +/** + * Make a get request to Datasquirel API + * ============================================================================== + * @async + * + * @param {Object} params - Single object passed + * @param {LocalPostQueryObject} params.options - SQL Query + * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} [params.dbSchema] - Name of the table to query + * + * @returns { Promise } - Return Object + */ +async function localPost({ options, dbSchema }) { + try { + /** + * Grab Body + */ + const { query, tableName, queryValues } = options; + const dbFullName = process.env.DSQL_DB_NAME || ""; + + /** + * Input Validation + * + * @description Input Validation + */ + if (typeof query === "string" && query?.match(/^create |^alter |^drop /i)) { + return { success: false, msg: "Wrong Input" }; + } + + if (typeof query === "object" && query?.action?.match(/^create |^alter |^drop /i)) { + return { success: false, msg: "Wrong Input" }; + } + + /** + * Create new user folder and file + * + * @description Create new user folder and file + */ + try { + let { result, error } = await runQuery({ + dbFullName: dbFullName, + query: query, + dbSchema: dbSchema, + queryValuesArray: queryValues, + tableName, + }); + + if (error) throw error; + + return { + success: true, + payload: result, + error: error, + }; + + //////////////////////////////////////// + } catch (error) { + //////////////////////////////////////// + + return { + success: false, + payload: null, + error: error.message, + }; + } + + //////////////////////////////////////// + } catch (error) { + //////////////////////////////////////// + console.log("Error in local post Request =>", error.message); + + return { + success: false, + payload: null, + msg: "Something went wrong!", + }; + + //////////////////////////////////////// + } +} + +module.exports = localPost; diff --git a/engine/query/update-api-schema-from-local-db.js b/engine/query/update-api-schema-from-local-db.js new file mode 100644 index 0000000..9fff28c --- /dev/null +++ b/engine/query/update-api-schema-from-local-db.js @@ -0,0 +1,143 @@ +// @ts-check + +/** + * Imports + */ +const https = require("https"); +const path = require("path"); +const fs = require("fs"); + +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ +/** ****************************************************************************** */ + +/** + * @typedef {Object} PostReturn + * @property {boolean} success - Did the function run successfully? + * @property {*} [payload] - The Y Coordinate + * @property {string} [error] - The Y Coordinate + */ + +/** + * # Update API Schema From Local DB + * + * @async + * + * @returns { Promise } - Return Object + */ +async function updateApiSchemaFromLocalDb() { + try { + /** + * Initialize + */ + const dbSchemaPath = path.resolve(process.cwd(), "dsql.schema.json"); + const key = process.env.DSQL_KEY || ""; + + const dbSchema = JSON.parse(fs.readFileSync(dbSchemaPath, "utf8")); + + /** + * Make https request + * + * @description make a request to datasquirel.com + */ + const httpResponse = await new Promise((resolve, reject) => { + const reqPayloadString = JSON.stringify({ + schema: dbSchema, + }).replace(/\n|\r|\n\r/gm, ""); + + try { + JSON.parse(reqPayloadString); + } catch (error) { + console.log(error); + console.log(reqPayloadString); + + return { + success: false, + payload: null, + error: "Query object is invalid. Please Check query data values", + }; + } + + const reqPayload = reqPayloadString; + + const httpsRequest = https.request( + { + method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": Buffer.from(reqPayload).length, + Authorization: key, + }, + port: 443, + hostname: "datasquirel.com", + path: `/api/query/update-schema-from-single-database`, + }, + + /** + * Callback Function + * + * @description https request callback + */ + (response) => { + var str = ""; + + response.on("data", function (chunk) { + str += chunk; + }); + + response.on("end", function () { + try { + resolve(JSON.parse(str)); + } catch (error) { + console.log(error); + console.log("Fetched Payload =>", str); + + resolve({ + success: false, + payload: null, + error: error, + }); + } + }); + + response.on("error", (err) => { + resolve({ + success: false, + payload: null, + error: err.message, + }); + }); + } + ); + + httpsRequest.write(reqPayload); + + httpsRequest.on("error", (error) => { + console.log("HTTPS request ERROR =>", error); + }); + + httpsRequest.end(); + }); + + /** ********************************************** */ + /** ********************************************** */ + /** ********************************************** */ + + return httpResponse; + } catch (error) { + return { + success: false, + payload: null, + error: error.message, + }; + } +} + +/** ********************************************** */ +/** ********************************************** */ +/** ********************************************** */ + +module.exports = updateApiSchemaFromLocalDb; diff --git a/engine/user/add-user.js b/engine/user/add-user.js new file mode 100644 index 0000000..2fa7098 --- /dev/null +++ b/engine/user/add-user.js @@ -0,0 +1,142 @@ +// @ts-check + +const hashPassword = require("../../functions/hashPassword"); +const addUsersTableToDb = require("../engine/addUsersTableToDb"); +const varDatabaseDbHandler = require("../engine/utils/varDatabaseDbHandler"); +const addDbEntry = require("../query/utils/addDbEntry"); +const runQuery = require("../query/utils/runQuery"); + +/** + * @typedef {Object} LocalPostReturn + * @property {boolean} success - Did the function run successfully? + * @property {*} [payload] - GET request results + * @property {string} [msg] - Message + * @property {string} [error] - Error Message + */ + +/** + * Make a get request to Datasquirel API + * ============================================================================== + * @async + * + * @param {Object} params - Single object passed + * @param {import("../../users/add-user").UserDataPayload} params.payload - SQL Query + * @param {import("../../types/database-schema.td").DSQL_DatabaseSchemaType} params.dbSchema - Name of the table to query + * + * @returns { Promise } - Return Object + */ +async function localAddUser({ payload, dbSchema }) { + try { + /** + * Initialize Variables + */ + const dbFullName = process.env.DSQL_DB_NAME || ""; + /** + * Hash Password + * + * @description Hash Password + */ + if (!payload?.password) { + return { success: false, payload: `Password is required to create an account` }; + } + + const hashedPassword = hashPassword(payload.password); + payload.password = hashedPassword; + + let fields = await varDatabaseDbHandler({ + queryString: `SHOW COLUMNS FROM users`, + database: dbFullName, + }); + + if (!fields) { + const newTable = await addUsersTableToDb({ dbSchema }); + + console.log(newTable); + + fields = await varDatabaseDbHandler({ + queryString: `SHOW COLUMNS FROM users`, + database: dbFullName, + }); + } + + if (!fields) { + return { + success: false, + payload: "Could not create users table", + }; + } + + const fieldsTitles = fields.map((fieldObject) => fieldObject.Field); + + let invalidField = null; + + for (let i = 0; i < Object.keys(payload).length; i++) { + const key = Object.keys(payload)[i]; + if (!fieldsTitles.includes(key)) { + invalidField = key; + break; + } + } + + if (invalidField) { + return { success: false, payload: `${invalidField} is not a valid field!` }; + } + + const existingUser = await varDatabaseDbHandler({ + queryString: `SELECT * FROM users WHERE email = ?${payload.username ? "OR username = ?" : ""}}`, + queryValuesArray: payload.username ? [payload.email, payload.username] : [payload.email], + database: dbFullName, + }); + + if (existingUser && existingUser[0]) { + return { + success: false, + payload: "User Already Exists", + }; + } + + const addUser = await addDbEntry({ + dbContext: "Dsql User", + paradigm: "Full Access", + dbFullName: dbFullName, + tableName: "users", + data: { + ...payload, + image: "/images/user_images/user-preset.png", + image_thumbnail: "/images/user_images/user-preset-thumbnail.png", + }, + }); + + if (addUser?.insertId) { + const newlyAddedUser = await varDatabaseDbHandler({ + queryString: `SELECT id,first_name,last_name,email,username,phone,image,image_thumbnail,city,state,country,zip_code,address,verification_status,more_user_data FROM users WHERE id='${addUser.insertId}'`, + database: dbFullName, + }); + + return { + success: true, + payload: newlyAddedUser?.[0], + }; + } else { + return { + success: false, + payload: "Could not create user", + }; + } + + //////////////////////////////////////// + } catch (error) { + //////////////////////////////////////// + console.log("Error in local add-user Request =>", error.message); + + return { + success: false, + payload: null, + msg: "Something went wrong!", + }; + + //////////////////////////////////////// + } +} + +module.exports = localAddUser; diff --git a/functions/hashPassword.js b/functions/hashPassword.js new file mode 100644 index 0000000..c788a9d --- /dev/null +++ b/functions/hashPassword.js @@ -0,0 +1,13 @@ +const { createHmac } = require("crypto"); + +/** + * # Hash password Function + * @param {string} password + * @returns {string} + */ +module.exports = function hashPassword(password) { + const hmac = createHmac("sha512", process.env.ENCRYPTION_PASSWORD); + hmac.update(password); + let hashed = hmac.digest("base64"); + return hashed; +}; diff --git a/package.json b/package.json index c6b2662..b0139cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "datasquirel", - "version": "1.5.4", + "version": "1.5.5", "description": "Cloud-based SQL data management tool", "main": "index.js", "bin": { diff --git a/types/database-schema.td.js b/types/database-schema.td.js index 7361fe2..b4ceb9f 100644 --- a/types/database-schema.td.js +++ b/types/database-schema.td.js @@ -30,7 +30,7 @@ * @property {string} [tableDescription] - Brief description of table * @property {DSQL_FieldSchemaType[]} fields - List of table Fields * @property {DSQL_IndexSchemaType[]} [indexes] - List of table indexes, if available - * @property {DSQL_ChildrenTablesType[]} childrenTables - List of children tables + * @property {DSQL_ChildrenTablesType[]} [childrenTables] - List of children tables * @property {boolean} [childTable] -If current table is a child clone * @property {string} [childTableName] - Table slug of parent table => "blog_posts" * @property {string} [childTableDbFullName] - Database full name(slug) including datasquirel data => "datasquirel_user_7_new_database" diff --git a/users/add-user.js b/users/add-user.js index c92b7a4..984cf75 100644 --- a/users/add-user.js +++ b/users/add-user.js @@ -1,9 +1,14 @@ +// @ts-check + /** * ============================================================================== * Imports * ============================================================================== */ const https = require("https"); +const path = require("path"); +const fs = require("fs"); +const localAddUser = require("../engine/user/add-user"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -20,10 +25,10 @@ const https = require("https"); /** * @typedef {object} UserDataPayload - * @property {!string} first_name - First Name *Required - * @property {!string} last_name - Last Name *Required - * @property {!string} email - Email *Required - * @property {!string} password - Password *Required + * @property {string} first_name - First Name *Required + * @property {string} last_name - Last Name *Required + * @property {string} email - Email *Required + * @property {string} password - Password *Required * @property {string?} username - Username (Optional) */ @@ -40,6 +45,32 @@ const https = require("https"); * @returns { Promise } */ async function addUser({ key, payload, database }) { + /** + * Check for local DB settings + * + * @description Look for local db settings in `.env` file and by pass the http request if available + */ + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC } = process.env; + + if (DSQL_HOST?.match(/./) && DSQL_USER?.match(/./) && DSQL_PASS?.match(/./) && DSQL_DB_NAME?.match(/./)) { + /** @type {import("../types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ + let dbSchema; + + try { + const localDbSchemaPath = path.resolve(process.cwd(), "dsql.schema.json"); + dbSchema = JSON.parse(fs.readFileSync(localDbSchemaPath, "utf8")); + } catch (error) {} + + console.log("Reading from local database ..."); + + if (dbSchema) { + return await localAddUser({ + dbSchema: dbSchema, + payload: payload, + }); + } + } + /** * Make https request * diff --git a/users/get-user.js b/users/get-user.js index d822cef..f217b69 100644 --- a/users/get-user.js +++ b/users/get-user.js @@ -44,6 +44,13 @@ const https = require("https"); * @returns { Promise} */ async function getUser({ key, userId, database, fields }) { + /** + * Check for local DB settings + * + * @description Look for local db settings in `.env` file and by pass the http request if available + */ + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC } = process.env; + /** * Make https request * diff --git a/users/login-user.js b/users/login-user.js index 682f339..1bf46b6 100644 --- a/users/login-user.js +++ b/users/login-user.js @@ -78,6 +78,13 @@ async function loginUser({ key, payload, database, additionalFields, response, e msg: "Encryption Salt must be at least 8 characters", }; + /** + * Check for local DB settings + * + * @description Look for local db settings in `.env` file and by pass the http request if available + */ + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC } = process.env; + /** * Make https request * diff --git a/users/reauth-user.js b/users/reauth-user.js index a6541ba..562818b 100644 --- a/users/reauth-user.js +++ b/users/reauth-user.js @@ -66,6 +66,13 @@ async function reauthUser({ key, database, response, request, level, encryptionK }; } + /** + * Check for local DB settings + * + * @description Look for local db settings in `.env` file and by pass the http request if available + */ + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC } = process.env; + /** * Make https request * diff --git a/users/social/github-auth.js b/users/social/github-auth.js index 94803ee..2e90922 100644 --- a/users/social/github-auth.js +++ b/users/social/github-auth.js @@ -110,6 +110,17 @@ async function githubAuth({ key, code, email, database, clientId, clientSecret, //////////////////////////////////////// //////////////////////////////////////// + /** + * Check for local DB settings + * + * @description Look for local db settings in `.env` file and by pass the http request if available + */ + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC } = process.env; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + /** * Make https request * diff --git a/users/social/google-auth.js b/users/social/google-auth.js index 520d48d..d4a74b6 100644 --- a/users/social/google-auth.js +++ b/users/social/google-auth.js @@ -108,6 +108,17 @@ async function googleAuth({ key, token, database, clientId, response, encryption //////////////////////////////////////// //////////////////////////////////////// + /** + * Check for local DB settings + * + * @description Look for local db settings in `.env` file and by pass the http request if available + */ + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC } = process.env; + + //////////////////////////////////////// + //////////////////////////////////////// + //////////////////////////////////////// + /** * Make https request * diff --git a/users/update-user.js b/users/update-user.js index 1727cf9..125268b 100644 --- a/users/update-user.js +++ b/users/update-user.js @@ -32,6 +32,13 @@ const https = require("https"); * @returns { Promise} */ async function updateUser({ key, payload, database }) { + /** + * Check for local DB settings + * + * @description Look for local db settings in `.env` file and by pass the http request if available + */ + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC } = process.env; + /** * Make https request * diff --git a/utils/get.js b/utils/get.js index 623f719..e152cd6 100644 --- a/utils/get.js +++ b/utils/get.js @@ -20,7 +20,7 @@ const localGet = require("../engine/query/get"); /** * @typedef {Object} GetReturn * @property {boolean} success - Did the function run successfully? - * @property {(Object[]|string|null|object)} [payload] - GET request results + * @property {*} [payload] - GET request results * @property {string} [msg] - Message * @property {string} [error] - Error Message */ diff --git a/utils/post.js b/utils/post.js index 2dec33e..0f581fd 100644 --- a/utils/post.js +++ b/utils/post.js @@ -4,6 +4,9 @@ * Imports */ const https = require("https"); +const path = require("path"); +const fs = require("fs"); +const localPost = require("../engine/query/post"); /** ****************************************************************************** */ /** ****************************************************************************** */ @@ -49,6 +52,34 @@ const https = require("https"); * @returns { Promise } - Return Object */ async function post({ key, query, queryValues, database, tableName }) { + /** + * Check for local DB settings + * + * @description Look for local db settings in `.env` file and by pass the http request if available + */ + const { DSQL_HOST, DSQL_USER, DSQL_PASS, DSQL_DB_NAME, DSQL_KEY, DSQL_REF_DB_NAME, DSQL_FULL_SYNC } = process.env; + + if (DSQL_HOST?.match(/./) && DSQL_USER?.match(/./) && DSQL_PASS?.match(/./) && DSQL_DB_NAME?.match(/./)) { + /** @type {import("../types/database-schema.td").DSQL_DatabaseSchemaType | undefined} */ + let dbSchema; + + try { + const localDbSchemaPath = path.resolve(process.cwd(), "dsql.schema.json"); + dbSchema = JSON.parse(fs.readFileSync(localDbSchemaPath, "utf8")); + } catch (error) {} + + console.log("Reading from local database ..."); + + return await localPost({ + dbSchema: dbSchema, + options: { + query: query, + queryValues: queryValues, + tableName: tableName, + }, + }); + } + /** * Make https request *